mirror of
https://github.com/Next-Flip/Momentum-Firmware.git
synced 2026-05-22 05:14:46 -07:00
Merge pull request #957 from LuisMayo/feat/add_ir_js_plugin
feat: add IR capabilities to the JS engine
This commit is contained in:
@@ -240,6 +240,14 @@ App(
|
||||
sources=["modules/js_subghz/*.c"],
|
||||
)
|
||||
|
||||
App(
|
||||
appid="js_infrared",
|
||||
apptype=FlipperAppType.PLUGIN,
|
||||
entry_point="js_infrared_ep",
|
||||
requires=["js_app"],
|
||||
sources=["modules/js_infrared/*.c"],
|
||||
)
|
||||
|
||||
App(
|
||||
appid="js_blebeacon",
|
||||
apptype=FlipperAppType.PLUGIN,
|
||||
|
||||
@@ -0,0 +1,47 @@
|
||||
checkSdkFeatures(["infrared-send"]);
|
||||
let infrared = require("infrared");
|
||||
|
||||
print("Sending Samsung32 signal (lowers volume)...");
|
||||
infrared.sendSignal("Samsung32", 0x00000007, 0x0000000b);
|
||||
delay(1000);
|
||||
print("Sending raw signal... (Fujitsu AC)");
|
||||
infrared.sendRawSignal(
|
||||
[
|
||||
3298, 1571, 442, 368, 442, 367, 443, 1180, 442, 370, 440, 1181, 442, 368,
|
||||
442, 367, 442, 368, 442, 1180, 443, 1180, 442, 368, 441, 367, 442, 369, 441,
|
||||
1180, 442, 1180, 443, 368, 442, 369, 441, 368, 442, 368, 442, 368, 442, 368,
|
||||
441, 368, 441, 368, 442, 368, 442, 368, 442, 367, 442, 368, 442, 366, 444,
|
||||
1181, 442, 368, 441, 367, 442, 368, 442, 367, 442, 369, 441, 367, 443, 367,
|
||||
442, 1180, 442, 368, 442, 368, 442, 368, 441, 368, 441, 1180, 442, 1180,
|
||||
442, 1181, 442, 1181, 441, 1181, 442, 1181, 442, 1181, 442, 1181, 442, 369,
|
||||
441, 368, 441, 1182, 442, 367, 443, 367, 443, 367, 442, 368, 442, 1181, 441,
|
||||
369, 441, 369, 441, 369, 441, 1180, 442, 1181, 441, 369, 442, 368, 442, 367,
|
||||
442, 368, 441, 1181, 441, 1183, 440, 368, 442, 368, 441, 369, 441, 1181,
|
||||
442, 368, 442, 367, 443, 1181, 442, 368, 442, 369, 441, 368, 441, 369, 440,
|
||||
368, 442, 367, 443, 367, 442, 367, 442, 367, 442, 368, 442, 369, 441, 369,
|
||||
441, 368, 442, 369, 441, 368, 441, 367, 443, 368, 442, 367, 442, 369, 441,
|
||||
369, 441, 368, 441, 367, 442, 367, 442, 368, 442, 368, 441, 368, 442, 368,
|
||||
442, 368, 441, 367, 442, 367, 442, 368, 442, 368, 441, 368, 442, 369, 441,
|
||||
368, 441, 367, 442, 368, 441, 368, 442, 368, 442, 368, 442, 368, 442, 367,
|
||||
442, 1181, 442, 367, 442, 368, 441, 1181, 442, 1182, 441, 1181, 442, 1181,
|
||||
442, 1181, 441, 368, 442, 368, 442, 369, 441,
|
||||
],
|
||||
true,
|
||||
{ frequency: 38000, dutyCycle: 0.33 },
|
||||
);
|
||||
delay(1000);
|
||||
print(
|
||||
"Sending raw signal... (Fujitsu AC) with default frequency and duty cycle",
|
||||
);
|
||||
infrared.sendRawSignal([
|
||||
3300, 1596, 416, 362, 448, 363, 446, 1177, 445, 363, 446, 1177, 445, 362, 448,
|
||||
362, 448, 364, 446, 1178, 444, 1207, 415, 362, 448, 362, 448, 363, 447, 1177,
|
||||
445, 1177, 446, 362, 448, 362, 447, 362, 447, 362, 448, 363, 447, 362, 447,
|
||||
363, 447, 363, 447, 363, 446, 363, 446, 362, 447, 362, 447, 363, 446, 1177,
|
||||
445, 363, 447, 364, 446, 362, 448, 363, 447, 363, 446, 362, 447, 362, 448,
|
||||
1175, 447, 363, 447, 364, 446, 362, 448, 362, 448, 1176, 446, 362, 448, 362,
|
||||
448, 363, 446, 362, 448, 362, 448, 363, 447, 1175, 446, 394, 415, 1176, 446,
|
||||
1178, 444, 1174, 449, 1177, 445, 1180, 443, 1179, 443,
|
||||
]);
|
||||
|
||||
print("Success");
|
||||
@@ -281,6 +281,7 @@ static const char* extra_features[] = {
|
||||
"blebeacon",
|
||||
"i2c",
|
||||
"spi",
|
||||
"infrared-send",
|
||||
"subghz",
|
||||
"usbdisk",
|
||||
"vgm",
|
||||
|
||||
129
applications/system/js_app/modules/js_infrared/js_infrared.c
Normal file
129
applications/system/js_app/modules/js_infrared/js_infrared.c
Normal file
@@ -0,0 +1,129 @@
|
||||
#include "../../js_modules.h"
|
||||
#include <infrared_worker.h>
|
||||
#include <lib/infrared/signal/infrared_signal.h>
|
||||
#include <lib/infrared/worker/infrared_transmit.h>
|
||||
|
||||
#define TAG "JsMath"
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
void js_send_protocol_signal(struct mjs* mjs) {
|
||||
size_t num_args = mjs_nargs(mjs);
|
||||
if(num_args < 3 || num_args > 4) {
|
||||
ret_bad_args(mjs, "Wrong argument count");
|
||||
return;
|
||||
}
|
||||
if(!mjs_is_string(mjs_arg(mjs, 0)) || !mjs_is_number(mjs_arg(mjs, 1)) ||
|
||||
!mjs_is_number(mjs_arg(mjs, 2)) || (num_args == 4 && !mjs_is_object(mjs_arg(mjs, 3)))) {
|
||||
ret_bad_args(mjs, "Wrong argument type");
|
||||
return;
|
||||
}
|
||||
bool repeat = false;
|
||||
int times = 1;
|
||||
if(num_args == 4) {
|
||||
mjs_val_t options_obj = mjs_arg(mjs, 3);
|
||||
|
||||
mjs_val_t repeat_val = mjs_get(mjs, options_obj, "repeat", ~0);
|
||||
if(mjs_is_boolean(repeat_val)) {
|
||||
repeat = mjs_get_bool(mjs, repeat_val);
|
||||
} else if(!mjs_is_undefined(repeat_val)) {
|
||||
ret_bad_args(mjs, "Wrong 'repeat' option type");
|
||||
return;
|
||||
}
|
||||
|
||||
mjs_val_t times_val = mjs_get(mjs, options_obj, "times", ~0);
|
||||
if(mjs_is_number(times_val)) {
|
||||
times = mjs_get_int(mjs, times_val);
|
||||
} else if(!mjs_is_undefined(times_val)) {
|
||||
ret_bad_args(mjs, "Wrong 'times' option type");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
InfraredMessage message;
|
||||
message.repeat = repeat;
|
||||
mjs_val_t protocol_arg = mjs_arg(mjs, 0);
|
||||
message.protocol = infrared_get_protocol_by_name(mjs_get_cstring(mjs, &protocol_arg));
|
||||
message.address = mjs_get_int(mjs, mjs_arg(mjs, 1));
|
||||
message.command = mjs_get_int(mjs, mjs_arg(mjs, 2));
|
||||
infrared_send(&message, times);
|
||||
}
|
||||
|
||||
void js_send_raw_signal(struct mjs* mjs) {
|
||||
size_t num_args = mjs_nargs(mjs);
|
||||
if(num_args < 1 || num_args > 3) {
|
||||
ret_bad_args(mjs, "Wrong argument count");
|
||||
return;
|
||||
}
|
||||
if(!mjs_is_array(mjs_arg(mjs, 0)) || (num_args > 1 && !mjs_is_boolean(mjs_arg(mjs, 1))) ||
|
||||
(num_args > 2 && !mjs_is_object(mjs_arg(mjs, 2)))) {
|
||||
ret_bad_args(mjs, "Wrong argument type");
|
||||
return;
|
||||
}
|
||||
int array_length = mjs_array_length(mjs, mjs_arg(mjs, 0));
|
||||
uint32_t timings[array_length];
|
||||
for(int i = 0; i < array_length; i++) {
|
||||
mjs_val_t elem = mjs_array_get(mjs, mjs_arg(mjs, 0), i);
|
||||
if(!mjs_is_number(elem)) {
|
||||
ret_bad_args(mjs, "Timings array must contain only numbers");
|
||||
return;
|
||||
}
|
||||
timings[i] = mjs_get_int(mjs, elem);
|
||||
}
|
||||
|
||||
bool start_from_mark = true;
|
||||
if(num_args > 1) {
|
||||
start_from_mark = mjs_get_bool(mjs, mjs_arg(mjs, 1));
|
||||
}
|
||||
|
||||
if(num_args > 2) {
|
||||
mjs_val_t options_obj = mjs_arg(mjs, 2);
|
||||
|
||||
mjs_val_t frequency_val = mjs_get(mjs, options_obj, "frequency", ~0);
|
||||
if(!mjs_is_number(frequency_val)) {
|
||||
ret_bad_args(mjs, "Wrong 'frequency' option type");
|
||||
return;
|
||||
}
|
||||
|
||||
mjs_val_t duty_val = mjs_get(mjs, options_obj, "dutyCycle", ~0);
|
||||
if(!mjs_is_number(duty_val)) {
|
||||
ret_bad_args(mjs, "Wrong 'dutyCycle' option type");
|
||||
return;
|
||||
}
|
||||
uint32_t frequency = mjs_get_int(mjs, frequency_val);
|
||||
float duty_cycle = mjs_get_double(mjs, duty_val);
|
||||
infrared_send_raw_ext(timings, array_length, start_from_mark, frequency, duty_cycle);
|
||||
} else {
|
||||
infrared_send_raw(timings, array_length, start_from_mark);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
static void* js_infrared_create(struct mjs* mjs, mjs_val_t* object, JsModules* modules) {
|
||||
UNUSED(modules);
|
||||
mjs_val_t infrared_object = mjs_mk_object(mjs);
|
||||
mjs_set(mjs, infrared_object, "sendSignal", ~0, MJS_MK_FN(js_send_protocol_signal));
|
||||
mjs_set(mjs, infrared_object, "sendRawSignal", ~0, MJS_MK_FN(js_send_raw_signal));
|
||||
*object = infrared_object;
|
||||
return (void*)1;
|
||||
}
|
||||
|
||||
static const JsModuleDescriptor js_infrared_desc = {
|
||||
"infrared",
|
||||
js_infrared_create,
|
||||
NULL,
|
||||
NULL,
|
||||
};
|
||||
|
||||
static const FlipperAppPluginDescriptor plugin_descriptor = {
|
||||
.appid = PLUGIN_APP_ID,
|
||||
.ep_api_version = PLUGIN_API_VERSION,
|
||||
.entry_point = &js_infrared_desc,
|
||||
};
|
||||
|
||||
const FlipperAppPluginDescriptor* js_infrared_ep(void) {
|
||||
return &plugin_descriptor;
|
||||
}
|
||||
41
applications/system/js_app/packages/fz-sdk/infrared/index.d.ts
vendored
Normal file
41
applications/system/js_app/packages/fz-sdk/infrared/index.d.ts
vendored
Normal file
@@ -0,0 +1,41 @@
|
||||
/**
|
||||
* Module for using Infrared blaster/receptor
|
||||
* @version Available with JS feature `infrared-send`
|
||||
* @module
|
||||
*/
|
||||
|
||||
/**
|
||||
* Sends an IR signal using a known protocol by Flipper Firmware
|
||||
* @param address Note that the address expects a number. If you're reading from Flipper's IR files, the address is usually in little-endian hex format. Javascript numbers are defined as big endian by default.
|
||||
* @param command Note that the command expects a number. If you're reading from Flipper's IR files, the command is usually in little-endian hex format. Javascript numbers are defined as big endian by default.
|
||||
* @param options Repeat marks the signal as a repeat signal, times indicates how many times to send the signal
|
||||
*/
|
||||
export declare function sendSignal(
|
||||
protocol:
|
||||
| "NEC"
|
||||
| "NECext"
|
||||
| "NEC42"
|
||||
| "NEC42ext"
|
||||
| "Samsung32"
|
||||
| "RC6"
|
||||
| "RC5"
|
||||
| "RC5X"
|
||||
| "SIRC"
|
||||
| "SIRC15"
|
||||
| "SIRC20"
|
||||
| "Kaseikyo"
|
||||
| "RCA",
|
||||
address: number,
|
||||
command: number,
|
||||
options?: { repeat?: boolean; times?: number },
|
||||
): void;
|
||||
|
||||
/**
|
||||
* Sends a signal from an unknown protocol
|
||||
* @param startFromMark defaults to true
|
||||
*/
|
||||
export declare function sendRawSignal(
|
||||
timings: number[],
|
||||
startFromMark?: boolean,
|
||||
advancedSettings?: { frequency: number; dutyCycle: number },
|
||||
): void;
|
||||
Reference in New Issue
Block a user