From f92a94a78afcabb63aa8c6ec8ce825c96a6a0e96 Mon Sep 17 00:00:00 2001 From: Spooks <62370103+Spooks4576@users.noreply.github.com> Date: Tue, 5 Mar 2024 20:17:00 -0700 Subject: [PATCH 01/16] JS: Added Submenu support --- applications/system/js_app/application.fam | 8 + .../js_app/examples/apps/Scripts/submenu.js | 11 ++ .../system/js_app/modules/js_submenu.c | 146 ++++++++++++++++++ 3 files changed, 165 insertions(+) create mode 100644 applications/system/js_app/examples/apps/Scripts/submenu.js create mode 100644 applications/system/js_app/modules/js_submenu.c diff --git a/applications/system/js_app/application.fam b/applications/system/js_app/application.fam index 16963317e..588ad03fa 100644 --- a/applications/system/js_app/application.fam +++ b/applications/system/js_app/application.fam @@ -62,3 +62,11 @@ App( requires=["js_app"], sources=["modules/js_usbdisk/*.c"], ) + +App( + appid="js_submenu", + apptype=FlipperAppType.PLUGIN, + entry_point="js_submenu_ep", + requires=["js_app"], + sources=["modules/js_submenu.c"], +) diff --git a/applications/system/js_app/examples/apps/Scripts/submenu.js b/applications/system/js_app/examples/apps/Scripts/submenu.js new file mode 100644 index 000000000..4c0cd79d0 --- /dev/null +++ b/applications/system/js_app/examples/apps/Scripts/submenu.js @@ -0,0 +1,11 @@ +let submenu = require("submenu"); + +submenu.addItem("Item 1", 0); +submenu.addItem("Item 2", 1); +submenu.addItem("Item 3", 2); + +submenu.setHeader("Select an option:"); + +let result = submenu.show(); + +print("Result: ", result); diff --git a/applications/system/js_app/modules/js_submenu.c b/applications/system/js_app/modules/js_submenu.c new file mode 100644 index 000000000..08c62f404 --- /dev/null +++ b/applications/system/js_app/modules/js_submenu.c @@ -0,0 +1,146 @@ +#include +#include +#include +#include "../js_modules.h" + +typedef struct { + Submenu* submenu; + ViewDispatcher* view_dispatcher; + uint32_t result; +} JsSubmenuInst; + +static JsSubmenuInst* get_this_ctx(struct mjs* mjs) { + mjs_val_t obj_inst = mjs_get(mjs, mjs_get_this(mjs), INST_PROP_NAME, ~0); + JsSubmenuInst* 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_str_arg(struct mjs* mjs, size_t index, const char** value) { + mjs_val_t str_obj = mjs_arg(mjs, index); + if(!mjs_is_string(str_obj)) { + ret_bad_args(mjs, "Argument must be a string"); + return false; + } + size_t str_len = 0; + *value = mjs_get_string(mjs, &str_obj, &str_len); + if((str_len == 0) || (*value == NULL)) { + ret_bad_args(mjs, "Bad string argument"); + return false; + } + return true; +} + +static int32_t get_int_arg(struct mjs* mjs, size_t index, int32_t* value) { + mjs_val_t int_obj = mjs_arg(mjs, index); + if(!mjs_is_number(int_obj)) { + ret_bad_args(mjs, "Argument must be a number"); + return false; + } + *value = mjs_get_int32(mjs, int_obj); + return true; +} + +static void submenu_callback(void* context, uint32_t id) { + UNUSED(id); + JsSubmenuInst* submenu = context; + submenu->result = id; + view_dispatcher_stop(submenu->view_dispatcher); +} + +static void js_submenu_add_item(struct mjs* mjs) { + JsSubmenuInst* submenu = get_this_ctx(mjs); + if(!check_arg_count(mjs, 2)) return; + + const char* label; + if(!get_str_arg(mjs, 0, &label)) return; + + int32_t id; + if(!get_int_arg(mjs, 1, &id)) return; + + submenu_add_item(submenu->submenu, label, id, submenu_callback, submenu); + + mjs_return(mjs, MJS_UNDEFINED); +} + +static void js_submenu_set_header(struct mjs* mjs) { + JsSubmenuInst* submenu = get_this_ctx(mjs); + if(!check_arg_count(mjs, 1)) return; + + const char* header; + if(!get_str_arg(mjs, 0, &header)) return; + + submenu_set_header(submenu->submenu, header); + + mjs_return(mjs, MJS_UNDEFINED); +} + +static void js_submenu_show(struct mjs* mjs) { + JsSubmenuInst* submenu = get_this_ctx(mjs); + if(!check_arg_count(mjs, 0)) return; + submenu->result = 0; + + view_dispatcher_attach_to_gui( + submenu->view_dispatcher, furi_record_open(RECORD_GUI), ViewDispatcherTypeFullscreen); + furi_record_close(RECORD_GUI); + + view_dispatcher_switch_to_view(submenu->view_dispatcher, 0); + + view_dispatcher_run(submenu->view_dispatcher); + + submenu_reset(submenu->submenu); + + mjs_return(mjs, mjs_mk_number(mjs, submenu->result)); +} + +static void* js_submenu_create(struct mjs* mjs, mjs_val_t* object) { + JsSubmenuInst* submenu = malloc(sizeof(JsSubmenuInst)); + mjs_val_t submenu_obj = mjs_mk_object(mjs); + mjs_set(mjs, submenu_obj, INST_PROP_NAME, ~0, mjs_mk_foreign(mjs, submenu)); + mjs_set(mjs, submenu_obj, "addItem", ~0, MJS_MK_FN(js_submenu_add_item)); + mjs_set(mjs, submenu_obj, "setHeader", ~0, MJS_MK_FN(js_submenu_set_header)); + mjs_set(mjs, submenu_obj, "show", ~0, MJS_MK_FN(js_submenu_show)); + submenu->submenu = submenu_alloc(); + submenu->view_dispatcher = view_dispatcher_alloc(); + view_dispatcher_enable_queue(submenu->view_dispatcher); + view_dispatcher_add_view(submenu->view_dispatcher, 0, submenu_get_view(submenu->submenu)); + *object = submenu_obj; + return submenu; +} + +static void js_submenu_destroy(void* inst) { + JsSubmenuInst* submenu = inst; + submenu_free(submenu->submenu); + view_dispatcher_free(submenu->view_dispatcher); + free(submenu); +} + +static const JsModuleDescriptor js_submenu_desc = { + "submenu", + js_submenu_create, + js_submenu_destroy, +}; + +static const FlipperAppPluginDescriptor submenu_plugin_descriptor = { + .appid = PLUGIN_APP_ID, + .ep_api_version = PLUGIN_API_VERSION, + .entry_point = &js_submenu_desc, +}; + +const FlipperAppPluginDescriptor* js_submenu_ep(void) { + return &submenu_plugin_descriptor; +} \ No newline at end of file From ab9c10c4360a7bba5ceef75973aaaf4338709b6f Mon Sep 17 00:00:00 2001 From: Spooks <62370103+Spooks4576@users.noreply.github.com> Date: Tue, 5 Mar 2024 23:59:06 -0700 Subject: [PATCH 02/16] Added Ble Beacon --- applications/system/js_app/application.fam | 8 + .../js_app/examples/apps/Scripts/blebeacon.js | 88 ++++++++ .../system/js_app/modules/js_blebeacon.c | 213 ++++++++++++++++++ 3 files changed, 309 insertions(+) create mode 100644 applications/system/js_app/examples/apps/Scripts/blebeacon.js create mode 100644 applications/system/js_app/modules/js_blebeacon.c diff --git a/applications/system/js_app/application.fam b/applications/system/js_app/application.fam index 588ad03fa..40fe06cff 100644 --- a/applications/system/js_app/application.fam +++ b/applications/system/js_app/application.fam @@ -70,3 +70,11 @@ App( requires=["js_app"], sources=["modules/js_submenu.c"], ) + +App( + appid="js_blebeacon", + apptype=FlipperAppType.PLUGIN, + entry_point="js_blebeacon_ep", + requires=["js_app"], + sources=["modules/js_blebeacon.c"], +) diff --git a/applications/system/js_app/examples/apps/Scripts/blebeacon.js b/applications/system/js_app/examples/apps/Scripts/blebeacon.js new file mode 100644 index 000000000..3f853f2cb --- /dev/null +++ b/applications/system/js_app/examples/apps/Scripts/blebeacon.js @@ -0,0 +1,88 @@ +let bleBeacon = require("blebeacon"); + +let currentIndex = 0; +let currentByteValue = 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 byteToHex(byte) { + let hexChars = '0123456789abcdef'; + let hex = ''; + if (byte >= 0 && byte <= 255) { + hex = hexChars[(byte >> 4) & 0x0F] + hexChars[byte & 0x0F]; + } + return hex; +} + +function getNextByteValue() { + let value = currentByteValue; + currentByteValue = (currentByteValue + 1) % 256; + return value; +} + +function generateRandomMac() { + let mac = ''; + for (let i = 0; i < 6; i++) { + if (mac.length) mac += ':'; + let byte = getNextByteValue(); + mac += byteToHex(byte); + } + return mac; +} + +function bytesToHexString(bytes) { + if (!bytes) { + print("Invalid input for bytesToHexString"); + return ''; + } + + let hexString = ''; + for (let i = 0; i < bytes.length; i++) { + hexString += byteToHex(bytes[i]); + } + return hexString; +} + +function sendRandomModelAdvertisement() { + if (!watchValues || watchValues.length === 0) { + print("watchValues array is empty or undefined."); + return; + } + + let model = watchValues[currentIndex]; + + let packet = [ + 14, 0xFF, 0x75, 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x01, 0xFF, 0x00, 0x00, 0x43, + model + ]; + + let packetString = bytesToHexString(packet); + if (!packetString) { + print("Failed to generate packet string."); + return; + } + + bleBeacon.setMac(generateRandomMac()); + bleBeacon.setData(packetString); + bleBeacon.send(); + + print("Sent data for model ID " + to_string(model)); + + currentIndex = (currentIndex + 1) % watchValues.length; + + delay(500); // 500 Ms is the fatest we can manage to recieve + // in C Flipper is way faster at spamming this + + bleBeacon.stop(); + + bleBeacon +} + +while (true) +{ + sendRandomModelAdvertisement(); +} \ No newline at end of file diff --git a/applications/system/js_app/modules/js_blebeacon.c b/applications/system/js_app/modules/js_blebeacon.c new file mode 100644 index 000000000..5bbcb0112 --- /dev/null +++ b/applications/system/js_app/modules/js_blebeacon.c @@ -0,0 +1,213 @@ +#include "../js_modules.h" +#include +#include + +typedef struct { + char* data; + char* mac_addr; + size_t beacon_data_len; + GapExtraBeaconConfig beacon_config; +} 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_str_arg(struct mjs* mjs, size_t index, char** value) { + mjs_val_t str_obj = mjs_arg(mjs, index); + if(!mjs_is_string(str_obj)) { + ret_bad_args(mjs, "Argument must be a string"); + return false; + } + size_t str_len; + const char* temp = mjs_get_string(mjs, &str_obj, &str_len); + if(str_len == 0 || !temp) { + ret_bad_args(mjs, "Bad string argument"); + return false; + } + + *value = (char*)malloc(str_len + 1); + if (!*value) { + ret_bad_args(mjs, "Memory allocation failed"); + return false; + } + strncpy(*value, temp, str_len); + (*value)[str_len] = '\0'; // Ensure null termination + return true; +} + +static uint8_t hex_char_to_uint(char c) { + if (c >= '0' && c <= '9') return c - '0'; + if (c >= 'a' && c <= 'f') return 10 + c - 'a'; + if (c >= 'A' && c <= 'F') return 10 + c - 'A'; + return 0; +} + +static uint8_t* macstr_to_uint8(const char* macstr) { + if (strlen(macstr) != 17) return NULL; + + uint8_t* mac_bytes = (uint8_t*)malloc(6 * sizeof(uint8_t)); + if (!mac_bytes) return NULL; + + for (size_t i = 0, j = 0; i < 17; i += 3, ++j) { + + mac_bytes[j] = (hex_char_to_uint(macstr[i]) << 4) | hex_char_to_uint(macstr[i + 1]); + + if (i < 15 && macstr[i + 2] != ':' && macstr[i + 2] != '-') { + free(mac_bytes); + return NULL; + } + } + + return mac_bytes; +} + +static uint8_t* hexstr_to_uint8(const char* hexstr, size_t* out_length) { + size_t len = strlen(hexstr); + if (len % 2 != 0) return NULL; + + if (len > EXTRA_BEACON_MAX_DATA_SIZE + 1) return NULL; + + *out_length = len / 2; + uint8_t* bytes = (uint8_t*)malloc(*out_length); + if (!bytes) return NULL; + + for (size_t i = 0; i < *out_length; ++i) { + bytes[i] = (hex_char_to_uint(hexstr[i * 2]) << 4) | hex_char_to_uint(hexstr[i * 2 + 1]); + } + + return bytes; +} + +static void js_blebeacon_set_data(struct mjs *mjs) { + FURI_LOG_D("BLE", "Setting data"); + if (!check_arg_count(mjs, 1)) return; + JSblebeaconInst* inst = get_this_ctx(mjs); + if (!inst) { + FURI_LOG_D("BLE", "Beacon instance is null"); + ret_bad_args(mjs, "Beacon instance is null"); + return; + } + + if (inst->data) { + FURI_LOG_D("BLE", "Freeing existing data"); + free(inst->data); + inst->data = NULL; + } + + + if (!get_str_arg(mjs, 0, &(inst->data))) return; // get_str_arg now modifies inst->data directly + + size_t data_len = 0; + uint8_t* beacon_data = hexstr_to_uint8(inst->data, &data_len); + if (!beacon_data) { + FURI_LOG_D("BLE", "Failed to convert data to hex"); + ret_bad_args(mjs, "Failed to convert data to hex"); + return; + } + + FURI_LOG_D("BLE", "Successfully set beacon data"); + furi_hal_bt_extra_beacon_set_data(beacon_data, data_len); + free(beacon_data); + mjs_return(mjs, MJS_UNDEFINED); +} + +static void js_blebeacon_set_mac(struct mjs *mjs) { + FURI_LOG_D("BLE", "Setting Mac"); + if (!check_arg_count(mjs, 1)) + { + ret_bad_args(mjs, "Bad args"); + return; + } + + JSblebeaconInst* inst = get_this_ctx(mjs); + char* mac_addr = ""; + if (!get_str_arg(mjs, 0, &mac_addr)) return; + inst->mac_addr = mac_addr; + inst->beacon_config.min_adv_interval_ms = 50; + inst->beacon_config.max_adv_interval_ms = 150; + + inst->beacon_config.adv_channel_map = GapAdvChannelMapAll; + inst->beacon_config.adv_power_level = GapAdvPowerLevel_0dBm; + + inst->beacon_config.address_type = GapAddressTypePublic; + + uint8_t* mac = macstr_to_uint8(mac_addr); + if (mac) { + memcpy(inst->beacon_config.address, mac, 6); + furi_hal_bt_extra_beacon_set_config(&inst->beacon_config); + mjs_return(mjs, MJS_UNDEFINED); + } else { + FURI_LOG_D("BLE", "Bad MacAddress"); + ret_bad_args(mjs, "Bad Mac Address"); + return; + } +} + +static void js_blebeacon_send(struct mjs *mjs) { + + furi_hal_bt_extra_beacon_start(); + + mjs_return(mjs, MJS_UNDEFINED); +} + +static void js_blebeacon_stop(struct mjs *mjs) { + + furi_hal_bt_extra_beacon_stop(); + + mjs_return(mjs, MJS_UNDEFINED); +} + +static void* js_blebeacon_create(struct mjs *mjs, mjs_val_t* object) { + JSblebeaconInst* inst = 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, inst)); + mjs_set(mjs, blebeacon_obj, "setData", ~0, MJS_MK_FN(js_blebeacon_set_data)); + mjs_set(mjs, blebeacon_obj, "setMac", ~0, MJS_MK_FN(js_blebeacon_set_mac)); + mjs_set(mjs, blebeacon_obj, "send", ~0, MJS_MK_FN(js_blebeacon_send)); + mjs_set(mjs, blebeacon_obj, "stop", ~0, MJS_MK_FN(js_blebeacon_stop)); + *object = blebeacon_obj; + return inst; +} + +static void js_blebeacon_destroy(void *ptr) { + JSblebeaconInst* inst = (JSblebeaconInst*)ptr; + if (inst) { + free(inst->data); + free(inst->mac_addr); + free(inst); + } +} + +static const JsModuleDescriptor js_blebeacon_desc = { + "blebeacon", + js_blebeacon_create, + js_blebeacon_destroy, +}; + +static const FlipperAppPluginDescriptor blebeacon_plugin_descriptor = { + .appid = PLUGIN_APP_ID, + .ep_api_version = PLUGIN_API_VERSION, + .entry_point = &js_blebeacon_desc, +}; + +const FlipperAppPluginDescriptor* js_blebeacon_ep(void) { + return &blebeacon_plugin_descriptor; +} \ No newline at end of file From 913127854c67a7b696ab4b57276789dc36feb42c Mon Sep 17 00:00:00 2001 From: Spooks <62370103+Spooks4576@users.noreply.github.com> Date: Wed, 6 Mar 2024 02:05:03 -0700 Subject: [PATCH 03/16] Moved Mac Address Gen to API --- .../js_app/examples/apps/Scripts/blebeacon.js | 20 +---- .../system/js_app/modules/js_blebeacon.c | 85 +++++++++++++++++++ 2 files changed, 88 insertions(+), 17 deletions(-) diff --git a/applications/system/js_app/examples/apps/Scripts/blebeacon.js b/applications/system/js_app/examples/apps/Scripts/blebeacon.js index 3f853f2cb..e9c286941 100644 --- a/applications/system/js_app/examples/apps/Scripts/blebeacon.js +++ b/applications/system/js_app/examples/apps/Scripts/blebeacon.js @@ -18,22 +18,6 @@ function byteToHex(byte) { return hex; } -function getNextByteValue() { - let value = currentByteValue; - currentByteValue = (currentByteValue + 1) % 256; - return value; -} - -function generateRandomMac() { - let mac = ''; - for (let i = 0; i < 6; i++) { - if (mac.length) mac += ':'; - let byte = getNextByteValue(); - mac += byteToHex(byte); - } - return mac; -} - function bytesToHexString(bytes) { if (!bytes) { print("Invalid input for bytesToHexString"); @@ -66,7 +50,9 @@ function sendRandomModelAdvertisement() { return; } - bleBeacon.setMac(generateRandomMac()); + let Mac = bleBeacon.genMac(); + + bleBeacon.setMac(Mac); bleBeacon.setData(packetString); bleBeacon.send(); diff --git a/applications/system/js_app/modules/js_blebeacon.c b/applications/system/js_app/modules/js_blebeacon.c index 5bbcb0112..3fbf7f6da 100644 --- a/applications/system/js_app/modules/js_blebeacon.c +++ b/applications/system/js_app/modules/js_blebeacon.c @@ -9,6 +9,78 @@ typedef struct { GapExtraBeaconConfig beacon_config; } JSblebeaconInst; +// Define the OUI Map as a constant array of structs +struct OUI_MAP_ENTRY { + const char *brand; + const char *oui; +}; + +struct OUI_MAP_ENTRY OUI_MAP[] = { + {"Apple", "00:1F:7F"}, + {"Dell", "00:14:5F"}, + {"HP", "00:4C:6F"}, + {"Lenovo", "00:50:C2"}, + {"Microsoft", "00:0C:29"}, + {"Samsung", "00:1C:42"}, + {"Sony", "00:0A:95"}, + {"Acer", "00:26:A9"}, + {"Asus", "00:19:D8"}, + {"Google", "08:00:27"}, + {"HTC", "00:1F:B5"}, + {"Intel", "00:19:5D"}, + {"LG", "00:1C:61"}, + {"Motorola", "00:1F:42"}, + {"Toshiba", "00:1E:67"}, + {"Xiaomi", "00:26:A8"}, +}; + +#define OUI_MAP_SIZE (sizeof(OUI_MAP) / sizeof(OUI_MAP[0])) + + +int rand_range(int min, int max) { + return min + rand() / (RAND_MAX / (max - min + 1) + 1); +} + +void byte_to_hex(char *output, unsigned char byte) { + static const char hex_chars[] = "0123456789ABCDEF"; + output[0] = hex_chars[byte >> 4]; + output[1] = hex_chars[byte & 0x0F]; +} + +static char* generate_mac_address(const char *brand) { + char *mac_address = (char*)malloc(18 * sizeof(char)); + if (mac_address == NULL) { + FURI_LOG_D("BLE", "Memory allocation failed.\n"); + return NULL; + } + + const char *oui = NULL; + for (unsigned int i = 0; i < OUI_MAP_SIZE; ++i) { + if (strcmp(brand, OUI_MAP[i].brand) == 0) { + oui = OUI_MAP[i].oui; + break; + } + } + + if (oui == NULL) { + FURI_LOG_D("BLE", "Brand not found.\n"); + free(mac_address); + return NULL; + } + + + char last_bytes[6]; + for (int i = 0; i < 3; ++i) { + unsigned char byte = rand_range(0x00, 0xFF); + byte_to_hex(&last_bytes[i * 2], byte); + } + + strcpy(mac_address, oui); + strcat(mac_address, ":"); + strcat(mac_address, last_bytes); + return mac_address; +} + 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); @@ -129,6 +201,18 @@ static void js_blebeacon_set_data(struct mjs *mjs) { mjs_return(mjs, MJS_UNDEFINED); } +static void js_blebeacon_generate_mac(struct mjs *mjs) +{ + char* company = ""; + if (!get_str_arg(mjs, 0, &company)) return; + + char* mac = generate_mac_address(company); + + mjs_val_t js_mac_address = mjs_mk_string(mjs, mac, strlen(mac), 1); + + return mjs_return(mjs, js_mac_address); +} + static void js_blebeacon_set_mac(struct mjs *mjs) { FURI_LOG_D("BLE", "Setting Mac"); if (!check_arg_count(mjs, 1)) @@ -183,6 +267,7 @@ static void* js_blebeacon_create(struct mjs *mjs, mjs_val_t* object) { mjs_set(mjs, blebeacon_obj, "setMac", ~0, MJS_MK_FN(js_blebeacon_set_mac)); mjs_set(mjs, blebeacon_obj, "send", ~0, MJS_MK_FN(js_blebeacon_send)); mjs_set(mjs, blebeacon_obj, "stop", ~0, MJS_MK_FN(js_blebeacon_stop)); + mjs_set(mjs, blebeacon_obj, "genMac", ~0, MJS_MK_FN(js_blebeacon_generate_mac)); *object = blebeacon_obj; return inst; } From c43d9d3bddc2bd6537e2a2f959477a7b5c3d56c6 Mon Sep 17 00:00:00 2001 From: Spooks <62370103+Spooks4576@users.noreply.github.com> Date: Wed, 6 Mar 2024 11:03:26 -0700 Subject: [PATCH 04/16] Math --- applications/system/js_app/application.fam | 10 + .../js_app/examples/apps/Scripts/math.js | 47 +++ .../system/js_app/modules/js_blebeacon.c | 2 +- applications/system/js_app/modules/js_math.c | 309 ++++++++++++++++++ 4 files changed, 367 insertions(+), 1 deletion(-) create mode 100644 applications/system/js_app/examples/apps/Scripts/math.js create mode 100644 applications/system/js_app/modules/js_math.c diff --git a/applications/system/js_app/application.fam b/applications/system/js_app/application.fam index 40fe06cff..779ecd8ad 100644 --- a/applications/system/js_app/application.fam +++ b/applications/system/js_app/application.fam @@ -78,3 +78,13 @@ App( requires=["js_app"], sources=["modules/js_blebeacon.c"], ) + +App( + appid="js_math", + apptype=FlipperAppType.PLUGIN, + entry_point="js_math_ep", + requires=["js_app"], + sources=["modules/js_math.c"], +) + + diff --git a/applications/system/js_app/examples/apps/Scripts/math.js b/applications/system/js_app/examples/apps/Scripts/math.js new file mode 100644 index 000000000..49212f904 --- /dev/null +++ b/applications/system/js_app/examples/apps/Scripts/math.js @@ -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); \ No newline at end of file diff --git a/applications/system/js_app/modules/js_blebeacon.c b/applications/system/js_app/modules/js_blebeacon.c index 3fbf7f6da..ff7176c52 100644 --- a/applications/system/js_app/modules/js_blebeacon.c +++ b/applications/system/js_app/modules/js_blebeacon.c @@ -9,7 +9,7 @@ typedef struct { GapExtraBeaconConfig beacon_config; } JSblebeaconInst; -// Define the OUI Map as a constant array of structs + struct OUI_MAP_ENTRY { const char *brand; const char *oui; diff --git a/applications/system/js_app/modules/js_math.c b/applications/system/js_app/modules/js_math.c new file mode 100644 index 000000000..d17b72b88 --- /dev/null +++ b/applications/system/js_app/modules/js_math.c @@ -0,0 +1,309 @@ +#include "../js_modules.h" +#include "furi_hal_random.h" + +#define MJS_PI (double)3.14159265358979323846 +#define MJS_E (double)2.7182818284590452354 + +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_mk_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; +} + +void mjs_abs(struct mjs* mjs) { + if (!check_arg_count(mjs, 1) || !mjs_is_number(mjs_arg(mjs, 0))) { + mjs_return(mjs, MJS_UNDEFINED); + } + double x = mjs_get_double(mjs, mjs_arg(mjs, 0)); + mjs_return(mjs, x < 0 ? mjs_mk_number(mjs, -x) : mjs_arg(mjs, 0)); +} + +void mjs_acos(struct mjs* mjs) { + if (!check_arg_count(mjs, 1) || !mjs_is_number(mjs_arg(mjs, 0))) { + mjs_return(mjs, MJS_UNDEFINED); + } + double x = mjs_get_double(mjs, mjs_arg(mjs, 0)); + if (x < -1 || x > 1) { + ret_bad_args(mjs, "Invalid input value for Math.acos"); + mjs_return(mjs, MJS_UNDEFINED); + } + mjs_return(mjs, mjs_mk_number(mjs, MJS_PI / (double)2 - atan(x / sqrt(1 - x * x)))); +} + +void mjs_acosh(struct mjs* mjs) { + if (!check_arg_count(mjs, 1) || !mjs_is_number(mjs_arg(mjs, 0))) { + mjs_return(mjs, MJS_UNDEFINED); + } + double x = mjs_get_double(mjs, mjs_arg(mjs, 0)); + if (x < 1) { + ret_bad_args(mjs, "Invalid input value for Math.acosh"); + mjs_return(mjs, MJS_UNDEFINED); + } + mjs_return(mjs, mjs_mk_number(mjs, log(x + sqrt(x * x - 1)))); +} + +void mjs_asin(struct mjs* mjs) { + if (!check_arg_count(mjs, 1) || !mjs_is_number(mjs_arg(mjs, 0))) { + mjs_return(mjs, MJS_UNDEFINED); + } + double x = mjs_get_double(mjs, mjs_arg(mjs, 0)); + mjs_return(mjs, mjs_mk_number(mjs, atan(x / sqrt(1 - x * x)))); +} + +void mjs_asinh(struct mjs* mjs) { + if (!check_arg_count(mjs, 1) || !mjs_is_number(mjs_arg(mjs, 0))) { + mjs_return(mjs, MJS_UNDEFINED); + } + double x = mjs_get_double(mjs, mjs_arg(mjs, 0)); + mjs_return(mjs, mjs_mk_number(mjs, log(x + sqrt(x * x + 1)))); +} + +void mjs_atan(struct mjs* mjs) { + if (!check_arg_count(mjs, 1) || !mjs_is_number(mjs_arg(mjs, 0))) { + mjs_return(mjs, MJS_UNDEFINED); + } + double x = mjs_get_double(mjs, mjs_arg(mjs, 0)); + mjs_return(mjs, mjs_mk_number(mjs, atan(x))); +} + +void mjs_atan2(struct mjs* mjs) { + if (!check_arg_count(mjs, 2) || !mjs_is_number(mjs_arg(mjs, 0)) || !mjs_is_number(mjs_arg(mjs, 1))) { + mjs_return(mjs, MJS_UNDEFINED); + } + double y = mjs_get_double(mjs, mjs_arg(mjs, 0)); + double x = mjs_get_double(mjs, mjs_arg(mjs, 1)); + mjs_return(mjs, mjs_mk_number(mjs, atan2(y, x))); +} + +void mjs_atanh(struct mjs* mjs) { + if (!check_arg_count(mjs, 1) || !mjs_is_number(mjs_arg(mjs, 0))) { + mjs_return(mjs, MJS_UNDEFINED); + } + double x = mjs_get_double(mjs, mjs_arg(mjs, 0)); + if (x <= -1 || x >= 1) { + ret_bad_args(mjs, "Invalid input value for Math.atanh"); + mjs_return(mjs, MJS_UNDEFINED); + } + mjs_return(mjs, mjs_mk_number(mjs, (double)0.5 * log((1 + x) / (1 - x)))); +} + +void mjs_cbrt(struct mjs* mjs) { + if (!check_arg_count(mjs, 1) || !mjs_is_number(mjs_arg(mjs, 0))) { + mjs_return(mjs, MJS_UNDEFINED); + } + double x = mjs_get_double(mjs, mjs_arg(mjs, 0)); + mjs_return(mjs, mjs_mk_number(mjs, pow(x, 1.0 / 3.0))); +} + +void mjs_ceil(struct mjs* mjs) { + if (!check_arg_count(mjs, 1) || !mjs_is_number(mjs_arg(mjs, 0))) { + mjs_return(mjs, MJS_UNDEFINED); + } + double x = mjs_get_double(mjs, mjs_arg(mjs, 0)); + mjs_return(mjs, mjs_mk_number(mjs, (int)(x + (double)0.5))); +} + +void mjs_clz32(struct mjs* mjs) { + if (!check_arg_count(mjs, 1) || !mjs_is_number(mjs_arg(mjs, 0))) { + mjs_return(mjs, MJS_UNDEFINED); + } + unsigned int x = (unsigned int)mjs_get_int(mjs, mjs_arg(mjs, 0)); + int count = 0; + while (x) { + x >>= 1; + count++; + } + mjs_return(mjs, mjs_mk_number(mjs, 32 - count)); +} + +void mjs_cos(struct mjs* mjs) { + if (!check_arg_count(mjs, 1) || !mjs_is_number(mjs_arg(mjs, 0))) { + mjs_return(mjs, MJS_UNDEFINED); + } + double x = mjs_get_double(mjs, mjs_arg(mjs, 0)); + mjs_return(mjs, mjs_mk_number(mjs, cos(x))); +} + +void mjs_exp(struct mjs* mjs) { + if (!check_arg_count(mjs, 1) || !mjs_is_number(mjs_arg(mjs, 0))) { + mjs_return(mjs, MJS_UNDEFINED); + } + double x = mjs_get_double(mjs, mjs_arg(mjs, 0)); + double result = 1; + double term = 1; + for (int i = 1; i < 100; i++) { + term *= x / i; + result += term; + } + mjs_return(mjs, mjs_mk_number(mjs, result)); +} + +void mjs_floor(struct mjs* mjs) { + if (!check_arg_count(mjs, 1) || !mjs_is_number(mjs_arg(mjs, 0))) { + mjs_return(mjs, MJS_UNDEFINED); + } + double x = mjs_get_double(mjs, mjs_arg(mjs, 0)); + mjs_return(mjs, mjs_mk_number(mjs, (int)x)); +} + +void mjs_log(struct mjs* mjs) { + if (!check_arg_count(mjs, 1) || !mjs_is_number(mjs_arg(mjs, 0))) { + mjs_return(mjs, MJS_UNDEFINED); + } + double x = mjs_get_double(mjs, mjs_arg(mjs, 0)); + if (x <= 0) { + ret_bad_args(mjs, "Invalid input value for Math.log"); + mjs_return(mjs, MJS_UNDEFINED); + } + double result = 0; + while (x >= MJS_E) { + x /= MJS_E; + result++; + } + mjs_return(mjs, mjs_mk_number(mjs, result + log(x))); +} + +void mjs_max(struct mjs* mjs) { + if (!check_arg_count(mjs, 2) || !mjs_is_number(mjs_arg(mjs, 0)) || !mjs_is_number(mjs_arg(mjs, 1))) { + mjs_return(mjs, MJS_UNDEFINED); + } + double x = mjs_get_double(mjs, mjs_arg(mjs, 0)); + double y = mjs_get_double(mjs, mjs_arg(mjs, 1)); + mjs_return(mjs, mjs_mk_number(mjs, x > y ? x : y)); +} + +void mjs_min(struct mjs* mjs) { + if (!check_arg_count(mjs, 2) || !mjs_is_number(mjs_arg(mjs, 0)) || !mjs_is_number(mjs_arg(mjs, 1))) { + mjs_return(mjs, MJS_UNDEFINED); + } + double x = mjs_get_double(mjs, mjs_arg(mjs, 0)); + double y = mjs_get_double(mjs, mjs_arg(mjs, 1)); + mjs_return(mjs, mjs_mk_number(mjs, x < y ? x : y)); +} + +void mjs_pow(struct mjs* mjs) { + if (!check_arg_count(mjs, 2) || !mjs_is_number(mjs_arg(mjs, 0)) || !mjs_is_number(mjs_arg(mjs, 1))) { + mjs_return(mjs, MJS_UNDEFINED); + } + double base = mjs_get_double(mjs, mjs_arg(mjs, 0)); + double exponent = mjs_get_double(mjs, mjs_arg(mjs, 1)); + double result = 1; + for (int i = 0; i < exponent; i++) { + result *= base; + } + mjs_return(mjs, mjs_mk_number(mjs, result)); +} + +void mjs_random(struct mjs* mjs) { + if (!check_arg_count(mjs, 0)) { + mjs_return(mjs, MJS_UNDEFINED); + } + const uint32_t random_val = furi_hal_random_get(); + double rnd = (double)random_val / RAND_MAX; + mjs_return(mjs, mjs_mk_number(mjs, rnd)); +} + +void mjs_sign(struct mjs* mjs) { + if (!check_arg_count(mjs, 1) || !mjs_is_number(mjs_arg(mjs, 0))) { + mjs_return(mjs, MJS_UNDEFINED); + } + double x = mjs_get_double(mjs, mjs_arg(mjs, 0)); + mjs_return(mjs, mjs_mk_number(mjs, x == 0 ? 0 : (x < 0 ? -1 : 1))); +} + +void mjs_sin(struct mjs* mjs) { + if (!check_arg_count(mjs, 1) || !mjs_is_number(mjs_arg(mjs, 0))) { + mjs_return(mjs, MJS_UNDEFINED); + } + double x = mjs_get_double(mjs, mjs_arg(mjs, 0)); + double result = x; + double term = x; + for (int i = 1; i < 10; i++) { + term *= -x * x / ((2 * i) * (2 * i + 1)); + result += term; + } + mjs_return(mjs, mjs_mk_number(mjs, result)); +} + +void mjs_sqrt(struct mjs* mjs) { + if (!check_arg_count(mjs, 1) || !mjs_is_number(mjs_arg(mjs, 0))) { + mjs_return(mjs, MJS_UNDEFINED); + } + double x = mjs_get_double(mjs, mjs_arg(mjs, 0)); + if (x < 0) { + ret_bad_args(mjs, "Invalid input value for Math.sqrt"); + mjs_return(mjs, MJS_UNDEFINED); + } + double result = 1; + while (result * result < x) { + result += (double)0.001; + } + mjs_return(mjs, mjs_mk_number(mjs, result)); +} + +void mjs_trunc(struct mjs* mjs) { + if (!check_arg_count(mjs, 1) || !mjs_is_number(mjs_arg(mjs, 0))) { + mjs_return(mjs, MJS_UNDEFINED); + } + double x = mjs_get_double(mjs, mjs_arg(mjs, 0)); + mjs_return(mjs, mjs_mk_number(mjs, x < 0 ? ceil(x) : floor(x))); +} + + +static void* js_math_create(struct mjs *mjs, mjs_val_t* object) { + mjs_val_t math_obj = mjs_mk_object(mjs); + mjs_set(mjs, math_obj, "abs", ~0, MJS_MK_FN(mjs_abs)); + mjs_set(mjs, math_obj, "acos", ~0, MJS_MK_FN(mjs_acos)); + mjs_set(mjs, math_obj, "acosh", ~0, MJS_MK_FN(mjs_acosh)); + mjs_set(mjs, math_obj, "asin", ~0, MJS_MK_FN(mjs_asin)); + mjs_set(mjs, math_obj, "asinh", ~0, MJS_MK_FN(mjs_asinh)); + mjs_set(mjs, math_obj, "atan", ~0, MJS_MK_FN(mjs_atan)); + mjs_set(mjs, math_obj, "atan2", ~0, MJS_MK_FN(mjs_atan2)); + mjs_set(mjs, math_obj, "atanh", ~0, MJS_MK_FN(mjs_atanh)); + mjs_set(mjs, math_obj, "cbrt", ~0, MJS_MK_FN(mjs_cbrt)); + mjs_set(mjs, math_obj, "ceil", ~0, MJS_MK_FN(mjs_ceil)); + mjs_set(mjs, math_obj, "clz32", ~0, MJS_MK_FN(mjs_clz32)); + mjs_set(mjs, math_obj, "cos", ~0, MJS_MK_FN(mjs_cos)); + mjs_set(mjs, math_obj, "exp", ~0, MJS_MK_FN(mjs_exp)); + mjs_set(mjs, math_obj, "floor", ~0, MJS_MK_FN(mjs_floor)); + mjs_set(mjs, math_obj, "log", ~0, MJS_MK_FN(mjs_log)); + mjs_set(mjs, math_obj, "max", ~0, MJS_MK_FN(mjs_max)); + mjs_set(mjs, math_obj, "min", ~0, MJS_MK_FN(mjs_min)); + mjs_set(mjs, math_obj, "pow", ~0, MJS_MK_FN(mjs_pow)); + mjs_set(mjs, math_obj, "random", ~0, MJS_MK_FN(mjs_random)); + mjs_set(mjs, math_obj, "sign", ~0, MJS_MK_FN(mjs_sign)); + mjs_set(mjs, math_obj, "sin", ~0, MJS_MK_FN(mjs_sin)); + mjs_set(mjs, math_obj, "sqrt", ~0, MJS_MK_FN(mjs_sqrt)); + mjs_set(mjs, math_obj, "trunc", ~0, MJS_MK_FN(mjs_trunc)); + mjs_set(mjs, math_obj, "PI", ~0, mjs_mk_number(mjs, MJS_PI)); + *object = math_obj; + return object; +} + +static void js_math_destroy(void *ptr) { + UNUSED(ptr); +} + +static const JsModuleDescriptor js_math_desc = { + "math", + js_math_create, + js_math_destroy, +}; + +static const FlipperAppPluginDescriptor btkicker_plugin_descriptor = { + .appid = PLUGIN_APP_ID, + .ep_api_version = PLUGIN_API_VERSION, + .entry_point = &js_math_desc, +}; + +const FlipperAppPluginDescriptor* js_math_ep(void) { + return &btkicker_plugin_descriptor; +} \ No newline at end of file From 2ff6dc8c1deb82fea63821d13ba37cd790b3dbae Mon Sep 17 00:00:00 2001 From: Spooks <62370103+Spooks4576@users.noreply.github.com> Date: Wed, 6 Mar 2024 15:02:00 -0700 Subject: [PATCH 05/16] Keyboard WIP (Byte Input Doesn't Work) --- applications/system/js_app/application.fam | 8 + .../js_app/examples/apps/Scripts/keyboard.js | 5 + .../system/js_app/modules/js_keyboard.c | 206 ++++++++++++++++++ 3 files changed, 219 insertions(+) create mode 100644 applications/system/js_app/examples/apps/Scripts/keyboard.js create mode 100644 applications/system/js_app/modules/js_keyboard.c diff --git a/applications/system/js_app/application.fam b/applications/system/js_app/application.fam index 779ecd8ad..8bd2f4a2f 100644 --- a/applications/system/js_app/application.fam +++ b/applications/system/js_app/application.fam @@ -87,4 +87,12 @@ App( sources=["modules/js_math.c"], ) +App( + appid="js_keyboard", + apptype=FlipperAppType.PLUGIN, + entry_point="js_keyboard_ep", + requires=["js_app"], + sources=["modules/js_keyboard.c"], +) + diff --git a/applications/system/js_app/examples/apps/Scripts/keyboard.js b/applications/system/js_app/examples/apps/Scripts/keyboard.js new file mode 100644 index 000000000..6e7b8332a --- /dev/null +++ b/applications/system/js_app/examples/apps/Scripts/keyboard.js @@ -0,0 +1,5 @@ +let keyboard = require("keyboard"); + +let text = keyboard.text(100, "Please Input Shit", 1); + +print(text); \ No newline at end of file diff --git a/applications/system/js_app/modules/js_keyboard.c b/applications/system/js_app/modules/js_keyboard.c new file mode 100644 index 000000000..1988fda25 --- /dev/null +++ b/applications/system/js_app/modules/js_keyboard.c @@ -0,0 +1,206 @@ +#include "../js_modules.h" +#include +#include +#include + +#define membersof(x) (sizeof(x) / sizeof(x[0])) + +typedef struct { + char* data; + TextInput* textinput; + ByteInput* byteinputview; + ViewDispatcher* view_dispatcher; + uint8_t* byteinput; +} JSkeyboardInst; + +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); +} + +char nibble_to_hex_character(uint8_t nibble) { + nibble &= 0xF; + if (nibble < 10) { + return '0' + nibble; + } else { + return 'A' + (nibble - 10); + } +} + +char* bytes_to_hex_string(uint8_t* bytes, size_t num_bytes) { + char* hex_string = (char*)malloc(num_bytes * 2 + 1); + if (hex_string == NULL) { + FURI_LOG_D("LOG", "Memory allocation failed\n"); + return NULL; + } + + for (size_t i = 0; i < num_bytes; ++i) { + hex_string[i * 2] = nibble_to_hex_character(bytes[i] >> 4); + hex_string[i * 2 + 1] = nibble_to_hex_character(bytes[i] & 0xF); + } + hex_string[num_bytes * 2] = '\0'; + + return hex_string; +} + +static bool get_str_arg(struct mjs* mjs, size_t index, const char** value) { + mjs_val_t str_obj = mjs_arg(mjs, index); + if(!mjs_is_string(str_obj)) { + ret_bad_args(mjs, "Argument must be a string"); + return false; + } + size_t str_len = 0; + *value = mjs_get_string(mjs, &str_obj, &str_len); + if((str_len == 0) || (*value == NULL)) { + ret_bad_args(mjs, "Bad string argument"); + return false; + } + return true; +} + +static bool get_int_arg(struct mjs* mjs, size_t index, int* value) { + mjs_val_t int_obj = mjs_arg(mjs, index); + if(!mjs_is_number(int_obj)) { + return false; + } + *value = (int)mjs_get_int(mjs, int_obj); + return true; +} + +static JSkeyboardInst* get_this_ctx(struct mjs* mjs) { + mjs_val_t obj_inst = mjs_get(mjs, mjs_get_this(mjs), INST_PROP_NAME, ~0); + JSkeyboardInst* storage = mjs_get_ptr(mjs, obj_inst); + furi_assert(storage); + return storage; +} + +void text_input_callback(void* context) +{ + JSkeyboardInst* keyboardinst = (JSkeyboardInst*)context; + view_dispatcher_stop(keyboardinst->view_dispatcher); +} + +void byte_input_callback(void* context) +{ + JSkeyboardInst* keyboardinst = (JSkeyboardInst*)context; + view_dispatcher_stop(keyboardinst->view_dispatcher); +} + +static void js_keyboard_text(struct mjs *mjs) { + + JSkeyboardInst* keyboardinst = get_this_ctx(mjs); + + int MaxInputLength; + if(!get_int_arg(mjs, 0, &MaxInputLength)) return; + + const char* defaultText = ""; + get_str_arg(mjs, 1, &defaultText); + + int ShouldSelect; + mjs_val_t bool_obj = mjs_arg(mjs, 2); + ShouldSelect = (int)mjs_get_bool(mjs, bool_obj); + + if (keyboardinst->textinput && keyboardinst->view_dispatcher) + { + if (strlen(defaultText) > 0) + { + text_input_set_header_text(keyboardinst->textinput, defaultText); + } + + view_dispatcher_attach_to_gui( + keyboardinst->view_dispatcher, furi_record_open(RECORD_GUI), ViewDispatcherTypeFullscreen); + furi_record_close(RECORD_GUI); + + text_input_set_result_callback(keyboardinst->textinput, text_input_callback, keyboardinst, keyboardinst->data, MaxInputLength, ShouldSelect); + + view_dispatcher_switch_to_view(keyboardinst->view_dispatcher, 0); + + view_dispatcher_run(keyboardinst->view_dispatcher); + } + + text_input_reset(keyboardinst->textinput); + + mjs_return(mjs, mjs_mk_string(mjs, keyboardinst->data, strlen(keyboardinst->data), 1)); +} + +static void js_keyboard_byte(struct mjs *mjs) { + + + + JSkeyboardInst* keyboardinst = get_this_ctx(mjs); + + int MaxInputLength; + if(!get_int_arg(mjs, 0, &MaxInputLength)) return; + + const char* defaultText; + get_str_arg(mjs, 1, &defaultText); + + if (keyboardinst->byteinputview && keyboardinst->view_dispatcher) + { + if (strlen(defaultText) > 0) + { + byte_input_set_header_text(keyboardinst->byteinputview, defaultText); + } + + view_dispatcher_attach_to_gui( + keyboardinst->view_dispatcher, furi_record_open(RECORD_GUI), ViewDispatcherTypeFullscreen); + furi_record_close(RECORD_GUI); + + byte_input_set_result_callback(keyboardinst->byteinputview, byte_input_callback, NULL, keyboardinst, keyboardinst->byteinput, 10); + + view_dispatcher_switch_to_view(keyboardinst->view_dispatcher, 1); + + view_dispatcher_run(keyboardinst->view_dispatcher); + } + + FURI_LOG_D("SHIT", "DID THING"); + keyboardinst->data = bytes_to_hex_string(keyboardinst->byteinput, 10); + FURI_LOG_D("SHIT", "DID THING 1"); + mjs_return(mjs, mjs_mk_string(mjs, keyboardinst->data, strlen(keyboardinst->data), 1)); + FURI_LOG_D("SHIT", "DID THING 2"); +} + + +static void* js_keyboard_create(struct mjs* mjs, mjs_val_t* object) { + JSkeyboardInst* keyboardinst = malloc(sizeof(JSkeyboardInst)); + mjs_val_t keyboard_obj = mjs_mk_object(mjs); + mjs_set(mjs, keyboard_obj, INST_PROP_NAME, ~0, mjs_mk_foreign(mjs, keyboardinst)); + mjs_set(mjs, keyboard_obj, "text", ~0, MJS_MK_FN(js_keyboard_text)); + //mjs_set(mjs, keyboard_obj, "byte", ~0, MJS_MK_FN(js_keyboard_byte)); // NULL POINTER DEREFERENCE + keyboardinst->byteinputview = byte_input_alloc(); + keyboardinst->textinput = text_input_alloc(); + keyboardinst->view_dispatcher = view_dispatcher_alloc(); + keyboardinst->data = malloc(100); + keyboardinst->byteinput = malloc(100); + view_dispatcher_enable_queue(keyboardinst->view_dispatcher); + view_dispatcher_add_view(keyboardinst->view_dispatcher, 0, text_input_get_view(keyboardinst->textinput)); + view_dispatcher_add_view(keyboardinst->view_dispatcher, 1, byte_input_get_view(keyboardinst->byteinputview)); + *object = keyboard_obj; + return keyboardinst; +} + +static void js_keyboard_destroy(void* inst) { + JSkeyboardInst* insts = (JSkeyboardInst*)inst; + byte_input_free(insts->byteinputview); + text_input_free(insts->textinput); + view_dispatcher_free(insts->view_dispatcher); + free(insts->data); + free(insts); +} + +static const JsModuleDescriptor js_keyboard_desc = { + "keyboard", + js_keyboard_create, + js_keyboard_destroy, +}; + +static const FlipperAppPluginDescriptor keyboard_plugin_descriptor = { + .appid = PLUGIN_APP_ID, + .ep_api_version = PLUGIN_API_VERSION, + .entry_point = &js_keyboard_desc, +}; + +const FlipperAppPluginDescriptor* js_keyboard_ep(void) { + UNUSED(js_keyboard_byte); + return &keyboard_plugin_descriptor; +} \ No newline at end of file From 337486df873b2abddea5f729b0edb3c919eaad84 Mon Sep 17 00:00:00 2001 From: Spooks <62370103+Spooks4576@users.noreply.github.com> Date: Wed, 6 Mar 2024 15:48:53 -0700 Subject: [PATCH 06/16] Update blebeacon.js --- .../js_app/examples/apps/Scripts/blebeacon.js | 23 +++++++++++++++---- 1 file changed, 18 insertions(+), 5 deletions(-) diff --git a/applications/system/js_app/examples/apps/Scripts/blebeacon.js b/applications/system/js_app/examples/apps/Scripts/blebeacon.js index e9c286941..f324fafd9 100644 --- a/applications/system/js_app/examples/apps/Scripts/blebeacon.js +++ b/applications/system/js_app/examples/apps/Scripts/blebeacon.js @@ -18,6 +18,22 @@ function byteToHex(byte) { return hex; } +function getNextByteValue() { + let value = currentByteValue; + currentByteValue = (currentByteValue + 1) % 256; + return value; +} + +function generateRandomMac() { + let mac = ''; + for (let i = 0; i < 6; i++) { + if (mac.length) mac += ':'; + let byte = getNextByteValue(); + mac += byteToHex(byte); + } + return mac; +} + function bytesToHexString(bytes) { if (!bytes) { print("Invalid input for bytesToHexString"); @@ -50,9 +66,7 @@ function sendRandomModelAdvertisement() { return; } - let Mac = bleBeacon.genMac(); - - bleBeacon.setMac(Mac); + bleBeacon.setMac(generateRandomMac()); bleBeacon.setData(packetString); bleBeacon.send(); @@ -60,8 +74,7 @@ function sendRandomModelAdvertisement() { currentIndex = (currentIndex + 1) % watchValues.length; - delay(500); // 500 Ms is the fatest we can manage to recieve - // in C Flipper is way faster at spamming this + delay(500); bleBeacon.stop(); From 86986278d3ccfcd6ad3d8fde974f54942578d4b1 Mon Sep 17 00:00:00 2001 From: Willy-JL <49810075+Willy-JL@users.noreply.github.com> Date: Thu, 7 Mar 2024 04:56:53 +0000 Subject: [PATCH 07/16] Format --- applications/system/js_app/application.fam | 2 - .../system/js_app/modules/js_blebeacon.c | 97 +++++++++---------- .../system/js_app/modules/js_keyboard.c | 63 ++++++------ applications/system/js_app/modules/js_math.c | 79 +++++++-------- 4 files changed, 120 insertions(+), 121 deletions(-) diff --git a/applications/system/js_app/application.fam b/applications/system/js_app/application.fam index 8bd2f4a2f..74be8273d 100644 --- a/applications/system/js_app/application.fam +++ b/applications/system/js_app/application.fam @@ -94,5 +94,3 @@ App( requires=["js_app"], sources=["modules/js_keyboard.c"], ) - - diff --git a/applications/system/js_app/modules/js_blebeacon.c b/applications/system/js_app/modules/js_blebeacon.c index ff7176c52..0e77e5648 100644 --- a/applications/system/js_app/modules/js_blebeacon.c +++ b/applications/system/js_app/modules/js_blebeacon.c @@ -9,10 +9,9 @@ typedef struct { GapExtraBeaconConfig beacon_config; } JSblebeaconInst; - struct OUI_MAP_ENTRY { - const char *brand; - const char *oui; + const char* brand; + const char* oui; }; struct OUI_MAP_ENTRY OUI_MAP[] = { @@ -36,41 +35,39 @@ struct OUI_MAP_ENTRY OUI_MAP[] = { #define OUI_MAP_SIZE (sizeof(OUI_MAP) / sizeof(OUI_MAP[0])) - int rand_range(int min, int max) { return min + rand() / (RAND_MAX / (max - min + 1) + 1); } -void byte_to_hex(char *output, unsigned char byte) { +void byte_to_hex(char* output, unsigned char byte) { static const char hex_chars[] = "0123456789ABCDEF"; output[0] = hex_chars[byte >> 4]; output[1] = hex_chars[byte & 0x0F]; } -static char* generate_mac_address(const char *brand) { - char *mac_address = (char*)malloc(18 * sizeof(char)); - if (mac_address == NULL) { +static char* generate_mac_address(const char* brand) { + char* mac_address = (char*)malloc(18 * sizeof(char)); + if(mac_address == NULL) { FURI_LOG_D("BLE", "Memory allocation failed.\n"); return NULL; } - const char *oui = NULL; - for (unsigned int i = 0; i < OUI_MAP_SIZE; ++i) { - if (strcmp(brand, OUI_MAP[i].brand) == 0) { + const char* oui = NULL; + for(unsigned int i = 0; i < OUI_MAP_SIZE; ++i) { + if(strcmp(brand, OUI_MAP[i].brand) == 0) { oui = OUI_MAP[i].oui; break; } } - if (oui == NULL) { + if(oui == NULL) { FURI_LOG_D("BLE", "Brand not found.\n"); free(mac_address); return NULL; } - char last_bytes[6]; - for (int i = 0; i < 3; ++i) { + for(int i = 0; i < 3; ++i) { unsigned char byte = rand_range(0x00, 0xFF); byte_to_hex(&last_bytes[i * 2], byte); } @@ -114,9 +111,9 @@ static bool get_str_arg(struct mjs* mjs, size_t index, char** value) { ret_bad_args(mjs, "Bad string argument"); return false; } - + *value = (char*)malloc(str_len + 1); - if (!*value) { + if(!*value) { ret_bad_args(mjs, "Memory allocation failed"); return false; } @@ -126,24 +123,23 @@ static bool get_str_arg(struct mjs* mjs, size_t index, char** value) { } static uint8_t hex_char_to_uint(char c) { - if (c >= '0' && c <= '9') return c - '0'; - if (c >= 'a' && c <= 'f') return 10 + c - 'a'; - if (c >= 'A' && c <= 'F') return 10 + c - 'A'; + if(c >= '0' && c <= '9') return c - '0'; + if(c >= 'a' && c <= 'f') return 10 + c - 'a'; + if(c >= 'A' && c <= 'F') return 10 + c - 'A'; return 0; } static uint8_t* macstr_to_uint8(const char* macstr) { - if (strlen(macstr) != 17) return NULL; + if(strlen(macstr) != 17) return NULL; uint8_t* mac_bytes = (uint8_t*)malloc(6 * sizeof(uint8_t)); - if (!mac_bytes) return NULL; - - for (size_t i = 0, j = 0; i < 17; i += 3, ++j) { + if(!mac_bytes) return NULL; + for(size_t i = 0, j = 0; i < 17; i += 3, ++j) { mac_bytes[j] = (hex_char_to_uint(macstr[i]) << 4) | hex_char_to_uint(macstr[i + 1]); - if (i < 15 && macstr[i + 2] != ':' && macstr[i + 2] != '-') { - free(mac_bytes); + if(i < 15 && macstr[i + 2] != ':' && macstr[i + 2] != '-') { + free(mac_bytes); return NULL; } } @@ -153,43 +149,42 @@ static uint8_t* macstr_to_uint8(const char* macstr) { static uint8_t* hexstr_to_uint8(const char* hexstr, size_t* out_length) { size_t len = strlen(hexstr); - if (len % 2 != 0) return NULL; + if(len % 2 != 0) return NULL; - if (len > EXTRA_BEACON_MAX_DATA_SIZE + 1) return NULL; + if(len > EXTRA_BEACON_MAX_DATA_SIZE + 1) return NULL; *out_length = len / 2; uint8_t* bytes = (uint8_t*)malloc(*out_length); - if (!bytes) return NULL; + if(!bytes) return NULL; - for (size_t i = 0; i < *out_length; ++i) { + for(size_t i = 0; i < *out_length; ++i) { bytes[i] = (hex_char_to_uint(hexstr[i * 2]) << 4) | hex_char_to_uint(hexstr[i * 2 + 1]); } return bytes; } -static void js_blebeacon_set_data(struct mjs *mjs) { +static void js_blebeacon_set_data(struct mjs* mjs) { FURI_LOG_D("BLE", "Setting data"); - if (!check_arg_count(mjs, 1)) return; + if(!check_arg_count(mjs, 1)) return; JSblebeaconInst* inst = get_this_ctx(mjs); - if (!inst) { + if(!inst) { FURI_LOG_D("BLE", "Beacon instance is null"); ret_bad_args(mjs, "Beacon instance is null"); return; } - if (inst->data) { + if(inst->data) { FURI_LOG_D("BLE", "Freeing existing data"); free(inst->data); - inst->data = NULL; + inst->data = NULL; } - - if (!get_str_arg(mjs, 0, &(inst->data))) return; // get_str_arg now modifies inst->data directly + if(!get_str_arg(mjs, 0, &(inst->data))) return; // get_str_arg now modifies inst->data directly size_t data_len = 0; uint8_t* beacon_data = hexstr_to_uint8(inst->data, &data_len); - if (!beacon_data) { + if(!beacon_data) { FURI_LOG_D("BLE", "Failed to convert data to hex"); ret_bad_args(mjs, "Failed to convert data to hex"); return; @@ -201,10 +196,9 @@ static void js_blebeacon_set_data(struct mjs *mjs) { mjs_return(mjs, MJS_UNDEFINED); } -static void js_blebeacon_generate_mac(struct mjs *mjs) -{ +static void js_blebeacon_generate_mac(struct mjs* mjs) { char* company = ""; - if (!get_str_arg(mjs, 0, &company)) return; + if(!get_str_arg(mjs, 0, &company)) return; char* mac = generate_mac_address(company); @@ -213,17 +207,16 @@ static void js_blebeacon_generate_mac(struct mjs *mjs) return mjs_return(mjs, js_mac_address); } -static void js_blebeacon_set_mac(struct mjs *mjs) { +static void js_blebeacon_set_mac(struct mjs* mjs) { FURI_LOG_D("BLE", "Setting Mac"); - if (!check_arg_count(mjs, 1)) - { + if(!check_arg_count(mjs, 1)) { ret_bad_args(mjs, "Bad args"); return; } - + JSblebeaconInst* inst = get_this_ctx(mjs); char* mac_addr = ""; - if (!get_str_arg(mjs, 0, &mac_addr)) return; + if(!get_str_arg(mjs, 0, &mac_addr)) return; inst->mac_addr = mac_addr; inst->beacon_config.min_adv_interval_ms = 50; inst->beacon_config.max_adv_interval_ms = 150; @@ -234,7 +227,7 @@ static void js_blebeacon_set_mac(struct mjs *mjs) { inst->beacon_config.address_type = GapAddressTypePublic; uint8_t* mac = macstr_to_uint8(mac_addr); - if (mac) { + if(mac) { memcpy(inst->beacon_config.address, mac, 6); furi_hal_bt_extra_beacon_set_config(&inst->beacon_config); mjs_return(mjs, MJS_UNDEFINED); @@ -245,21 +238,19 @@ static void js_blebeacon_set_mac(struct mjs *mjs) { } } -static void js_blebeacon_send(struct mjs *mjs) { - +static void js_blebeacon_send(struct mjs* mjs) { furi_hal_bt_extra_beacon_start(); mjs_return(mjs, MJS_UNDEFINED); } -static void js_blebeacon_stop(struct mjs *mjs) { - +static void js_blebeacon_stop(struct mjs* mjs) { furi_hal_bt_extra_beacon_stop(); mjs_return(mjs, MJS_UNDEFINED); } -static void* js_blebeacon_create(struct mjs *mjs, mjs_val_t* object) { +static void* js_blebeacon_create(struct mjs* mjs, mjs_val_t* object) { JSblebeaconInst* inst = 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, inst)); @@ -272,9 +263,9 @@ static void* js_blebeacon_create(struct mjs *mjs, mjs_val_t* object) { return inst; } -static void js_blebeacon_destroy(void *ptr) { +static void js_blebeacon_destroy(void* ptr) { JSblebeaconInst* inst = (JSblebeaconInst*)ptr; - if (inst) { + if(inst) { free(inst->data); free(inst->mac_addr); free(inst); diff --git a/applications/system/js_app/modules/js_keyboard.c b/applications/system/js_app/modules/js_keyboard.c index 1988fda25..d4e9fcba1 100644 --- a/applications/system/js_app/modules/js_keyboard.c +++ b/applications/system/js_app/modules/js_keyboard.c @@ -20,7 +20,7 @@ static void ret_bad_args(struct mjs* mjs, const char* error) { char nibble_to_hex_character(uint8_t nibble) { nibble &= 0xF; - if (nibble < 10) { + if(nibble < 10) { return '0' + nibble; } else { return 'A' + (nibble - 10); @@ -29,12 +29,12 @@ char nibble_to_hex_character(uint8_t nibble) { char* bytes_to_hex_string(uint8_t* bytes, size_t num_bytes) { char* hex_string = (char*)malloc(num_bytes * 2 + 1); - if (hex_string == NULL) { + if(hex_string == NULL) { FURI_LOG_D("LOG", "Memory allocation failed\n"); return NULL; } - for (size_t i = 0; i < num_bytes; ++i) { + for(size_t i = 0; i < num_bytes; ++i) { hex_string[i * 2] = nibble_to_hex_character(bytes[i] >> 4); hex_string[i * 2 + 1] = nibble_to_hex_character(bytes[i] & 0xF); } @@ -74,20 +74,17 @@ static JSkeyboardInst* get_this_ctx(struct mjs* mjs) { return storage; } -void text_input_callback(void* context) -{ +void text_input_callback(void* context) { JSkeyboardInst* keyboardinst = (JSkeyboardInst*)context; view_dispatcher_stop(keyboardinst->view_dispatcher); } -void byte_input_callback(void* context) -{ +void byte_input_callback(void* context) { JSkeyboardInst* keyboardinst = (JSkeyboardInst*)context; view_dispatcher_stop(keyboardinst->view_dispatcher); } -static void js_keyboard_text(struct mjs *mjs) { - +static void js_keyboard_text(struct mjs* mjs) { JSkeyboardInst* keyboardinst = get_this_ctx(mjs); int MaxInputLength; @@ -100,18 +97,24 @@ static void js_keyboard_text(struct mjs *mjs) { mjs_val_t bool_obj = mjs_arg(mjs, 2); ShouldSelect = (int)mjs_get_bool(mjs, bool_obj); - if (keyboardinst->textinput && keyboardinst->view_dispatcher) - { - if (strlen(defaultText) > 0) - { + if(keyboardinst->textinput && keyboardinst->view_dispatcher) { + if(strlen(defaultText) > 0) { text_input_set_header_text(keyboardinst->textinput, defaultText); } view_dispatcher_attach_to_gui( - keyboardinst->view_dispatcher, furi_record_open(RECORD_GUI), ViewDispatcherTypeFullscreen); + keyboardinst->view_dispatcher, + furi_record_open(RECORD_GUI), + ViewDispatcherTypeFullscreen); furi_record_close(RECORD_GUI); - text_input_set_result_callback(keyboardinst->textinput, text_input_callback, keyboardinst, keyboardinst->data, MaxInputLength, ShouldSelect); + text_input_set_result_callback( + keyboardinst->textinput, + text_input_callback, + keyboardinst, + keyboardinst->data, + MaxInputLength, + ShouldSelect); view_dispatcher_switch_to_view(keyboardinst->view_dispatcher, 0); @@ -123,10 +126,7 @@ static void js_keyboard_text(struct mjs *mjs) { mjs_return(mjs, mjs_mk_string(mjs, keyboardinst->data, strlen(keyboardinst->data), 1)); } -static void js_keyboard_byte(struct mjs *mjs) { - - - +static void js_keyboard_byte(struct mjs* mjs) { JSkeyboardInst* keyboardinst = get_this_ctx(mjs); int MaxInputLength; @@ -135,18 +135,24 @@ static void js_keyboard_byte(struct mjs *mjs) { const char* defaultText; get_str_arg(mjs, 1, &defaultText); - if (keyboardinst->byteinputview && keyboardinst->view_dispatcher) - { - if (strlen(defaultText) > 0) - { + if(keyboardinst->byteinputview && keyboardinst->view_dispatcher) { + if(strlen(defaultText) > 0) { byte_input_set_header_text(keyboardinst->byteinputview, defaultText); } view_dispatcher_attach_to_gui( - keyboardinst->view_dispatcher, furi_record_open(RECORD_GUI), ViewDispatcherTypeFullscreen); + keyboardinst->view_dispatcher, + furi_record_open(RECORD_GUI), + ViewDispatcherTypeFullscreen); furi_record_close(RECORD_GUI); - byte_input_set_result_callback(keyboardinst->byteinputview, byte_input_callback, NULL, keyboardinst, keyboardinst->byteinput, 10); + byte_input_set_result_callback( + keyboardinst->byteinputview, + byte_input_callback, + NULL, + keyboardinst, + keyboardinst->byteinput, + 10); view_dispatcher_switch_to_view(keyboardinst->view_dispatcher, 1); @@ -160,7 +166,6 @@ static void js_keyboard_byte(struct mjs *mjs) { FURI_LOG_D("SHIT", "DID THING 2"); } - static void* js_keyboard_create(struct mjs* mjs, mjs_val_t* object) { JSkeyboardInst* keyboardinst = malloc(sizeof(JSkeyboardInst)); mjs_val_t keyboard_obj = mjs_mk_object(mjs); @@ -173,8 +178,10 @@ static void* js_keyboard_create(struct mjs* mjs, mjs_val_t* object) { keyboardinst->data = malloc(100); keyboardinst->byteinput = malloc(100); view_dispatcher_enable_queue(keyboardinst->view_dispatcher); - view_dispatcher_add_view(keyboardinst->view_dispatcher, 0, text_input_get_view(keyboardinst->textinput)); - view_dispatcher_add_view(keyboardinst->view_dispatcher, 1, byte_input_get_view(keyboardinst->byteinputview)); + view_dispatcher_add_view( + keyboardinst->view_dispatcher, 0, text_input_get_view(keyboardinst->textinput)); + view_dispatcher_add_view( + keyboardinst->view_dispatcher, 1, byte_input_get_view(keyboardinst->byteinputview)); *object = keyboard_obj; return keyboardinst; } diff --git a/applications/system/js_app/modules/js_math.c b/applications/system/js_app/modules/js_math.c index d17b72b88..5e78fc661 100644 --- a/applications/system/js_app/modules/js_math.c +++ b/applications/system/js_app/modules/js_math.c @@ -19,7 +19,7 @@ static bool check_arg_count(struct mjs* mjs, size_t count) { } void mjs_abs(struct mjs* mjs) { - if (!check_arg_count(mjs, 1) || !mjs_is_number(mjs_arg(mjs, 0))) { + if(!check_arg_count(mjs, 1) || !mjs_is_number(mjs_arg(mjs, 0))) { mjs_return(mjs, MJS_UNDEFINED); } double x = mjs_get_double(mjs, mjs_arg(mjs, 0)); @@ -27,11 +27,11 @@ void mjs_abs(struct mjs* mjs) { } void mjs_acos(struct mjs* mjs) { - if (!check_arg_count(mjs, 1) || !mjs_is_number(mjs_arg(mjs, 0))) { + if(!check_arg_count(mjs, 1) || !mjs_is_number(mjs_arg(mjs, 0))) { mjs_return(mjs, MJS_UNDEFINED); } double x = mjs_get_double(mjs, mjs_arg(mjs, 0)); - if (x < -1 || x > 1) { + if(x < -1 || x > 1) { ret_bad_args(mjs, "Invalid input value for Math.acos"); mjs_return(mjs, MJS_UNDEFINED); } @@ -39,11 +39,11 @@ void mjs_acos(struct mjs* mjs) { } void mjs_acosh(struct mjs* mjs) { - if (!check_arg_count(mjs, 1) || !mjs_is_number(mjs_arg(mjs, 0))) { + if(!check_arg_count(mjs, 1) || !mjs_is_number(mjs_arg(mjs, 0))) { mjs_return(mjs, MJS_UNDEFINED); } double x = mjs_get_double(mjs, mjs_arg(mjs, 0)); - if (x < 1) { + if(x < 1) { ret_bad_args(mjs, "Invalid input value for Math.acosh"); mjs_return(mjs, MJS_UNDEFINED); } @@ -51,7 +51,7 @@ void mjs_acosh(struct mjs* mjs) { } void mjs_asin(struct mjs* mjs) { - if (!check_arg_count(mjs, 1) || !mjs_is_number(mjs_arg(mjs, 0))) { + if(!check_arg_count(mjs, 1) || !mjs_is_number(mjs_arg(mjs, 0))) { mjs_return(mjs, MJS_UNDEFINED); } double x = mjs_get_double(mjs, mjs_arg(mjs, 0)); @@ -59,7 +59,7 @@ void mjs_asin(struct mjs* mjs) { } void mjs_asinh(struct mjs* mjs) { - if (!check_arg_count(mjs, 1) || !mjs_is_number(mjs_arg(mjs, 0))) { + if(!check_arg_count(mjs, 1) || !mjs_is_number(mjs_arg(mjs, 0))) { mjs_return(mjs, MJS_UNDEFINED); } double x = mjs_get_double(mjs, mjs_arg(mjs, 0)); @@ -67,7 +67,7 @@ void mjs_asinh(struct mjs* mjs) { } void mjs_atan(struct mjs* mjs) { - if (!check_arg_count(mjs, 1) || !mjs_is_number(mjs_arg(mjs, 0))) { + if(!check_arg_count(mjs, 1) || !mjs_is_number(mjs_arg(mjs, 0))) { mjs_return(mjs, MJS_UNDEFINED); } double x = mjs_get_double(mjs, mjs_arg(mjs, 0)); @@ -75,7 +75,8 @@ void mjs_atan(struct mjs* mjs) { } void mjs_atan2(struct mjs* mjs) { - if (!check_arg_count(mjs, 2) || !mjs_is_number(mjs_arg(mjs, 0)) || !mjs_is_number(mjs_arg(mjs, 1))) { + if(!check_arg_count(mjs, 2) || !mjs_is_number(mjs_arg(mjs, 0)) || + !mjs_is_number(mjs_arg(mjs, 1))) { mjs_return(mjs, MJS_UNDEFINED); } double y = mjs_get_double(mjs, mjs_arg(mjs, 0)); @@ -84,11 +85,11 @@ void mjs_atan2(struct mjs* mjs) { } void mjs_atanh(struct mjs* mjs) { - if (!check_arg_count(mjs, 1) || !mjs_is_number(mjs_arg(mjs, 0))) { + if(!check_arg_count(mjs, 1) || !mjs_is_number(mjs_arg(mjs, 0))) { mjs_return(mjs, MJS_UNDEFINED); } double x = mjs_get_double(mjs, mjs_arg(mjs, 0)); - if (x <= -1 || x >= 1) { + if(x <= -1 || x >= 1) { ret_bad_args(mjs, "Invalid input value for Math.atanh"); mjs_return(mjs, MJS_UNDEFINED); } @@ -96,7 +97,7 @@ void mjs_atanh(struct mjs* mjs) { } void mjs_cbrt(struct mjs* mjs) { - if (!check_arg_count(mjs, 1) || !mjs_is_number(mjs_arg(mjs, 0))) { + if(!check_arg_count(mjs, 1) || !mjs_is_number(mjs_arg(mjs, 0))) { mjs_return(mjs, MJS_UNDEFINED); } double x = mjs_get_double(mjs, mjs_arg(mjs, 0)); @@ -104,7 +105,7 @@ void mjs_cbrt(struct mjs* mjs) { } void mjs_ceil(struct mjs* mjs) { - if (!check_arg_count(mjs, 1) || !mjs_is_number(mjs_arg(mjs, 0))) { + if(!check_arg_count(mjs, 1) || !mjs_is_number(mjs_arg(mjs, 0))) { mjs_return(mjs, MJS_UNDEFINED); } double x = mjs_get_double(mjs, mjs_arg(mjs, 0)); @@ -112,12 +113,12 @@ void mjs_ceil(struct mjs* mjs) { } void mjs_clz32(struct mjs* mjs) { - if (!check_arg_count(mjs, 1) || !mjs_is_number(mjs_arg(mjs, 0))) { + if(!check_arg_count(mjs, 1) || !mjs_is_number(mjs_arg(mjs, 0))) { mjs_return(mjs, MJS_UNDEFINED); } unsigned int x = (unsigned int)mjs_get_int(mjs, mjs_arg(mjs, 0)); int count = 0; - while (x) { + while(x) { x >>= 1; count++; } @@ -125,7 +126,7 @@ void mjs_clz32(struct mjs* mjs) { } void mjs_cos(struct mjs* mjs) { - if (!check_arg_count(mjs, 1) || !mjs_is_number(mjs_arg(mjs, 0))) { + if(!check_arg_count(mjs, 1) || !mjs_is_number(mjs_arg(mjs, 0))) { mjs_return(mjs, MJS_UNDEFINED); } double x = mjs_get_double(mjs, mjs_arg(mjs, 0)); @@ -133,13 +134,13 @@ void mjs_cos(struct mjs* mjs) { } void mjs_exp(struct mjs* mjs) { - if (!check_arg_count(mjs, 1) || !mjs_is_number(mjs_arg(mjs, 0))) { + if(!check_arg_count(mjs, 1) || !mjs_is_number(mjs_arg(mjs, 0))) { mjs_return(mjs, MJS_UNDEFINED); } double x = mjs_get_double(mjs, mjs_arg(mjs, 0)); double result = 1; double term = 1; - for (int i = 1; i < 100; i++) { + for(int i = 1; i < 100; i++) { term *= x / i; result += term; } @@ -147,7 +148,7 @@ void mjs_exp(struct mjs* mjs) { } void mjs_floor(struct mjs* mjs) { - if (!check_arg_count(mjs, 1) || !mjs_is_number(mjs_arg(mjs, 0))) { + if(!check_arg_count(mjs, 1) || !mjs_is_number(mjs_arg(mjs, 0))) { mjs_return(mjs, MJS_UNDEFINED); } double x = mjs_get_double(mjs, mjs_arg(mjs, 0)); @@ -155,16 +156,16 @@ void mjs_floor(struct mjs* mjs) { } void mjs_log(struct mjs* mjs) { - if (!check_arg_count(mjs, 1) || !mjs_is_number(mjs_arg(mjs, 0))) { + if(!check_arg_count(mjs, 1) || !mjs_is_number(mjs_arg(mjs, 0))) { mjs_return(mjs, MJS_UNDEFINED); } double x = mjs_get_double(mjs, mjs_arg(mjs, 0)); - if (x <= 0) { + if(x <= 0) { ret_bad_args(mjs, "Invalid input value for Math.log"); mjs_return(mjs, MJS_UNDEFINED); } double result = 0; - while (x >= MJS_E) { + while(x >= MJS_E) { x /= MJS_E; result++; } @@ -172,7 +173,8 @@ void mjs_log(struct mjs* mjs) { } void mjs_max(struct mjs* mjs) { - if (!check_arg_count(mjs, 2) || !mjs_is_number(mjs_arg(mjs, 0)) || !mjs_is_number(mjs_arg(mjs, 1))) { + if(!check_arg_count(mjs, 2) || !mjs_is_number(mjs_arg(mjs, 0)) || + !mjs_is_number(mjs_arg(mjs, 1))) { mjs_return(mjs, MJS_UNDEFINED); } double x = mjs_get_double(mjs, mjs_arg(mjs, 0)); @@ -181,7 +183,8 @@ void mjs_max(struct mjs* mjs) { } void mjs_min(struct mjs* mjs) { - if (!check_arg_count(mjs, 2) || !mjs_is_number(mjs_arg(mjs, 0)) || !mjs_is_number(mjs_arg(mjs, 1))) { + if(!check_arg_count(mjs, 2) || !mjs_is_number(mjs_arg(mjs, 0)) || + !mjs_is_number(mjs_arg(mjs, 1))) { mjs_return(mjs, MJS_UNDEFINED); } double x = mjs_get_double(mjs, mjs_arg(mjs, 0)); @@ -190,20 +193,21 @@ void mjs_min(struct mjs* mjs) { } void mjs_pow(struct mjs* mjs) { - if (!check_arg_count(mjs, 2) || !mjs_is_number(mjs_arg(mjs, 0)) || !mjs_is_number(mjs_arg(mjs, 1))) { + if(!check_arg_count(mjs, 2) || !mjs_is_number(mjs_arg(mjs, 0)) || + !mjs_is_number(mjs_arg(mjs, 1))) { mjs_return(mjs, MJS_UNDEFINED); } double base = mjs_get_double(mjs, mjs_arg(mjs, 0)); double exponent = mjs_get_double(mjs, mjs_arg(mjs, 1)); double result = 1; - for (int i = 0; i < exponent; i++) { + for(int i = 0; i < exponent; i++) { result *= base; } mjs_return(mjs, mjs_mk_number(mjs, result)); } void mjs_random(struct mjs* mjs) { - if (!check_arg_count(mjs, 0)) { + if(!check_arg_count(mjs, 0)) { mjs_return(mjs, MJS_UNDEFINED); } const uint32_t random_val = furi_hal_random_get(); @@ -212,7 +216,7 @@ void mjs_random(struct mjs* mjs) { } void mjs_sign(struct mjs* mjs) { - if (!check_arg_count(mjs, 1) || !mjs_is_number(mjs_arg(mjs, 0))) { + if(!check_arg_count(mjs, 1) || !mjs_is_number(mjs_arg(mjs, 0))) { mjs_return(mjs, MJS_UNDEFINED); } double x = mjs_get_double(mjs, mjs_arg(mjs, 0)); @@ -220,13 +224,13 @@ void mjs_sign(struct mjs* mjs) { } void mjs_sin(struct mjs* mjs) { - if (!check_arg_count(mjs, 1) || !mjs_is_number(mjs_arg(mjs, 0))) { + if(!check_arg_count(mjs, 1) || !mjs_is_number(mjs_arg(mjs, 0))) { mjs_return(mjs, MJS_UNDEFINED); } double x = mjs_get_double(mjs, mjs_arg(mjs, 0)); double result = x; double term = x; - for (int i = 1; i < 10; i++) { + for(int i = 1; i < 10; i++) { term *= -x * x / ((2 * i) * (2 * i + 1)); result += term; } @@ -234,31 +238,30 @@ void mjs_sin(struct mjs* mjs) { } void mjs_sqrt(struct mjs* mjs) { - if (!check_arg_count(mjs, 1) || !mjs_is_number(mjs_arg(mjs, 0))) { + if(!check_arg_count(mjs, 1) || !mjs_is_number(mjs_arg(mjs, 0))) { mjs_return(mjs, MJS_UNDEFINED); } double x = mjs_get_double(mjs, mjs_arg(mjs, 0)); - if (x < 0) { + if(x < 0) { ret_bad_args(mjs, "Invalid input value for Math.sqrt"); mjs_return(mjs, MJS_UNDEFINED); } double result = 1; - while (result * result < x) { + while(result * result < x) { result += (double)0.001; } mjs_return(mjs, mjs_mk_number(mjs, result)); } void mjs_trunc(struct mjs* mjs) { - if (!check_arg_count(mjs, 1) || !mjs_is_number(mjs_arg(mjs, 0))) { + if(!check_arg_count(mjs, 1) || !mjs_is_number(mjs_arg(mjs, 0))) { mjs_return(mjs, MJS_UNDEFINED); } double x = mjs_get_double(mjs, mjs_arg(mjs, 0)); mjs_return(mjs, mjs_mk_number(mjs, x < 0 ? ceil(x) : floor(x))); } - -static void* js_math_create(struct mjs *mjs, mjs_val_t* object) { +static void* js_math_create(struct mjs* mjs, mjs_val_t* object) { mjs_val_t math_obj = mjs_mk_object(mjs); mjs_set(mjs, math_obj, "abs", ~0, MJS_MK_FN(mjs_abs)); mjs_set(mjs, math_obj, "acos", ~0, MJS_MK_FN(mjs_acos)); @@ -286,9 +289,9 @@ static void* js_math_create(struct mjs *mjs, mjs_val_t* object) { mjs_set(mjs, math_obj, "PI", ~0, mjs_mk_number(mjs, MJS_PI)); *object = math_obj; return object; -} +} -static void js_math_destroy(void *ptr) { +static void js_math_destroy(void* ptr) { UNUSED(ptr); } From be014b5103cf03371e789608fb1483ed793e94fd Mon Sep 17 00:00:00 2001 From: Willy-JL <49810075+Willy-JL@users.noreply.github.com> Date: Thu, 7 Mar 2024 05:15:01 +0000 Subject: [PATCH 08/16] Small JS bindings tweaks - no destroy for math - tweak example print results - namespace naming consistency --- .../js_app/examples/apps/Scripts/keyboard.js | 2 +- .../js_app/examples/apps/Scripts/submenu.js | 2 +- .../system/js_app/modules/js_blebeacon.c | 18 +-- .../system/js_app/modules/js_keyboard.c | 23 ++-- applications/system/js_app/modules/js_math.c | 116 +++++++++--------- 5 files changed, 78 insertions(+), 83 deletions(-) diff --git a/applications/system/js_app/examples/apps/Scripts/keyboard.js b/applications/system/js_app/examples/apps/Scripts/keyboard.js index 6e7b8332a..ddcb40a61 100644 --- a/applications/system/js_app/examples/apps/Scripts/keyboard.js +++ b/applications/system/js_app/examples/apps/Scripts/keyboard.js @@ -2,4 +2,4 @@ let keyboard = require("keyboard"); let text = keyboard.text(100, "Please Input Shit", 1); -print(text); \ No newline at end of file +print("Got text:", text); \ No newline at end of file diff --git a/applications/system/js_app/examples/apps/Scripts/submenu.js b/applications/system/js_app/examples/apps/Scripts/submenu.js index 4c0cd79d0..6744ca452 100644 --- a/applications/system/js_app/examples/apps/Scripts/submenu.js +++ b/applications/system/js_app/examples/apps/Scripts/submenu.js @@ -8,4 +8,4 @@ submenu.setHeader("Select an option:"); let result = submenu.show(); -print("Result: ", result); +print("Result:", result); diff --git a/applications/system/js_app/modules/js_blebeacon.c b/applications/system/js_app/modules/js_blebeacon.c index 0e77e5648..946a99bab 100644 --- a/applications/system/js_app/modules/js_blebeacon.c +++ b/applications/system/js_app/modules/js_blebeacon.c @@ -7,7 +7,7 @@ typedef struct { char* mac_addr; size_t beacon_data_len; GapExtraBeaconConfig beacon_config; -} JSblebeaconInst; +} JsBlebeaconInst; struct OUI_MAP_ENTRY { const char* brand; @@ -78,9 +78,9 @@ static char* generate_mac_address(const char* brand) { return mac_address; } -static JSblebeaconInst* get_this_ctx(struct mjs* mjs) { +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); + JsBlebeaconInst* storage = mjs_get_ptr(mjs, obj_inst); furi_assert(storage); return storage; } @@ -167,7 +167,7 @@ static uint8_t* hexstr_to_uint8(const char* hexstr, size_t* out_length) { static void js_blebeacon_set_data(struct mjs* mjs) { FURI_LOG_D("BLE", "Setting data"); if(!check_arg_count(mjs, 1)) return; - JSblebeaconInst* inst = get_this_ctx(mjs); + JsBlebeaconInst* inst = get_this_ctx(mjs); if(!inst) { FURI_LOG_D("BLE", "Beacon instance is null"); ret_bad_args(mjs, "Beacon instance is null"); @@ -214,7 +214,7 @@ static void js_blebeacon_set_mac(struct mjs* mjs) { return; } - JSblebeaconInst* inst = get_this_ctx(mjs); + JsBlebeaconInst* inst = get_this_ctx(mjs); char* mac_addr = ""; if(!get_str_arg(mjs, 0, &mac_addr)) return; inst->mac_addr = mac_addr; @@ -251,7 +251,7 @@ static void js_blebeacon_stop(struct mjs* mjs) { } static void* js_blebeacon_create(struct mjs* mjs, mjs_val_t* object) { - JSblebeaconInst* inst = malloc(sizeof(JSblebeaconInst)); + JsBlebeaconInst* inst = 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, inst)); mjs_set(mjs, blebeacon_obj, "setData", ~0, MJS_MK_FN(js_blebeacon_set_data)); @@ -264,7 +264,7 @@ static void* js_blebeacon_create(struct mjs* mjs, mjs_val_t* object) { } static void js_blebeacon_destroy(void* ptr) { - JSblebeaconInst* inst = (JSblebeaconInst*)ptr; + JsBlebeaconInst* inst = (JsBlebeaconInst*)ptr; if(inst) { free(inst->data); free(inst->mac_addr); @@ -278,12 +278,12 @@ static const JsModuleDescriptor js_blebeacon_desc = { js_blebeacon_destroy, }; -static const FlipperAppPluginDescriptor blebeacon_plugin_descriptor = { +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 &blebeacon_plugin_descriptor; + return &plugin_descriptor; } \ No newline at end of file diff --git a/applications/system/js_app/modules/js_keyboard.c b/applications/system/js_app/modules/js_keyboard.c index d4e9fcba1..e120ee0d6 100644 --- a/applications/system/js_app/modules/js_keyboard.c +++ b/applications/system/js_app/modules/js_keyboard.c @@ -11,7 +11,7 @@ typedef struct { ByteInput* byteinputview; ViewDispatcher* view_dispatcher; uint8_t* byteinput; -} JSkeyboardInst; +} JsKeyboardInst; static void ret_bad_args(struct mjs* mjs, const char* error) { mjs_prepend_errorf(mjs, MJS_BAD_ARGS_ERROR, "%s", error); @@ -67,25 +67,25 @@ static bool get_int_arg(struct mjs* mjs, size_t index, int* value) { return true; } -static JSkeyboardInst* get_this_ctx(struct mjs* mjs) { +static JsKeyboardInst* get_this_ctx(struct mjs* mjs) { mjs_val_t obj_inst = mjs_get(mjs, mjs_get_this(mjs), INST_PROP_NAME, ~0); - JSkeyboardInst* storage = mjs_get_ptr(mjs, obj_inst); + JsKeyboardInst* storage = mjs_get_ptr(mjs, obj_inst); furi_assert(storage); return storage; } void text_input_callback(void* context) { - JSkeyboardInst* keyboardinst = (JSkeyboardInst*)context; + JsKeyboardInst* keyboardinst = (JsKeyboardInst*)context; view_dispatcher_stop(keyboardinst->view_dispatcher); } void byte_input_callback(void* context) { - JSkeyboardInst* keyboardinst = (JSkeyboardInst*)context; + JsKeyboardInst* keyboardinst = (JsKeyboardInst*)context; view_dispatcher_stop(keyboardinst->view_dispatcher); } static void js_keyboard_text(struct mjs* mjs) { - JSkeyboardInst* keyboardinst = get_this_ctx(mjs); + JsKeyboardInst* keyboardinst = get_this_ctx(mjs); int MaxInputLength; if(!get_int_arg(mjs, 0, &MaxInputLength)) return; @@ -127,7 +127,7 @@ static void js_keyboard_text(struct mjs* mjs) { } static void js_keyboard_byte(struct mjs* mjs) { - JSkeyboardInst* keyboardinst = get_this_ctx(mjs); + JsKeyboardInst* keyboardinst = get_this_ctx(mjs); int MaxInputLength; if(!get_int_arg(mjs, 0, &MaxInputLength)) return; @@ -167,7 +167,7 @@ static void js_keyboard_byte(struct mjs* mjs) { } static void* js_keyboard_create(struct mjs* mjs, mjs_val_t* object) { - JSkeyboardInst* keyboardinst = malloc(sizeof(JSkeyboardInst)); + JsKeyboardInst* keyboardinst = malloc(sizeof(JsKeyboardInst)); mjs_val_t keyboard_obj = mjs_mk_object(mjs); mjs_set(mjs, keyboard_obj, INST_PROP_NAME, ~0, mjs_mk_foreign(mjs, keyboardinst)); mjs_set(mjs, keyboard_obj, "text", ~0, MJS_MK_FN(js_keyboard_text)); @@ -187,7 +187,7 @@ static void* js_keyboard_create(struct mjs* mjs, mjs_val_t* object) { } static void js_keyboard_destroy(void* inst) { - JSkeyboardInst* insts = (JSkeyboardInst*)inst; + JsKeyboardInst* insts = (JsKeyboardInst*)inst; byte_input_free(insts->byteinputview); text_input_free(insts->textinput); view_dispatcher_free(insts->view_dispatcher); @@ -201,13 +201,12 @@ static const JsModuleDescriptor js_keyboard_desc = { js_keyboard_destroy, }; -static const FlipperAppPluginDescriptor keyboard_plugin_descriptor = { +static const FlipperAppPluginDescriptor plugin_descriptor = { .appid = PLUGIN_APP_ID, .ep_api_version = PLUGIN_API_VERSION, .entry_point = &js_keyboard_desc, }; const FlipperAppPluginDescriptor* js_keyboard_ep(void) { - UNUSED(js_keyboard_byte); - return &keyboard_plugin_descriptor; + return &plugin_descriptor; } \ No newline at end of file diff --git a/applications/system/js_app/modules/js_math.c b/applications/system/js_app/modules/js_math.c index 5e78fc661..2af989908 100644 --- a/applications/system/js_app/modules/js_math.c +++ b/applications/system/js_app/modules/js_math.c @@ -1,8 +1,8 @@ #include "../js_modules.h" #include "furi_hal_random.h" -#define MJS_PI (double)3.14159265358979323846 -#define MJS_E (double)2.7182818284590452354 +#define JS_MATH_PI (double)3.14159265358979323846 +#define JS_MATH_E (double)2.7182818284590452354 static void ret_bad_args(struct mjs* mjs, const char* error) { mjs_prepend_errorf(mjs, MJS_BAD_ARGS_ERROR, "%s", error); @@ -18,7 +18,7 @@ static bool check_arg_count(struct mjs* mjs, size_t count) { return true; } -void mjs_abs(struct mjs* mjs) { +void js_math_abs(struct mjs* mjs) { if(!check_arg_count(mjs, 1) || !mjs_is_number(mjs_arg(mjs, 0))) { mjs_return(mjs, MJS_UNDEFINED); } @@ -26,7 +26,7 @@ void mjs_abs(struct mjs* mjs) { mjs_return(mjs, x < 0 ? mjs_mk_number(mjs, -x) : mjs_arg(mjs, 0)); } -void mjs_acos(struct mjs* mjs) { +void js_math_acos(struct mjs* mjs) { if(!check_arg_count(mjs, 1) || !mjs_is_number(mjs_arg(mjs, 0))) { mjs_return(mjs, MJS_UNDEFINED); } @@ -35,10 +35,10 @@ void mjs_acos(struct mjs* mjs) { ret_bad_args(mjs, "Invalid input value for Math.acos"); mjs_return(mjs, MJS_UNDEFINED); } - mjs_return(mjs, mjs_mk_number(mjs, MJS_PI / (double)2 - atan(x / sqrt(1 - x * x)))); + mjs_return(mjs, mjs_mk_number(mjs, JS_MATH_PI / (double)2 - atan(x / sqrt(1 - x * x)))); } -void mjs_acosh(struct mjs* mjs) { +void js_math_acosh(struct mjs* mjs) { if(!check_arg_count(mjs, 1) || !mjs_is_number(mjs_arg(mjs, 0))) { mjs_return(mjs, MJS_UNDEFINED); } @@ -50,7 +50,7 @@ void mjs_acosh(struct mjs* mjs) { mjs_return(mjs, mjs_mk_number(mjs, log(x + sqrt(x * x - 1)))); } -void mjs_asin(struct mjs* mjs) { +void js_math_asin(struct mjs* mjs) { if(!check_arg_count(mjs, 1) || !mjs_is_number(mjs_arg(mjs, 0))) { mjs_return(mjs, MJS_UNDEFINED); } @@ -58,7 +58,7 @@ void mjs_asin(struct mjs* mjs) { mjs_return(mjs, mjs_mk_number(mjs, atan(x / sqrt(1 - x * x)))); } -void mjs_asinh(struct mjs* mjs) { +void js_math_asinh(struct mjs* mjs) { if(!check_arg_count(mjs, 1) || !mjs_is_number(mjs_arg(mjs, 0))) { mjs_return(mjs, MJS_UNDEFINED); } @@ -66,7 +66,7 @@ void mjs_asinh(struct mjs* mjs) { mjs_return(mjs, mjs_mk_number(mjs, log(x + sqrt(x * x + 1)))); } -void mjs_atan(struct mjs* mjs) { +void js_math_atan(struct mjs* mjs) { if(!check_arg_count(mjs, 1) || !mjs_is_number(mjs_arg(mjs, 0))) { mjs_return(mjs, MJS_UNDEFINED); } @@ -74,7 +74,7 @@ void mjs_atan(struct mjs* mjs) { mjs_return(mjs, mjs_mk_number(mjs, atan(x))); } -void mjs_atan2(struct mjs* mjs) { +void js_math_atan2(struct mjs* mjs) { if(!check_arg_count(mjs, 2) || !mjs_is_number(mjs_arg(mjs, 0)) || !mjs_is_number(mjs_arg(mjs, 1))) { mjs_return(mjs, MJS_UNDEFINED); @@ -84,7 +84,7 @@ void mjs_atan2(struct mjs* mjs) { mjs_return(mjs, mjs_mk_number(mjs, atan2(y, x))); } -void mjs_atanh(struct mjs* mjs) { +void js_math_atanh(struct mjs* mjs) { if(!check_arg_count(mjs, 1) || !mjs_is_number(mjs_arg(mjs, 0))) { mjs_return(mjs, MJS_UNDEFINED); } @@ -96,7 +96,7 @@ void mjs_atanh(struct mjs* mjs) { mjs_return(mjs, mjs_mk_number(mjs, (double)0.5 * log((1 + x) / (1 - x)))); } -void mjs_cbrt(struct mjs* mjs) { +void js_math_cbrt(struct mjs* mjs) { if(!check_arg_count(mjs, 1) || !mjs_is_number(mjs_arg(mjs, 0))) { mjs_return(mjs, MJS_UNDEFINED); } @@ -104,7 +104,7 @@ void mjs_cbrt(struct mjs* mjs) { mjs_return(mjs, mjs_mk_number(mjs, pow(x, 1.0 / 3.0))); } -void mjs_ceil(struct mjs* mjs) { +void js_math_ceil(struct mjs* mjs) { if(!check_arg_count(mjs, 1) || !mjs_is_number(mjs_arg(mjs, 0))) { mjs_return(mjs, MJS_UNDEFINED); } @@ -112,7 +112,7 @@ void mjs_ceil(struct mjs* mjs) { mjs_return(mjs, mjs_mk_number(mjs, (int)(x + (double)0.5))); } -void mjs_clz32(struct mjs* mjs) { +void js_math_clz32(struct mjs* mjs) { if(!check_arg_count(mjs, 1) || !mjs_is_number(mjs_arg(mjs, 0))) { mjs_return(mjs, MJS_UNDEFINED); } @@ -125,7 +125,7 @@ void mjs_clz32(struct mjs* mjs) { mjs_return(mjs, mjs_mk_number(mjs, 32 - count)); } -void mjs_cos(struct mjs* mjs) { +void js_math_cos(struct mjs* mjs) { if(!check_arg_count(mjs, 1) || !mjs_is_number(mjs_arg(mjs, 0))) { mjs_return(mjs, MJS_UNDEFINED); } @@ -133,7 +133,7 @@ void mjs_cos(struct mjs* mjs) { mjs_return(mjs, mjs_mk_number(mjs, cos(x))); } -void mjs_exp(struct mjs* mjs) { +void js_math_exp(struct mjs* mjs) { if(!check_arg_count(mjs, 1) || !mjs_is_number(mjs_arg(mjs, 0))) { mjs_return(mjs, MJS_UNDEFINED); } @@ -147,7 +147,7 @@ void mjs_exp(struct mjs* mjs) { mjs_return(mjs, mjs_mk_number(mjs, result)); } -void mjs_floor(struct mjs* mjs) { +void js_math_floor(struct mjs* mjs) { if(!check_arg_count(mjs, 1) || !mjs_is_number(mjs_arg(mjs, 0))) { mjs_return(mjs, MJS_UNDEFINED); } @@ -155,7 +155,7 @@ void mjs_floor(struct mjs* mjs) { mjs_return(mjs, mjs_mk_number(mjs, (int)x)); } -void mjs_log(struct mjs* mjs) { +void js_math_log(struct mjs* mjs) { if(!check_arg_count(mjs, 1) || !mjs_is_number(mjs_arg(mjs, 0))) { mjs_return(mjs, MJS_UNDEFINED); } @@ -165,14 +165,14 @@ void mjs_log(struct mjs* mjs) { mjs_return(mjs, MJS_UNDEFINED); } double result = 0; - while(x >= MJS_E) { - x /= MJS_E; + while(x >= JS_MATH_E) { + x /= JS_MATH_E; result++; } mjs_return(mjs, mjs_mk_number(mjs, result + log(x))); } -void mjs_max(struct mjs* mjs) { +void js_math_max(struct mjs* mjs) { if(!check_arg_count(mjs, 2) || !mjs_is_number(mjs_arg(mjs, 0)) || !mjs_is_number(mjs_arg(mjs, 1))) { mjs_return(mjs, MJS_UNDEFINED); @@ -182,7 +182,7 @@ void mjs_max(struct mjs* mjs) { mjs_return(mjs, mjs_mk_number(mjs, x > y ? x : y)); } -void mjs_min(struct mjs* mjs) { +void js_math_min(struct mjs* mjs) { if(!check_arg_count(mjs, 2) || !mjs_is_number(mjs_arg(mjs, 0)) || !mjs_is_number(mjs_arg(mjs, 1))) { mjs_return(mjs, MJS_UNDEFINED); @@ -192,7 +192,7 @@ void mjs_min(struct mjs* mjs) { mjs_return(mjs, mjs_mk_number(mjs, x < y ? x : y)); } -void mjs_pow(struct mjs* mjs) { +void js_math_pow(struct mjs* mjs) { if(!check_arg_count(mjs, 2) || !mjs_is_number(mjs_arg(mjs, 0)) || !mjs_is_number(mjs_arg(mjs, 1))) { mjs_return(mjs, MJS_UNDEFINED); @@ -206,7 +206,7 @@ void mjs_pow(struct mjs* mjs) { mjs_return(mjs, mjs_mk_number(mjs, result)); } -void mjs_random(struct mjs* mjs) { +void js_math_random(struct mjs* mjs) { if(!check_arg_count(mjs, 0)) { mjs_return(mjs, MJS_UNDEFINED); } @@ -215,7 +215,7 @@ void mjs_random(struct mjs* mjs) { mjs_return(mjs, mjs_mk_number(mjs, rnd)); } -void mjs_sign(struct mjs* mjs) { +void js_math_sign(struct mjs* mjs) { if(!check_arg_count(mjs, 1) || !mjs_is_number(mjs_arg(mjs, 0))) { mjs_return(mjs, MJS_UNDEFINED); } @@ -223,7 +223,7 @@ void mjs_sign(struct mjs* mjs) { mjs_return(mjs, mjs_mk_number(mjs, x == 0 ? 0 : (x < 0 ? -1 : 1))); } -void mjs_sin(struct mjs* mjs) { +void js_math_sin(struct mjs* mjs) { if(!check_arg_count(mjs, 1) || !mjs_is_number(mjs_arg(mjs, 0))) { mjs_return(mjs, MJS_UNDEFINED); } @@ -237,7 +237,7 @@ void mjs_sin(struct mjs* mjs) { mjs_return(mjs, mjs_mk_number(mjs, result)); } -void mjs_sqrt(struct mjs* mjs) { +void js_math_sqrt(struct mjs* mjs) { if(!check_arg_count(mjs, 1) || !mjs_is_number(mjs_arg(mjs, 0))) { mjs_return(mjs, MJS_UNDEFINED); } @@ -253,7 +253,7 @@ void mjs_sqrt(struct mjs* mjs) { mjs_return(mjs, mjs_mk_number(mjs, result)); } -void mjs_trunc(struct mjs* mjs) { +void js_math_trunc(struct mjs* mjs) { if(!check_arg_count(mjs, 1) || !mjs_is_number(mjs_arg(mjs, 0))) { mjs_return(mjs, MJS_UNDEFINED); } @@ -263,50 +263,46 @@ void mjs_trunc(struct mjs* mjs) { static void* js_math_create(struct mjs* mjs, mjs_val_t* object) { mjs_val_t math_obj = mjs_mk_object(mjs); - mjs_set(mjs, math_obj, "abs", ~0, MJS_MK_FN(mjs_abs)); - mjs_set(mjs, math_obj, "acos", ~0, MJS_MK_FN(mjs_acos)); - mjs_set(mjs, math_obj, "acosh", ~0, MJS_MK_FN(mjs_acosh)); - mjs_set(mjs, math_obj, "asin", ~0, MJS_MK_FN(mjs_asin)); - mjs_set(mjs, math_obj, "asinh", ~0, MJS_MK_FN(mjs_asinh)); - mjs_set(mjs, math_obj, "atan", ~0, MJS_MK_FN(mjs_atan)); - mjs_set(mjs, math_obj, "atan2", ~0, MJS_MK_FN(mjs_atan2)); - mjs_set(mjs, math_obj, "atanh", ~0, MJS_MK_FN(mjs_atanh)); - mjs_set(mjs, math_obj, "cbrt", ~0, MJS_MK_FN(mjs_cbrt)); - mjs_set(mjs, math_obj, "ceil", ~0, MJS_MK_FN(mjs_ceil)); - mjs_set(mjs, math_obj, "clz32", ~0, MJS_MK_FN(mjs_clz32)); - mjs_set(mjs, math_obj, "cos", ~0, MJS_MK_FN(mjs_cos)); - mjs_set(mjs, math_obj, "exp", ~0, MJS_MK_FN(mjs_exp)); - mjs_set(mjs, math_obj, "floor", ~0, MJS_MK_FN(mjs_floor)); - mjs_set(mjs, math_obj, "log", ~0, MJS_MK_FN(mjs_log)); - mjs_set(mjs, math_obj, "max", ~0, MJS_MK_FN(mjs_max)); - mjs_set(mjs, math_obj, "min", ~0, MJS_MK_FN(mjs_min)); - mjs_set(mjs, math_obj, "pow", ~0, MJS_MK_FN(mjs_pow)); - mjs_set(mjs, math_obj, "random", ~0, MJS_MK_FN(mjs_random)); - mjs_set(mjs, math_obj, "sign", ~0, MJS_MK_FN(mjs_sign)); - mjs_set(mjs, math_obj, "sin", ~0, MJS_MK_FN(mjs_sin)); - mjs_set(mjs, math_obj, "sqrt", ~0, MJS_MK_FN(mjs_sqrt)); - mjs_set(mjs, math_obj, "trunc", ~0, MJS_MK_FN(mjs_trunc)); - mjs_set(mjs, math_obj, "PI", ~0, mjs_mk_number(mjs, MJS_PI)); + mjs_set(mjs, math_obj, "abs", ~0, MJS_MK_FN(js_math_abs)); + mjs_set(mjs, math_obj, "acos", ~0, MJS_MK_FN(js_math_acos)); + mjs_set(mjs, math_obj, "acosh", ~0, MJS_MK_FN(js_math_acosh)); + mjs_set(mjs, math_obj, "asin", ~0, MJS_MK_FN(js_math_asin)); + mjs_set(mjs, math_obj, "asinh", ~0, MJS_MK_FN(js_math_asinh)); + mjs_set(mjs, math_obj, "atan", ~0, MJS_MK_FN(js_math_atan)); + mjs_set(mjs, math_obj, "atan2", ~0, MJS_MK_FN(js_math_atan2)); + mjs_set(mjs, math_obj, "atanh", ~0, MJS_MK_FN(js_math_atanh)); + mjs_set(mjs, math_obj, "cbrt", ~0, MJS_MK_FN(js_math_cbrt)); + mjs_set(mjs, math_obj, "ceil", ~0, MJS_MK_FN(js_math_ceil)); + mjs_set(mjs, math_obj, "clz32", ~0, MJS_MK_FN(js_math_clz32)); + mjs_set(mjs, math_obj, "cos", ~0, MJS_MK_FN(js_math_cos)); + mjs_set(mjs, math_obj, "exp", ~0, MJS_MK_FN(js_math_exp)); + mjs_set(mjs, math_obj, "floor", ~0, MJS_MK_FN(js_math_floor)); + mjs_set(mjs, math_obj, "log", ~0, MJS_MK_FN(js_math_log)); + mjs_set(mjs, math_obj, "max", ~0, MJS_MK_FN(js_math_max)); + mjs_set(mjs, math_obj, "min", ~0, MJS_MK_FN(js_math_min)); + mjs_set(mjs, math_obj, "pow", ~0, MJS_MK_FN(js_math_pow)); + mjs_set(mjs, math_obj, "random", ~0, MJS_MK_FN(js_math_random)); + mjs_set(mjs, math_obj, "sign", ~0, MJS_MK_FN(js_math_sign)); + mjs_set(mjs, math_obj, "sin", ~0, MJS_MK_FN(js_math_sin)); + mjs_set(mjs, math_obj, "sqrt", ~0, MJS_MK_FN(js_math_sqrt)); + mjs_set(mjs, math_obj, "trunc", ~0, MJS_MK_FN(js_math_trunc)); + mjs_set(mjs, math_obj, "PI", ~0, mjs_mk_number(mjs, JS_MATH_PI)); *object = math_obj; - return object; -} - -static void js_math_destroy(void* ptr) { - UNUSED(ptr); + return (void*)1; } static const JsModuleDescriptor js_math_desc = { "math", js_math_create, - js_math_destroy, + NULL, }; -static const FlipperAppPluginDescriptor btkicker_plugin_descriptor = { +static const FlipperAppPluginDescriptor plugin_descriptor = { .appid = PLUGIN_APP_ID, .ep_api_version = PLUGIN_API_VERSION, .entry_point = &js_math_desc, }; const FlipperAppPluginDescriptor* js_math_ep(void) { - return &btkicker_plugin_descriptor; + return &plugin_descriptor; } \ No newline at end of file From 3d6baaef1c345ab23bb65107ee4e7b67dc03230a Mon Sep 17 00:00:00 2001 From: Willy-JL <49810075+Willy-JL@users.noreply.github.com> Date: Thu, 7 Mar 2024 05:16:34 +0000 Subject: [PATCH 09/16] Expose math.E value --- applications/system/js_app/modules/js_math.c | 1 + 1 file changed, 1 insertion(+) diff --git a/applications/system/js_app/modules/js_math.c b/applications/system/js_app/modules/js_math.c index 2af989908..80d97fb9c 100644 --- a/applications/system/js_app/modules/js_math.c +++ b/applications/system/js_app/modules/js_math.c @@ -287,6 +287,7 @@ static void* js_math_create(struct mjs* mjs, mjs_val_t* object) { mjs_set(mjs, math_obj, "sqrt", ~0, MJS_MK_FN(js_math_sqrt)); mjs_set(mjs, math_obj, "trunc", ~0, MJS_MK_FN(js_math_trunc)); mjs_set(mjs, math_obj, "PI", ~0, mjs_mk_number(mjs, JS_MATH_PI)); + mjs_set(mjs, math_obj, "E", ~0, mjs_mk_number(mjs, JS_MATH_E)); *object = math_obj; return (void*)1; } From fcef129698ee0707fbbf7ffc6b6994c73d7e4c6c Mon Sep 17 00:00:00 2001 From: Willy-JL <49810075+Willy-JL@users.noreply.github.com> Date: Thu, 7 Mar 2024 05:21:23 +0000 Subject: [PATCH 10/16] Naming consistency for keyboard --- .../system/js_app/modules/js_keyboard.c | 85 +++++++++---------- 1 file changed, 38 insertions(+), 47 deletions(-) diff --git a/applications/system/js_app/modules/js_keyboard.c b/applications/system/js_app/modules/js_keyboard.c index e120ee0d6..29b5c0714 100644 --- a/applications/system/js_app/modules/js_keyboard.c +++ b/applications/system/js_app/modules/js_keyboard.c @@ -7,8 +7,8 @@ typedef struct { char* data; - TextInput* textinput; - ByteInput* byteinputview; + TextInput* text_input; + ByteInput* byte_input; ViewDispatcher* view_dispatcher; uint8_t* byteinput; } JsKeyboardInst; @@ -75,17 +75,17 @@ static JsKeyboardInst* get_this_ctx(struct mjs* mjs) { } void text_input_callback(void* context) { - JsKeyboardInst* keyboardinst = (JsKeyboardInst*)context; - view_dispatcher_stop(keyboardinst->view_dispatcher); + JsKeyboardInst* keyboard = (JsKeyboardInst*)context; + view_dispatcher_stop(keyboard->view_dispatcher); } void byte_input_callback(void* context) { - JsKeyboardInst* keyboardinst = (JsKeyboardInst*)context; - view_dispatcher_stop(keyboardinst->view_dispatcher); + JsKeyboardInst* keyboard = (JsKeyboardInst*)context; + view_dispatcher_stop(keyboard->view_dispatcher); } static void js_keyboard_text(struct mjs* mjs) { - JsKeyboardInst* keyboardinst = get_this_ctx(mjs); + JsKeyboardInst* keyboard = get_this_ctx(mjs); int MaxInputLength; if(!get_int_arg(mjs, 0, &MaxInputLength)) return; @@ -97,37 +97,35 @@ static void js_keyboard_text(struct mjs* mjs) { mjs_val_t bool_obj = mjs_arg(mjs, 2); ShouldSelect = (int)mjs_get_bool(mjs, bool_obj); - if(keyboardinst->textinput && keyboardinst->view_dispatcher) { + if(keyboard->text_input && keyboard->view_dispatcher) { if(strlen(defaultText) > 0) { - text_input_set_header_text(keyboardinst->textinput, defaultText); + text_input_set_header_text(keyboard->text_input, defaultText); } view_dispatcher_attach_to_gui( - keyboardinst->view_dispatcher, - furi_record_open(RECORD_GUI), - ViewDispatcherTypeFullscreen); + keyboard->view_dispatcher, furi_record_open(RECORD_GUI), ViewDispatcherTypeFullscreen); furi_record_close(RECORD_GUI); text_input_set_result_callback( - keyboardinst->textinput, + keyboard->text_input, text_input_callback, - keyboardinst, - keyboardinst->data, + keyboard, + keyboard->data, MaxInputLength, ShouldSelect); - view_dispatcher_switch_to_view(keyboardinst->view_dispatcher, 0); + view_dispatcher_switch_to_view(keyboard->view_dispatcher, 0); - view_dispatcher_run(keyboardinst->view_dispatcher); + view_dispatcher_run(keyboard->view_dispatcher); } - text_input_reset(keyboardinst->textinput); + text_input_reset(keyboard->text_input); - mjs_return(mjs, mjs_mk_string(mjs, keyboardinst->data, strlen(keyboardinst->data), 1)); + mjs_return(mjs, mjs_mk_string(mjs, keyboard->data, strlen(keyboard->data), 1)); } static void js_keyboard_byte(struct mjs* mjs) { - JsKeyboardInst* keyboardinst = get_this_ctx(mjs); + JsKeyboardInst* keyboard = get_this_ctx(mjs); int MaxInputLength; if(!get_int_arg(mjs, 0, &MaxInputLength)) return; @@ -135,61 +133,54 @@ static void js_keyboard_byte(struct mjs* mjs) { const char* defaultText; get_str_arg(mjs, 1, &defaultText); - if(keyboardinst->byteinputview && keyboardinst->view_dispatcher) { + if(keyboard->byte_input && keyboard->view_dispatcher) { if(strlen(defaultText) > 0) { - byte_input_set_header_text(keyboardinst->byteinputview, defaultText); + byte_input_set_header_text(keyboard->byte_input, defaultText); } view_dispatcher_attach_to_gui( - keyboardinst->view_dispatcher, - furi_record_open(RECORD_GUI), - ViewDispatcherTypeFullscreen); + keyboard->view_dispatcher, furi_record_open(RECORD_GUI), ViewDispatcherTypeFullscreen); furi_record_close(RECORD_GUI); byte_input_set_result_callback( - keyboardinst->byteinputview, - byte_input_callback, - NULL, - keyboardinst, - keyboardinst->byteinput, - 10); + keyboard->byte_input, byte_input_callback, NULL, keyboard, keyboard->byteinput, 10); - view_dispatcher_switch_to_view(keyboardinst->view_dispatcher, 1); + view_dispatcher_switch_to_view(keyboard->view_dispatcher, 1); - view_dispatcher_run(keyboardinst->view_dispatcher); + view_dispatcher_run(keyboard->view_dispatcher); } FURI_LOG_D("SHIT", "DID THING"); - keyboardinst->data = bytes_to_hex_string(keyboardinst->byteinput, 10); + keyboard->data = bytes_to_hex_string(keyboard->byteinput, 10); FURI_LOG_D("SHIT", "DID THING 1"); - mjs_return(mjs, mjs_mk_string(mjs, keyboardinst->data, strlen(keyboardinst->data), 1)); + mjs_return(mjs, mjs_mk_string(mjs, keyboard->data, strlen(keyboard->data), 1)); FURI_LOG_D("SHIT", "DID THING 2"); } static void* js_keyboard_create(struct mjs* mjs, mjs_val_t* object) { - JsKeyboardInst* keyboardinst = malloc(sizeof(JsKeyboardInst)); + JsKeyboardInst* keyboard = malloc(sizeof(JsKeyboardInst)); mjs_val_t keyboard_obj = mjs_mk_object(mjs); - mjs_set(mjs, keyboard_obj, INST_PROP_NAME, ~0, mjs_mk_foreign(mjs, keyboardinst)); + mjs_set(mjs, keyboard_obj, INST_PROP_NAME, ~0, mjs_mk_foreign(mjs, keyboard)); mjs_set(mjs, keyboard_obj, "text", ~0, MJS_MK_FN(js_keyboard_text)); - //mjs_set(mjs, keyboard_obj, "byte", ~0, MJS_MK_FN(js_keyboard_byte)); // NULL POINTER DEREFERENCE - keyboardinst->byteinputview = byte_input_alloc(); - keyboardinst->textinput = text_input_alloc(); - keyboardinst->view_dispatcher = view_dispatcher_alloc(); + mjs_set(mjs, keyboard_obj, "byte", ~0, MJS_MK_FN(js_keyboard_byte)); + keyboard->byte_input = byte_input_alloc(); + keyboard->text_input = text_input_alloc(); + keyboard->view_dispatcher = view_dispatcher_alloc(); keyboardinst->data = malloc(100); keyboardinst->byteinput = malloc(100); - view_dispatcher_enable_queue(keyboardinst->view_dispatcher); + view_dispatcher_enable_queue(keyboard->view_dispatcher); view_dispatcher_add_view( - keyboardinst->view_dispatcher, 0, text_input_get_view(keyboardinst->textinput)); + keyboard->view_dispatcher, 0, text_input_get_view(keyboard->text_input)); view_dispatcher_add_view( - keyboardinst->view_dispatcher, 1, byte_input_get_view(keyboardinst->byteinputview)); + keyboard->view_dispatcher, 1, byte_input_get_view(keyboard->byte_input)); *object = keyboard_obj; - return keyboardinst; + return keyboard; } static void js_keyboard_destroy(void* inst) { JsKeyboardInst* insts = (JsKeyboardInst*)inst; - byte_input_free(insts->byteinputview); - text_input_free(insts->textinput); + byte_input_free(insts->byte_input); + text_input_free(insts->text_input); view_dispatcher_free(insts->view_dispatcher); free(insts->data); free(insts); From 43781d9332f9e9953eaa290c102cd388473aca7e Mon Sep 17 00:00:00 2001 From: Willy-JL <49810075+Willy-JL@users.noreply.github.com> Date: Thu, 7 Mar 2024 05:24:31 +0000 Subject: [PATCH 11/16] Use view IDs --- .../system/js_app/modules/js_keyboard.c | 17 +++++++++++++---- applications/system/js_app/modules/js_submenu.c | 9 +++++++-- 2 files changed, 20 insertions(+), 6 deletions(-) diff --git a/applications/system/js_app/modules/js_keyboard.c b/applications/system/js_app/modules/js_keyboard.c index 29b5c0714..6c546039f 100644 --- a/applications/system/js_app/modules/js_keyboard.c +++ b/applications/system/js_app/modules/js_keyboard.c @@ -13,6 +13,11 @@ typedef struct { uint8_t* byteinput; } JsKeyboardInst; +typedef enum { + JsKeyboardViewTextInput, + JsKeyboardViewByteInput, +} JsKeyboardView; + 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); @@ -114,7 +119,7 @@ static void js_keyboard_text(struct mjs* mjs) { MaxInputLength, ShouldSelect); - view_dispatcher_switch_to_view(keyboard->view_dispatcher, 0); + view_dispatcher_switch_to_view(keyboard->view_dispatcher, JsKeyboardViewTextInput); view_dispatcher_run(keyboard->view_dispatcher); } @@ -145,7 +150,7 @@ static void js_keyboard_byte(struct mjs* mjs) { byte_input_set_result_callback( keyboard->byte_input, byte_input_callback, NULL, keyboard, keyboard->byteinput, 10); - view_dispatcher_switch_to_view(keyboard->view_dispatcher, 1); + view_dispatcher_switch_to_view(keyboard->view_dispatcher, JsKeyboardViewByteInput); view_dispatcher_run(keyboard->view_dispatcher); } @@ -170,9 +175,13 @@ static void* js_keyboard_create(struct mjs* mjs, mjs_val_t* object) { keyboardinst->byteinput = malloc(100); view_dispatcher_enable_queue(keyboard->view_dispatcher); view_dispatcher_add_view( - keyboard->view_dispatcher, 0, text_input_get_view(keyboard->text_input)); + keyboard->view_dispatcher, + JsKeyboardViewTextInput, + text_input_get_view(keyboard->text_input)); view_dispatcher_add_view( - keyboard->view_dispatcher, 1, byte_input_get_view(keyboard->byte_input)); + keyboard->view_dispatcher, + JsKeyboardViewByteInput, + byte_input_get_view(keyboard->byte_input)); *object = keyboard_obj; return keyboard; } diff --git a/applications/system/js_app/modules/js_submenu.c b/applications/system/js_app/modules/js_submenu.c index 08c62f404..88478364b 100644 --- a/applications/system/js_app/modules/js_submenu.c +++ b/applications/system/js_app/modules/js_submenu.c @@ -9,6 +9,10 @@ typedef struct { uint32_t result; } JsSubmenuInst; +typedef enum { + JsSubmenuViewSubmenu, +} JsSubmenuView; + static JsSubmenuInst* get_this_ctx(struct mjs* mjs) { mjs_val_t obj_inst = mjs_get(mjs, mjs_get_this(mjs), INST_PROP_NAME, ~0); JsSubmenuInst* storage = mjs_get_ptr(mjs, obj_inst); @@ -98,7 +102,7 @@ static void js_submenu_show(struct mjs* mjs) { submenu->view_dispatcher, furi_record_open(RECORD_GUI), ViewDispatcherTypeFullscreen); furi_record_close(RECORD_GUI); - view_dispatcher_switch_to_view(submenu->view_dispatcher, 0); + view_dispatcher_switch_to_view(submenu->view_dispatcher, JsSubmenuViewSubmenu); view_dispatcher_run(submenu->view_dispatcher); @@ -117,7 +121,8 @@ static void* js_submenu_create(struct mjs* mjs, mjs_val_t* object) { submenu->submenu = submenu_alloc(); submenu->view_dispatcher = view_dispatcher_alloc(); view_dispatcher_enable_queue(submenu->view_dispatcher); - view_dispatcher_add_view(submenu->view_dispatcher, 0, submenu_get_view(submenu->submenu)); + view_dispatcher_add_view( + submenu->view_dispatcher, JsSubmenuViewSubmenu, submenu_get_view(submenu->submenu)); *object = submenu_obj; return submenu; } From d5e4af482fc0dc6925cbcdcbf83bf3632951e660 Mon Sep 17 00:00:00 2001 From: Willy-JL <49810075+Willy-JL@users.noreply.github.com> Date: Thu, 7 Mar 2024 05:26:40 +0000 Subject: [PATCH 12/16] Fix view memory leaks --- applications/system/js_app/modules/js_keyboard.c | 14 ++++++++------ applications/system/js_app/modules/js_submenu.c | 1 + 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/applications/system/js_app/modules/js_keyboard.c b/applications/system/js_app/modules/js_keyboard.c index 6c546039f..dc7de0648 100644 --- a/applications/system/js_app/modules/js_keyboard.c +++ b/applications/system/js_app/modules/js_keyboard.c @@ -187,12 +187,14 @@ static void* js_keyboard_create(struct mjs* mjs, mjs_val_t* object) { } static void js_keyboard_destroy(void* inst) { - JsKeyboardInst* insts = (JsKeyboardInst*)inst; - byte_input_free(insts->byte_input); - text_input_free(insts->text_input); - view_dispatcher_free(insts->view_dispatcher); - free(insts->data); - free(insts); + JsKeyboardInst* keyboard = (JsKeyboardInst*)inst; + view_dispatcher_remove_view(keyboard->view_dispatcher, JsKeyboardViewByteInput); + byte_input_free(keyboard->byte_input); + view_dispatcher_remove_view(keyboard->view_dispatcher, JsKeyboardViewTextInput); + text_input_free(keyboard->text_input); + view_dispatcher_free(keyboard->view_dispatcher); + free(keyboard->data); + free(keyboard); } static const JsModuleDescriptor js_keyboard_desc = { diff --git a/applications/system/js_app/modules/js_submenu.c b/applications/system/js_app/modules/js_submenu.c index 88478364b..b87f34fa8 100644 --- a/applications/system/js_app/modules/js_submenu.c +++ b/applications/system/js_app/modules/js_submenu.c @@ -129,6 +129,7 @@ static void* js_submenu_create(struct mjs* mjs, mjs_val_t* object) { static void js_submenu_destroy(void* inst) { JsSubmenuInst* submenu = inst; + view_dispatcher_remove_view(submenu->view_dispatcher, JsSubmenuViewSubmenu); submenu_free(submenu->submenu); view_dispatcher_free(submenu->view_dispatcher); free(submenu); From bf8e1845f023b2345d0d450faac74e4f0038cf17 Mon Sep 17 00:00:00 2001 From: Willy-JL <49810075+Willy-JL@users.noreply.github.com> Date: Thu, 7 Mar 2024 05:53:03 +0000 Subject: [PATCH 13/16] JS Keyboard improve memory and error handling --- .../js_app/examples/apps/Scripts/keyboard.js | 3 +- .../system/js_app/modules/js_keyboard.c | 137 +++++++----------- 2 files changed, 57 insertions(+), 83 deletions(-) diff --git a/applications/system/js_app/examples/apps/Scripts/keyboard.js b/applications/system/js_app/examples/apps/Scripts/keyboard.js index ddcb40a61..91510111a 100644 --- a/applications/system/js_app/examples/apps/Scripts/keyboard.js +++ b/applications/system/js_app/examples/apps/Scripts/keyboard.js @@ -1,5 +1,6 @@ let keyboard = require("keyboard"); -let text = keyboard.text(100, "Please Input Shit", 1); +// Default text is optional +let text = keyboard.text(100, "Some default text", true); print("Got text:", text); \ No newline at end of file diff --git a/applications/system/js_app/modules/js_keyboard.c b/applications/system/js_app/modules/js_keyboard.c index dc7de0648..542bdf2fd 100644 --- a/applications/system/js_app/modules/js_keyboard.c +++ b/applications/system/js_app/modules/js_keyboard.c @@ -23,49 +23,25 @@ static void ret_bad_args(struct mjs* mjs, const char* error) { mjs_return(mjs, MJS_UNDEFINED); } -char nibble_to_hex_character(uint8_t nibble) { - nibble &= 0xF; - if(nibble < 10) { - return '0' + nibble; - } else { - return 'A' + (nibble - 10); - } -} - -char* bytes_to_hex_string(uint8_t* bytes, size_t num_bytes) { - char* hex_string = (char*)malloc(num_bytes * 2 + 1); - if(hex_string == NULL) { - FURI_LOG_D("LOG", "Memory allocation failed\n"); - return NULL; - } - - for(size_t i = 0; i < num_bytes; ++i) { - hex_string[i * 2] = nibble_to_hex_character(bytes[i] >> 4); - hex_string[i * 2 + 1] = nibble_to_hex_character(bytes[i] & 0xF); - } - hex_string[num_bytes * 2] = '\0'; - - return hex_string; -} - -static bool get_str_arg(struct mjs* mjs, size_t index, const char** value) { +static bool get_str_arg(struct mjs* mjs, size_t index, const char** value, bool error) { mjs_val_t str_obj = mjs_arg(mjs, index); if(!mjs_is_string(str_obj)) { - ret_bad_args(mjs, "Argument must be a string"); + if(error) ret_bad_args(mjs, "Argument must be a string"); return false; } size_t str_len = 0; *value = mjs_get_string(mjs, &str_obj, &str_len); if((str_len == 0) || (*value == NULL)) { - ret_bad_args(mjs, "Bad string argument"); + if(error) ret_bad_args(mjs, "Bad string argument"); return false; } return true; } -static bool get_int_arg(struct mjs* mjs, size_t index, int* value) { +static bool get_int_arg(struct mjs* mjs, size_t index, int* 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 = (int)mjs_get_int(mjs, int_obj); @@ -92,74 +68,73 @@ void byte_input_callback(void* context) { static void js_keyboard_text(struct mjs* mjs) { JsKeyboardInst* keyboard = get_this_ctx(mjs); - int MaxInputLength; - if(!get_int_arg(mjs, 0, &MaxInputLength)) return; + int input_length; + if(!get_int_arg(mjs, 0, &input_length, true)) return; + char* buffer = malloc(input_length); - const char* defaultText = ""; - get_str_arg(mjs, 1, &defaultText); - - int ShouldSelect; - mjs_val_t bool_obj = mjs_arg(mjs, 2); - ShouldSelect = (int)mjs_get_bool(mjs, bool_obj); - - if(keyboard->text_input && keyboard->view_dispatcher) { - if(strlen(defaultText) > 0) { - text_input_set_header_text(keyboard->text_input, defaultText); - } - - view_dispatcher_attach_to_gui( - keyboard->view_dispatcher, furi_record_open(RECORD_GUI), ViewDispatcherTypeFullscreen); - furi_record_close(RECORD_GUI); - - text_input_set_result_callback( - keyboard->text_input, - text_input_callback, - keyboard, - keyboard->data, - MaxInputLength, - ShouldSelect); - - view_dispatcher_switch_to_view(keyboard->view_dispatcher, JsKeyboardViewTextInput); - - view_dispatcher_run(keyboard->view_dispatcher); + const char* default_text = ""; + bool clear_default = false; + if(get_str_arg(mjs, 1, &default_text, false)) { + strlcpy(buffer, default_text, input_length); + mjs_val_t bool_obj = mjs_arg(mjs, 2); + clear_default = mjs_get_bool(mjs, bool_obj); } + // TODO: own function + // if(strlen(default_text) > 0) { + // text_input_set_header_text(keyboard->text_input, default_text); + // } + + view_dispatcher_attach_to_gui( + keyboard->view_dispatcher, furi_record_open(RECORD_GUI), ViewDispatcherTypeFullscreen); + furi_record_close(RECORD_GUI); + + text_input_set_result_callback( + keyboard->text_input, text_input_callback, keyboard, buffer, input_length, clear_default); + + view_dispatcher_switch_to_view(keyboard->view_dispatcher, JsKeyboardViewTextInput); + + view_dispatcher_run(keyboard->view_dispatcher); + text_input_reset(keyboard->text_input); - mjs_return(mjs, mjs_mk_string(mjs, keyboard->data, strlen(keyboard->data), 1)); + mjs_return(mjs, mjs_mk_string(mjs, buffer, ~0, true)); + free(buffer); } static void js_keyboard_byte(struct mjs* mjs) { JsKeyboardInst* keyboard = get_this_ctx(mjs); - int MaxInputLength; - if(!get_int_arg(mjs, 0, &MaxInputLength)) return; + int input_length; + if(!get_int_arg(mjs, 0, &input_length, true)) return; + uint8_t* buffer = malloc(input_length); - const char* defaultText; - get_str_arg(mjs, 1, &defaultText); + // const char* default_data; + // if(get_str_arg(mjs, 1, &default_data, false)) { + // strlcpy(buffer, default_data, input_length); + // } - if(keyboard->byte_input && keyboard->view_dispatcher) { - if(strlen(defaultText) > 0) { - byte_input_set_header_text(keyboard->byte_input, defaultText); - } + // TODO: own function + // if(strlen(default_data) > 0) { + // byte_input_set_header_text(keyboard->byte_input, default_data); + // } - view_dispatcher_attach_to_gui( - keyboard->view_dispatcher, furi_record_open(RECORD_GUI), ViewDispatcherTypeFullscreen); - furi_record_close(RECORD_GUI); + view_dispatcher_attach_to_gui( + keyboard->view_dispatcher, furi_record_open(RECORD_GUI), ViewDispatcherTypeFullscreen); + furi_record_close(RECORD_GUI); - byte_input_set_result_callback( - keyboard->byte_input, byte_input_callback, NULL, keyboard, keyboard->byteinput, 10); + byte_input_set_result_callback( + keyboard->byte_input, byte_input_callback, NULL, keyboard, buffer, input_length); - view_dispatcher_switch_to_view(keyboard->view_dispatcher, JsKeyboardViewByteInput); + view_dispatcher_switch_to_view(keyboard->view_dispatcher, JsKeyboardViewByteInput); - view_dispatcher_run(keyboard->view_dispatcher); - } + view_dispatcher_run(keyboard->view_dispatcher); - FURI_LOG_D("SHIT", "DID THING"); - keyboard->data = bytes_to_hex_string(keyboard->byteinput, 10); - FURI_LOG_D("SHIT", "DID THING 1"); - mjs_return(mjs, mjs_mk_string(mjs, keyboard->data, strlen(keyboard->data), 1)); - FURI_LOG_D("SHIT", "DID THING 2"); + byte_input_set_result_callback(keyboard->byte_input, NULL, NULL, NULL, NULL, 0); + byte_input_set_header_text(keyboard->byte_input, ""); + + mjs_return(mjs, mjs_mk_string(mjs, (char*)buffer, ~0, true)); + free(buffer); } static void* js_keyboard_create(struct mjs* mjs, mjs_val_t* object) { @@ -171,8 +146,6 @@ static void* js_keyboard_create(struct mjs* mjs, mjs_val_t* object) { keyboard->byte_input = byte_input_alloc(); keyboard->text_input = text_input_alloc(); keyboard->view_dispatcher = view_dispatcher_alloc(); - keyboardinst->data = malloc(100); - keyboardinst->byteinput = malloc(100); view_dispatcher_enable_queue(keyboard->view_dispatcher); view_dispatcher_add_view( keyboard->view_dispatcher, From 0405849ca615cc992eae374c6a3c4fcd16feea68 Mon Sep 17 00:00:00 2001 From: Willy-JL <49810075+Willy-JL@users.noreply.github.com> Date: Thu, 7 Mar 2024 05:59:33 +0000 Subject: [PATCH 14/16] JS Keyboard add setHeader() --- .../js_app/examples/apps/Scripts/keyboard.js | 5 ++-- .../system/js_app/modules/js_keyboard.c | 23 +++++++++++-------- 2 files changed, 16 insertions(+), 12 deletions(-) diff --git a/applications/system/js_app/examples/apps/Scripts/keyboard.js b/applications/system/js_app/examples/apps/Scripts/keyboard.js index 91510111a..784ddf2a0 100644 --- a/applications/system/js_app/examples/apps/Scripts/keyboard.js +++ b/applications/system/js_app/examples/apps/Scripts/keyboard.js @@ -1,6 +1,7 @@ let keyboard = require("keyboard"); -// Default text is optional -let text = keyboard.text(100, "Some default text", true); +keyboard.setHeader("Example Text Input"); +// Default text is optional +let text = keyboard.text(100, "Default text", true); print("Got text:", text); \ No newline at end of file diff --git a/applications/system/js_app/modules/js_keyboard.c b/applications/system/js_app/modules/js_keyboard.c index 542bdf2fd..4a7b13546 100644 --- a/applications/system/js_app/modules/js_keyboard.c +++ b/applications/system/js_app/modules/js_keyboard.c @@ -65,6 +65,18 @@ void byte_input_callback(void* context) { view_dispatcher_stop(keyboard->view_dispatcher); } +static void js_keyboard_set_header(struct mjs* mjs) { + JsKeyboardInst* keyboard = get_this_ctx(mjs); + + const char* header; + if(!get_str_arg(mjs, 0, &header, true)) return; + + text_input_set_header_text(keyboard->text_input, header); + byte_input_set_header_text(keyboard->byte_input, header); + + mjs_return(mjs, MJS_UNDEFINED); +} + static void js_keyboard_text(struct mjs* mjs) { JsKeyboardInst* keyboard = get_this_ctx(mjs); @@ -80,11 +92,6 @@ static void js_keyboard_text(struct mjs* mjs) { clear_default = mjs_get_bool(mjs, bool_obj); } - // TODO: own function - // if(strlen(default_text) > 0) { - // text_input_set_header_text(keyboard->text_input, default_text); - // } - view_dispatcher_attach_to_gui( keyboard->view_dispatcher, furi_record_open(RECORD_GUI), ViewDispatcherTypeFullscreen); furi_record_close(RECORD_GUI); @@ -114,11 +121,6 @@ static void js_keyboard_byte(struct mjs* mjs) { // strlcpy(buffer, default_data, input_length); // } - // TODO: own function - // if(strlen(default_data) > 0) { - // byte_input_set_header_text(keyboard->byte_input, default_data); - // } - view_dispatcher_attach_to_gui( keyboard->view_dispatcher, furi_record_open(RECORD_GUI), ViewDispatcherTypeFullscreen); furi_record_close(RECORD_GUI); @@ -141,6 +143,7 @@ static void* js_keyboard_create(struct mjs* mjs, mjs_val_t* object) { JsKeyboardInst* keyboard = malloc(sizeof(JsKeyboardInst)); mjs_val_t keyboard_obj = mjs_mk_object(mjs); mjs_set(mjs, keyboard_obj, INST_PROP_NAME, ~0, mjs_mk_foreign(mjs, keyboard)); + mjs_set(mjs, keyboard_obj, "setHeader", ~0, MJS_MK_FN(js_keyboard_set_header)); mjs_set(mjs, keyboard_obj, "text", ~0, MJS_MK_FN(js_keyboard_text)); mjs_set(mjs, keyboard_obj, "byte", ~0, MJS_MK_FN(js_keyboard_byte)); keyboard->byte_input = byte_input_alloc(); From 03f780f43ccf8e0572db1b39deb3c679d538595f Mon Sep 17 00:00:00 2001 From: Willy-JL <49810075+Willy-JL@users.noreply.github.com> Date: Thu, 7 Mar 2024 06:20:14 +0000 Subject: [PATCH 15/16] Use correct array buf for js byte keyboard --- .../js_app/examples/apps/Scripts/keyboard.js | 14 ++++++++++- .../system/js_app/modules/js_keyboard.c | 23 +++++++++++-------- 2 files changed, 27 insertions(+), 10 deletions(-) diff --git a/applications/system/js_app/examples/apps/Scripts/keyboard.js b/applications/system/js_app/examples/apps/Scripts/keyboard.js index 784ddf2a0..a34607c29 100644 --- a/applications/system/js_app/examples/apps/Scripts/keyboard.js +++ b/applications/system/js_app/examples/apps/Scripts/keyboard.js @@ -4,4 +4,16 @@ keyboard.setHeader("Example Text Input"); // Default text is optional let text = keyboard.text(100, "Default text", true); -print("Got text:", text); \ No newline at end of file +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); \ No newline at end of file diff --git a/applications/system/js_app/modules/js_keyboard.c b/applications/system/js_app/modules/js_keyboard.c index 4a7b13546..e6c0b5a54 100644 --- a/applications/system/js_app/modules/js_keyboard.c +++ b/applications/system/js_app/modules/js_keyboard.c @@ -38,13 +38,13 @@ static bool get_str_arg(struct mjs* mjs, size_t index, const char** value, bool return true; } -static bool get_int_arg(struct mjs* mjs, size_t index, int* value, bool error) { +static bool get_int_arg(struct mjs* mjs, size_t index, size_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 = (int)mjs_get_int(mjs, int_obj); + *value = mjs_get_int(mjs, int_obj); return true; } @@ -80,7 +80,7 @@ static void js_keyboard_set_header(struct mjs* mjs) { static void js_keyboard_text(struct mjs* mjs) { JsKeyboardInst* keyboard = get_this_ctx(mjs); - int input_length; + size_t input_length; if(!get_int_arg(mjs, 0, &input_length, true)) return; char* buffer = malloc(input_length); @@ -112,14 +112,19 @@ static void js_keyboard_text(struct mjs* mjs) { static void js_keyboard_byte(struct mjs* mjs) { JsKeyboardInst* keyboard = get_this_ctx(mjs); - int input_length; + size_t input_length; if(!get_int_arg(mjs, 0, &input_length, true)) return; uint8_t* buffer = malloc(input_length); - // const char* default_data; - // if(get_str_arg(mjs, 1, &default_data, false)) { - // strlcpy(buffer, default_data, input_length); - // } + mjs_val_t default_data_arg = mjs_arg(mjs, 1); + if(mjs_is_typed_array(default_data_arg)) { + if(mjs_is_data_view(default_data_arg)) { + default_data_arg = mjs_dataview_get_buf(mjs, default_data_arg); + } + size_t default_data_len = 0; + char* default_data = mjs_array_buf_get_ptr(mjs, default_data_arg, &default_data_len); + memcpy(buffer, (uint8_t*)default_data, MIN((size_t)input_length, default_data_len)); + } view_dispatcher_attach_to_gui( keyboard->view_dispatcher, furi_record_open(RECORD_GUI), ViewDispatcherTypeFullscreen); @@ -135,7 +140,7 @@ static void js_keyboard_byte(struct mjs* mjs) { byte_input_set_result_callback(keyboard->byte_input, NULL, NULL, NULL, NULL, 0); byte_input_set_header_text(keyboard->byte_input, ""); - mjs_return(mjs, mjs_mk_string(mjs, (char*)buffer, ~0, true)); + mjs_return(mjs, mjs_mk_array_buf(mjs, (char*)buffer, input_length)); free(buffer); } From eedeee4941ab6ea733fa45b4a782660da5b59639 Mon Sep 17 00:00:00 2001 From: Willy-JL <49810075+Willy-JL@users.noreply.github.com> Date: Thu, 7 Mar 2024 07:44:11 +0000 Subject: [PATCH 16/16] JS Blebeacon keep/not prev cfg, use arraybuf, more options --- .../js_app/examples/apps/Scripts/blebeacon.js | 72 +--- .../system/js_app/modules/js_blebeacon.c | 336 +++++++----------- .../system/js_app/modules/js_keyboard.c | 2 +- 3 files changed, 149 insertions(+), 261 deletions(-) diff --git a/applications/system/js_app/examples/apps/Scripts/blebeacon.js b/applications/system/js_app/examples/apps/Scripts/blebeacon.js index f324fafd9..5e29ccbc1 100644 --- a/applications/system/js_app/examples/apps/Scripts/blebeacon.js +++ b/applications/system/js_app/examples/apps/Scripts/blebeacon.js @@ -1,7 +1,7 @@ -let bleBeacon = require("blebeacon"); +let blebeacon = require("blebeacon"); +let math = require("math"); let currentIndex = 0; -let currentByteValue = 0; let watchValues = [ 0x1A, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x11, 0x12, 0x13, 0x14, 0x15, @@ -9,50 +9,15 @@ let watchValues = [ 0x20, 0xEC, 0xEF ]; -function byteToHex(byte) { - let hexChars = '0123456789abcdef'; - let hex = ''; - if (byte >= 0 && byte <= 255) { - hex = hexChars[(byte >> 4) & 0x0F] + hexChars[byte & 0x0F]; - } - return hex; -} - -function getNextByteValue() { - let value = currentByteValue; - currentByteValue = (currentByteValue + 1) % 256; - return value; -} - function generateRandomMac() { - let mac = ''; + let mac = []; for (let i = 0; i < 6; i++) { - if (mac.length) mac += ':'; - let byte = getNextByteValue(); - mac += byteToHex(byte); + mac.push(math.floor(math.random() * 256)); } - return mac; -} - -function bytesToHexString(bytes) { - if (!bytes) { - print("Invalid input for bytesToHexString"); - return ''; - } - - let hexString = ''; - for (let i = 0; i < bytes.length; i++) { - hexString += byteToHex(bytes[i]); - } - return hexString; + return Uint8Array(mac); } function sendRandomModelAdvertisement() { - if (!watchValues || watchValues.length === 0) { - print("watchValues array is empty or undefined."); - return; - } - let model = watchValues[currentIndex]; let packet = [ @@ -60,28 +25,27 @@ function sendRandomModelAdvertisement() { model ]; - let packetString = bytesToHexString(packet); - if (!packetString) { - print("Failed to generate packet string."); - return; - } + let intervalMs = 50; - bleBeacon.setMac(generateRandomMac()); - bleBeacon.setData(packetString); - bleBeacon.send(); + // 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(500); + delay(intervalMs); - bleBeacon.stop(); - - bleBeacon + blebeacon.stop(); } -while (true) -{ +// Make sure it resets at script exit, true will keep advertising in background +blebeacon.keepAlive(true); + +while (true) { sendRandomModelAdvertisement(); } \ No newline at end of file diff --git a/applications/system/js_app/modules/js_blebeacon.c b/applications/system/js_app/modules/js_blebeacon.c index 946a99bab..35dbbb47b 100644 --- a/applications/system/js_app/modules/js_blebeacon.c +++ b/applications/system/js_app/modules/js_blebeacon.c @@ -3,81 +3,20 @@ #include typedef struct { - char* data; - char* mac_addr; - size_t beacon_data_len; - GapExtraBeaconConfig beacon_config; + 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; -struct OUI_MAP_ENTRY { - const char* brand; - const char* oui; -}; - -struct OUI_MAP_ENTRY OUI_MAP[] = { - {"Apple", "00:1F:7F"}, - {"Dell", "00:14:5F"}, - {"HP", "00:4C:6F"}, - {"Lenovo", "00:50:C2"}, - {"Microsoft", "00:0C:29"}, - {"Samsung", "00:1C:42"}, - {"Sony", "00:0A:95"}, - {"Acer", "00:26:A9"}, - {"Asus", "00:19:D8"}, - {"Google", "08:00:27"}, - {"HTC", "00:1F:B5"}, - {"Intel", "00:19:5D"}, - {"LG", "00:1C:61"}, - {"Motorola", "00:1F:42"}, - {"Toshiba", "00:1E:67"}, - {"Xiaomi", "00:26:A8"}, -}; - -#define OUI_MAP_SIZE (sizeof(OUI_MAP) / sizeof(OUI_MAP[0])) - -int rand_range(int min, int max) { - return min + rand() / (RAND_MAX / (max - min + 1) + 1); -} - -void byte_to_hex(char* output, unsigned char byte) { - static const char hex_chars[] = "0123456789ABCDEF"; - output[0] = hex_chars[byte >> 4]; - output[1] = hex_chars[byte & 0x0F]; -} - -static char* generate_mac_address(const char* brand) { - char* mac_address = (char*)malloc(18 * sizeof(char)); - if(mac_address == NULL) { - FURI_LOG_D("BLE", "Memory allocation failed.\n"); - return NULL; - } - - const char* oui = NULL; - for(unsigned int i = 0; i < OUI_MAP_SIZE; ++i) { - if(strcmp(brand, OUI_MAP[i].brand) == 0) { - oui = OUI_MAP[i].oui; - break; - } - } - - if(oui == NULL) { - FURI_LOG_D("BLE", "Brand not found.\n"); - free(mac_address); - return NULL; - } - - char last_bytes[6]; - for(int i = 0; i < 3; ++i) { - unsigned char byte = rand_range(0x00, 0xFF); - byte_to_hex(&last_bytes[i * 2], byte); - } - - strcpy(mac_address, oui); - strcat(mac_address, ":"); - strcat(mac_address, last_bytes); - return mac_address; -} - 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); @@ -99,177 +38,162 @@ static bool check_arg_count(struct mjs* mjs, size_t count) { return true; } -static bool get_str_arg(struct mjs* mjs, size_t index, char** value) { - mjs_val_t str_obj = mjs_arg(mjs, index); - if(!mjs_is_string(str_obj)) { - ret_bad_args(mjs, "Argument must be a string"); +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; } - size_t str_len; - const char* temp = mjs_get_string(mjs, &str_obj, &str_len); - if(str_len == 0 || !temp) { - ret_bad_args(mjs, "Bad string argument"); - return false; - } - - *value = (char*)malloc(str_len + 1); - if(!*value) { - ret_bad_args(mjs, "Memory allocation failed"); - return false; - } - strncpy(*value, temp, str_len); - (*value)[str_len] = '\0'; // Ensure null termination + *value = mjs_get_int(mjs, int_obj); return true; } -static uint8_t hex_char_to_uint(char c) { - if(c >= '0' && c <= '9') return c - '0'; - if(c >= 'a' && c <= 'f') return 10 + c - 'a'; - if(c >= 'A' && c <= 'F') return 10 + c - 'A'; - return 0; -} +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; + } -static uint8_t* macstr_to_uint8(const char* macstr) { - if(strlen(macstr) != 17) return NULL; + 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* mac_bytes = (uint8_t*)malloc(6 * sizeof(uint8_t)); - if(!mac_bytes) return NULL; + uint8_t power = GapAdvPowerLevel_0dBm; + get_int_arg(mjs, 1, &power, false); + power = CLAMP(power, GapAdvPowerLevel_6dBm, GapAdvPowerLevel_Neg40dBm); - for(size_t i = 0, j = 0; i < 17; i += 3, ++j) { - mac_bytes[j] = (hex_char_to_uint(macstr[i]) << 4) | hex_char_to_uint(macstr[i + 1]); + uint8_t intv_min = 50; + get_int_arg(mjs, 2, &intv_min, false); + intv_min = MAX(intv_min, 20); - if(i < 15 && macstr[i + 2] != ':' && macstr[i + 2] != '-') { - free(mac_bytes); - return NULL; + 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; } } - - return mac_bytes; -} - -static uint8_t* hexstr_to_uint8(const char* hexstr, size_t* out_length) { - size_t len = strlen(hexstr); - if(len % 2 != 0) return NULL; - - if(len > EXTRA_BEACON_MAX_DATA_SIZE + 1) return NULL; - - *out_length = len / 2; - uint8_t* bytes = (uint8_t*)malloc(*out_length); - if(!bytes) return NULL; - - for(size_t i = 0; i < *out_length; ++i) { - bytes[i] = (hex_char_to_uint(hexstr[i * 2]) << 4) | hex_char_to_uint(hexstr[i * 2 + 1]); - } - - return bytes; + furi_check(furi_hal_bt_extra_beacon_set_config(&config)); } static void js_blebeacon_set_data(struct mjs* mjs) { - FURI_LOG_D("BLE", "Setting data"); + JsBlebeaconInst* blebeacon = get_this_ctx(mjs); if(!check_arg_count(mjs, 1)) return; - JsBlebeaconInst* inst = get_this_ctx(mjs); - if(!inst) { - FURI_LOG_D("BLE", "Beacon instance is null"); - ret_bad_args(mjs, "Beacon instance is null"); - return; - } - - if(inst->data) { - FURI_LOG_D("BLE", "Freeing existing data"); - free(inst->data); - inst->data = NULL; - } - - if(!get_str_arg(mjs, 0, &(inst->data))) return; // get_str_arg now modifies inst->data directly + char* data = NULL; size_t data_len = 0; - uint8_t* beacon_data = hexstr_to_uint8(inst->data, &data_len); - if(!beacon_data) { - FURI_LOG_D("BLE", "Failed to convert data to hex"); - ret_bad_args(mjs, "Failed to convert data to hex"); + 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; } - FURI_LOG_D("BLE", "Successfully set beacon data"); - furi_hal_bt_extra_beacon_set_data(beacon_data, data_len); - free(beacon_data); + 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_generate_mac(struct mjs* mjs) { - char* company = ""; - if(!get_str_arg(mjs, 0, &company)) return; +static void js_blebeacon_start(struct mjs* mjs) { + JsBlebeaconInst* blebeacon = get_this_ctx(mjs); + if(!check_arg_count(mjs, 0)) return; - char* mac = generate_mac_address(company); - - mjs_val_t js_mac_address = mjs_mk_string(mjs, mac, strlen(mac), 1); - - return mjs_return(mjs, js_mac_address); -} - -static void js_blebeacon_set_mac(struct mjs* mjs) { - FURI_LOG_D("BLE", "Setting Mac"); - if(!check_arg_count(mjs, 1)) { - ret_bad_args(mjs, "Bad args"); - return; + if(!blebeacon->saved_prev_active) { + blebeacon->saved_prev_active = true; + blebeacon->prev_active = furi_hal_bt_extra_beacon_is_active(); } - - JsBlebeaconInst* inst = get_this_ctx(mjs); - char* mac_addr = ""; - if(!get_str_arg(mjs, 0, &mac_addr)) return; - inst->mac_addr = mac_addr; - inst->beacon_config.min_adv_interval_ms = 50; - inst->beacon_config.max_adv_interval_ms = 150; - - inst->beacon_config.adv_channel_map = GapAdvChannelMapAll; - inst->beacon_config.adv_power_level = GapAdvPowerLevel_0dBm; - - inst->beacon_config.address_type = GapAddressTypePublic; - - uint8_t* mac = macstr_to_uint8(mac_addr); - if(mac) { - memcpy(inst->beacon_config.address, mac, 6); - furi_hal_bt_extra_beacon_set_config(&inst->beacon_config); - mjs_return(mjs, MJS_UNDEFINED); - } else { - FURI_LOG_D("BLE", "Bad MacAddress"); - ret_bad_args(mjs, "Bad Mac Address"); - return; - } -} - -static void js_blebeacon_send(struct mjs* mjs) { - furi_hal_bt_extra_beacon_start(); + 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_create(struct mjs* mjs, mjs_val_t* object) { - JsBlebeaconInst* inst = 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, inst)); - mjs_set(mjs, blebeacon_obj, "setData", ~0, MJS_MK_FN(js_blebeacon_set_data)); - mjs_set(mjs, blebeacon_obj, "setMac", ~0, MJS_MK_FN(js_blebeacon_set_mac)); - mjs_set(mjs, blebeacon_obj, "send", ~0, MJS_MK_FN(js_blebeacon_send)); - mjs_set(mjs, blebeacon_obj, "stop", ~0, MJS_MK_FN(js_blebeacon_stop)); - mjs_set(mjs, blebeacon_obj, "genMac", ~0, MJS_MK_FN(js_blebeacon_generate_mac)); - *object = blebeacon_obj; - return inst; +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_destroy(void* ptr) { - JsBlebeaconInst* inst = (JsBlebeaconInst*)ptr; - if(inst) { - free(inst->data); - free(inst->mac_addr); - free(inst); +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 = { diff --git a/applications/system/js_app/modules/js_keyboard.c b/applications/system/js_app/modules/js_keyboard.c index e6c0b5a54..8958dcaf8 100644 --- a/applications/system/js_app/modules/js_keyboard.c +++ b/applications/system/js_app/modules/js_keyboard.c @@ -168,7 +168,7 @@ static void* js_keyboard_create(struct mjs* mjs, mjs_val_t* object) { } static void js_keyboard_destroy(void* inst) { - JsKeyboardInst* keyboard = (JsKeyboardInst*)inst; + JsKeyboardInst* keyboard = inst; view_dispatcher_remove_view(keyboard->view_dispatcher, JsKeyboardViewByteInput); byte_input_free(keyboard->byte_input); view_dispatcher_remove_view(keyboard->view_dispatcher, JsKeyboardViewTextInput);