Merge branch 'dev' into somfy_encoder_new

This commit is contained in:
MX 2023-01-18 19:01:22 +03:00
commit 27826f95ca
No known key found for this signature in database
GPG key ID: 6C4C311DFD4B4AB5
100 changed files with 2948 additions and 3468 deletions

View file

@ -1 +1 @@
--rules-config .pvsconfig -e lib/fatfs -e lib/fnv1a-hash -e lib/FreeRTOS-Kernel -e lib/heatshrink -e lib/libusb_stm32 -e lib/littlefs -e lib/mbedtls -e lib/micro-ecc -e lib/microtar -e lib/mlib -e lib/qrcode -e lib/ST25RFAL002 -e lib/STM32CubeWB -e lib/u8g2 -e lib/nanopb -e */arm-none-eabi/* -e applications/plugins/dap_link/lib/free-dap --ignore-ccache -C gccarm --rules-config .pvsconfig -e lib/fatfs -e lib/fnv1a-hash -e lib/FreeRTOS-Kernel -e lib/heatshrink -e lib/libusb_stm32 -e lib/littlefs -e lib/mbedtls -e lib/micro-ecc -e lib/microtar -e lib/mlib -e lib/qrcode -e lib/ST25RFAL002 -e lib/STM32CubeWB -e lib/u8g2 -e lib/nanopb -e */arm-none-eabi/* -e applications/plugins/dap_link/lib/free-dap

View file

@ -105,6 +105,12 @@
"type": "shell", "type": "shell",
"command": "./fbt COMPACT=1 DEBUG=0 FORCE=1 flash_usb_full" "command": "./fbt COMPACT=1 DEBUG=0 FORCE=1 flash_usb_full"
}, },
{
"label": "[Debug] Create PVS-Studio report",
"group": "build",
"type": "shell",
"command": "./fbt firmware_pvs"
},
{ {
"label": "[Debug] Build FAPs", "label": "[Debug] Build FAPs",
"group": "build", "group": "build",
@ -138,6 +144,18 @@
"Serial Console" "Serial Console"
] ]
}, },
{
"label": "[Debug] Build and upload all FAPs to Flipper over USB",
"group": "build",
"type": "shell",
"command": "./fbt fap_deploy"
},
{
"label": "[Release] Build and upload all FAPs to Flipper over USB",
"group": "build",
"type": "shell",
"command": "./fbt COMPACT=1 DEBUG=0 fap_deploy"
},
{ {
// Press Ctrl+] to quit // Press Ctrl+] to quit
"label": "Serial Console", "label": "Serial Console",
@ -145,7 +163,7 @@
"command": "./fbt cli", "command": "./fbt cli",
"group": "none", "group": "none",
"isBackground": true, "isBackground": true,
"options": { "options": {
"env": { "env": {
"FBT_NO_SYNC": "0" "FBT_NO_SYNC": "0"
} }
@ -162,4 +180,4 @@
} }
} }
] ]
} }

View file

@ -148,9 +148,12 @@ fap_dist = [
for app_artifact in firmware_env["FW_EXTAPPS"].applications.values() for app_artifact in firmware_env["FW_EXTAPPS"].applications.values()
), ),
), ),
distenv.Install( *(
f"#/dist/{dist_dir}/apps", distenv.Install(
"#/assets/resources/apps", f"#/dist/{dist_dir}/apps/{app_artifact.app.fap_category}",
app_artifact.compact[0],
)
for app_artifact in firmware_env["FW_EXTAPPS"].applications.values()
), ),
] ]
Depends( Depends(
@ -165,6 +168,14 @@ Alias("fap_dist", fap_dist)
distenv.Depends(firmware_env["FW_RESOURCES"], firmware_env["FW_EXTAPPS"].resources_dist) distenv.Depends(firmware_env["FW_RESOURCES"], firmware_env["FW_EXTAPPS"].resources_dist)
# Copy all faps to device
fap_deploy = distenv.PhonyTarget(
"fap_deploy",
"${PYTHON3} ${ROOT_DIR}/scripts/storage.py send ${SOURCE} /ext/apps",
source=Dir("#/assets/resources/apps"),
)
# Target for bundling core2 package for qFlipper # Target for bundling core2 package for qFlipper
copro_dist = distenv.CoproBuilder( copro_dist = distenv.CoproBuilder(

View file

@ -31,7 +31,8 @@ void AccessorApp::run(void) {
onewire_host_stop(onewire_host); onewire_host_stop(onewire_host);
} }
AccessorApp::AccessorApp() { AccessorApp::AccessorApp()
: text_store{0} {
notification = static_cast<NotificationApp*>(furi_record_open(RECORD_NOTIFICATION)); notification = static_cast<NotificationApp*>(furi_record_open(RECORD_NOTIFICATION));
onewire_host = onewire_host_alloc(); onewire_host = onewire_host_alloc();
furi_hal_power_enable_otg(); furi_hal_power_enable_otg();

View file

@ -171,9 +171,6 @@ bool WIEGAND::DoWiegandConversion() {
return true; return true;
} else { } else {
_lastWiegand = sysTick; _lastWiegand = sysTick;
_bitCount = 0;
_cardTemp = 0;
_cardTempHigh = 0;
return false; return false;
} }

View file

@ -2,8 +2,11 @@
#include <gui/canvas.h> #include <gui/canvas.h>
#include <gui/elements.h> #include <gui/elements.h>
#include <lib/toolbox/float_tools.h>
#include <m-array.h> #include <m-array.h>
#include <furi.h> #include <furi.h>
#include <inttypes.h>
#include <stdint.h> #include <stdint.h>
struct BtTestParam { struct BtTestParam {
@ -98,16 +101,16 @@ static void bt_test_draw_callback(Canvas* canvas, void* _model) {
elements_scrollbar(canvas, model->position, BtTestParamArray_size(model->params)); elements_scrollbar(canvas, model->position, BtTestParamArray_size(model->params));
canvas_draw_str(canvas, 6, 60, model->message); canvas_draw_str(canvas, 6, 60, model->message);
if(model->state == BtTestStateStarted) { if(model->state == BtTestStateStarted) {
if(model->rssi != 0.0f) { if(!float_is_equal(model->rssi, 0.0f)) {
snprintf(info_str, sizeof(info_str), "RSSI:%3.1f dB", (double)model->rssi); snprintf(info_str, sizeof(info_str), "RSSI:%3.1f dB", (double)model->rssi);
canvas_draw_str_aligned(canvas, 124, 60, AlignRight, AlignBottom, info_str); canvas_draw_str_aligned(canvas, 124, 60, AlignRight, AlignBottom, info_str);
} }
} else if(model->state == BtTestStateStopped) { } else if(model->state == BtTestStateStopped) {
if(model->packets_num_rx) { if(model->packets_num_rx) {
snprintf(info_str, sizeof(info_str), "%ld pack rcv", model->packets_num_rx); snprintf(info_str, sizeof(info_str), "%" PRIu32 " pack rcv", model->packets_num_rx);
canvas_draw_str_aligned(canvas, 124, 60, AlignRight, AlignBottom, info_str); canvas_draw_str_aligned(canvas, 124, 60, AlignRight, AlignBottom, info_str);
} else if(model->packets_num_tx) { } else if(model->packets_num_tx) {
snprintf(info_str, sizeof(info_str), "%ld pack sent", model->packets_num_tx); snprintf(info_str, sizeof(info_str), "%" PRIu32 " pack sent", model->packets_num_tx);
canvas_draw_str_aligned(canvas, 124, 60, AlignRight, AlignBottom, info_str); canvas_draw_str_aligned(canvas, 124, 60, AlignRight, AlignBottom, info_str);
} }
} }
@ -153,7 +156,7 @@ static bool bt_test_input_callback(InputEvent* event, void* context) {
} }
void bt_test_process_up(BtTest* bt_test) { void bt_test_process_up(BtTest* bt_test) {
with_view_model( with_view_model( // -V658
bt_test->view, bt_test->view,
BtTestModel * model, BtTestModel * model,
{ {

View file

@ -48,7 +48,7 @@ FileBrowserApp* file_browser_app_alloc(char* arg) {
app->file_path = furi_string_alloc(); app->file_path = furi_string_alloc();
app->file_browser = file_browser_alloc(app->file_path); app->file_browser = file_browser_alloc(app->file_path);
file_browser_configure(app->file_browser, "*", NULL, true, &I_badusb_10px, true); file_browser_configure(app->file_browser, "*", NULL, true, false, &I_badusb_10px, true);
view_dispatcher_add_view( view_dispatcher_add_view(
app->view_dispatcher, FileBrowserAppViewStart, widget_get_view(app->widget)); app->view_dispatcher, FileBrowserAppViewStart, widget_get_view(app->widget));

View file

@ -6,7 +6,6 @@
#include <lib/subghz/subghz_keystore.h> #include <lib/subghz/subghz_keystore.h>
#include <lib/subghz/subghz_file_encoder_worker.h> #include <lib/subghz/subghz_file_encoder_worker.h>
#include <lib/subghz/protocols/protocol_items.h> #include <lib/subghz/protocols/protocol_items.h>
#include <lib/subghz/helpers/subghz_config_preset_custom.h>
#include <flipper_format/flipper_format_i.h> #include <flipper_format/flipper_format_i.h>
#define TAG "SubGhz TEST" #define TAG "SubGhz TEST"
@ -204,132 +203,6 @@ static bool subghz_encoder_test(const char* path) {
return subghz_test_decoder_count ? true : false; return subghz_test_decoder_count ? true : false;
} }
static bool subghz_custom_preset_test(void) {
static const uint8_t preset_data[][2] = {
{CC1101_MDMCFG0, 0},
{CC1101_MDMCFG1, 0},
{CC1101_MDMCFG2, 0},
{CC1101_MDMCFG3, 0},
{CC1101_MDMCFG4, 0},
};
static uint8_t test_data[sizeof(preset_data)] = {0};
memcpy(test_data, preset_data, sizeof(preset_data));
uint8_t* test_data_ptr = &test_data[0];
{ // CHEKING BANDWIDTH SET
for(uint32_t i = 0; i < CH_BANDWIDTH_NUM; ++i) {
uint8_t bw_value = subghz_preset_custom_bandwidth_values[i];
bool result =
subghz_preset_custom_set_bandwidth(test_data_ptr, sizeof(test_data), bw_value);
if(!result) {
FURI_LOG_E(TAG, "Failed to set BW value: %hhu", bw_value);
return false;
}
uint8_t get_bw_value =
subghz_preset_custom_get_bandwidth(test_data_ptr, sizeof(test_data));
if(get_bw_value != bw_value) {
FURI_LOG_E(
TAG,
"BW value from preset: %hhu is not equal expected value: %hhu",
get_bw_value,
bw_value);
return false;
}
FURI_LOG_T(TAG, "Bandwidth check OK: %hhu", bw_value);
}
}
{ // CHEKING MACHESTER SET
bool result =
subghz_preset_custom_set_machester_enable(test_data_ptr, sizeof(test_data), false);
if(!result) {
FURI_LOG_E(TAG, "Failed to set manchester enable flag");
return false;
}
bool flag = subghz_preset_custom_get_machester_enable(test_data_ptr, sizeof(test_data));
if(flag != false) {
FURI_LOG_E(TAG, "Manchester disable flag setup failed!");
return false;
}
subghz_preset_custom_set_machester_enable(test_data_ptr, sizeof(test_data), true);
flag = subghz_preset_custom_get_machester_enable(test_data_ptr, sizeof(test_data));
if(flag != true) {
FURI_LOG_E(TAG, "Manchester enable flag setup failed!");
return false;
}
FURI_LOG_T(TAG, "Manchester flag check OK");
}
{ // CHEKING DATARATE SET
const float datarateRoughMax = 1600000.0f; // bauds
const float datarateRoughStep = 5000.0f;
const float datarateFineMax = 30000.0f;
const float datarateFineStep = 50.0f;
bool result = false;
char datarate_set_str[16] = {0};
char datarate_get_str[16] = {0};
float datarate_set = datarateRoughMax;
float datarate_get = -1.0f;
while(datarate_set > 0) {
subghz_preset_custom_printf_datarate(
datarate_set, datarate_set_str, sizeof(datarate_set_str));
result =
subghz_preset_custom_set_datarate(test_data_ptr, sizeof(test_data), datarate_set);
if(!result) {
FURI_LOG_E(TAG, "Failed to set datarate: %s!", datarate_set_str);
return false;
}
datarate_get = subghz_preset_custom_get_datarate(test_data_ptr, sizeof(test_data));
subghz_preset_custom_printf_datarate(
datarate_get, datarate_get_str, sizeof(datarate_get_str));
if(datarate_get < 0) {
FURI_LOG_E(TAG, "Failed to get datarate!");
return false;
}
if(datarate_set > datarateFineMax) {
result = fabsf(datarate_get - datarate_set) <= datarateRoughStep;
datarate_set -= datarateRoughStep;
} else {
result = fabsf(datarate_get - datarate_set) <= datarateFineStep;
datarate_set -= datarateFineStep;
}
if(result) {
FURI_LOG_T(
TAG,
"Datarate check OK: Set: %s - Get: %s",
datarate_set_str,
datarate_get_str);
} else {
FURI_LOG_E(
TAG,
"Datarate check failed!: %s is way to diff %s! DRATE_E: %hhu DRATE_M: %hhu",
datarate_set_str,
datarate_get_str,
test_data[4 * 2 + 1] & 0b00001111,
test_data[3 * 2 + 1]);
return false;
}
}
}
FURI_LOG_I(TAG, "Sub GHz custom preset test: OK");
return true;
}
MU_TEST(subghz_keystore_test) { MU_TEST(subghz_keystore_test) {
mu_assert( mu_assert(
subghz_environment_load_keystore(environment_handler, KEYSTORE_DIR_NAME), subghz_environment_load_keystore(environment_handler, KEYSTORE_DIR_NAME),
@ -874,10 +747,6 @@ MU_TEST(subghz_random_test) {
mu_assert(subghz_decode_random_test(TEST_RANDOM_DIR_NAME), "Random test error\r\n"); mu_assert(subghz_decode_random_test(TEST_RANDOM_DIR_NAME), "Random test error\r\n");
} }
MU_TEST(subghz_preset_test) {
mu_assert(subghz_custom_preset_test(), "Custom preset logic error\r\n");
}
MU_TEST_SUITE(subghz) { MU_TEST_SUITE(subghz) {
subghz_test_init(); subghz_test_init();
MU_RUN_TEST(subghz_keystore_test); MU_RUN_TEST(subghz_keystore_test);
@ -948,16 +817,7 @@ MU_TEST_SUITE(subghz) {
subghz_test_deinit(); subghz_test_deinit();
} }
MU_TEST_SUITE(subghz_app) {
MU_RUN_TEST(subghz_preset_test);
}
int run_minunit_test_subghz() { int run_minunit_test_subghz() {
MU_RUN_SUITE(subghz); MU_RUN_SUITE(subghz);
return MU_EXIT_CODE; return MU_EXIT_CODE;
} }
int run_minunit_test_subghz_app() {
MU_RUN_SUITE(subghz_app);
return MU_EXIT_CODE;
}

View file

@ -5,7 +5,6 @@
#include <notification/notification_messages.h> #include <notification/notification_messages.h>
#include <cli/cli.h> #include <cli/cli.h>
#include <loader/loader.h> #include <loader/loader.h>
#include <lib/toolbox/args.h>
#define TAG "UnitTests" #define TAG "UnitTests"
@ -20,7 +19,6 @@ int run_minunit_test_flipper_format_string();
int run_minunit_test_stream(); int run_minunit_test_stream();
int run_minunit_test_storage(); int run_minunit_test_storage();
int run_minunit_test_subghz(); int run_minunit_test_subghz();
int run_minunit_test_subghz_app();
int run_minunit_test_dirwalk(); int run_minunit_test_dirwalk();
int run_minunit_test_power(); int run_minunit_test_power();
int run_minunit_test_protocol_dict(); int run_minunit_test_protocol_dict();
@ -49,7 +47,6 @@ const UnitTest unit_tests[] = {
{.name = "flipper_format_string", .entry = run_minunit_test_flipper_format_string}, {.name = "flipper_format_string", .entry = run_minunit_test_flipper_format_string},
{.name = "rpc", .entry = run_minunit_test_rpc}, {.name = "rpc", .entry = run_minunit_test_rpc},
{.name = "subghz", .entry = run_minunit_test_subghz}, {.name = "subghz", .entry = run_minunit_test_subghz},
{.name = "subghz_app", .entry = run_minunit_test_subghz_app},
{.name = "infrared", .entry = run_minunit_test_infrared}, {.name = "infrared", .entry = run_minunit_test_infrared},
{.name = "nfc", .entry = run_minunit_test_nfc}, {.name = "nfc", .entry = run_minunit_test_nfc},
{.name = "power", .entry = run_minunit_test_power}, {.name = "power", .entry = run_minunit_test_power},
@ -76,72 +73,6 @@ void minunit_print_fail(const char* str) {
printf(FURI_LOG_CLR_E "%s\r\n" FURI_LOG_CLR_RESET, str); printf(FURI_LOG_CLR_E "%s\r\n" FURI_LOG_CLR_RESET, str);
} }
void unit_tests_cli_logs_puts(const char* str) {
printf(str);
}
// by default there is no output from unit tests
// you have to enable them with this function
void unit_tests_cli_enable_logs(FuriLogLevel logLevel) {
furi_log_init();
furi_log_set_level(logLevel);
furi_log_set_puts(unit_tests_cli_logs_puts);
}
void unit_tests_cli_print_help() {
printf(
"Usage:\r\n"
" unit_tests [log level] [test_suit_name]\r\n"
" Arguments:\r\n"
" [log level]: optional, enables printing output from FURI_LOG_* macro in unit_tests\r\n"
" [test_suit_name]: a specific test suit to run. If not specified runs all tests\r\n"
" Warning: supports only 1 test suit to launch\r\n"
" Example:\r\n"
" unit_tests - run ALL tests wihtout log printing\r\n"
" unit_tests bt - run bt tests wihtout log printing\r\n"
" unit_tests log debug subghz - run subghz tests with logs at debug level abd above\r\n\r\n"
" unit_tests help [?]\r\n"
" prints this help\r\n");
}
bool unit_tests_cli_parse_log_level(FuriString* args) {
bool result = true;
FuriString* level = furi_string_alloc();
if(args_read_string_and_trim(args, level)) {
if(furi_string_cmpi_str(level, "default") == 0) {
unit_tests_cli_enable_logs(FuriLogLevelDefault);
} else if(furi_string_cmpi_str(level, "none") == 0) {
unit_tests_cli_enable_logs(FuriLogLevelNone);
} else if(furi_string_cmpi_str(level, "error") == 0) {
unit_tests_cli_enable_logs(FuriLogLevelError);
} else if(furi_string_cmpi_str(level, "warn") == 0) {
unit_tests_cli_enable_logs(FuriLogLevelWarn);
} else if(furi_string_cmpi_str(level, "info") == 0) {
unit_tests_cli_enable_logs(FuriLogLevelInfo);
} else if(furi_string_cmpi_str(level, "debug") == 0) {
unit_tests_cli_enable_logs(FuriLogLevelDebug);
} else if(furi_string_cmpi_str(level, "trace") == 0) {
unit_tests_cli_enable_logs(FuriLogLevelTrace);
} else {
printf("Error: Invalid log level: %s\r\n", furi_string_get_cstr(level));
result = false;
}
}
furi_string_free(level);
return result;
}
FuriString* unit_tests_cli_parse_test_suit(FuriString* args) {
FuriString* test_suit = furi_string_alloc();
if(!args_read_string_and_trim(args, test_suit)) {
furi_string_free(test_suit);
return NULL;
}
return test_suit;
}
void unit_tests_cli(Cli* cli, FuriString* args, void* context) { void unit_tests_cli(Cli* cli, FuriString* args, void* context) {
UNUSED(cli); UNUSED(cli);
UNUSED(args); UNUSED(args);
@ -151,34 +82,6 @@ void unit_tests_cli(Cli* cli, FuriString* args, void* context) {
minunit_fail = 0; minunit_fail = 0;
minunit_status = 0; minunit_status = 0;
if(furi_string_cmp_str(args, "help") == 0 || furi_string_cmp_str(args, "?") == 0) {
unit_tests_cli_print_help();
return;
}
FuriString* test_suit_to_run = NULL;
if(furi_string_size(args)) {
FuriString* arg = furi_string_alloc();
if(args_read_string_and_trim(args, arg)) {
if(furi_string_cmp_str(arg, "log") == 0) {
// read next argument - log level, if fail - show help and return
if(!unit_tests_cli_parse_log_level(args)) {
unit_tests_cli_print_help();
furi_string_free(arg);
return;
}
// next argument might be test suit
test_suit_to_run = unit_tests_cli_parse_test_suit(args);
} else {
// if first argument wasn't log - it was exact test suit to run
test_suit_to_run = unit_tests_cli_parse_test_suit(arg);
}
}
furi_string_free(arg);
}
Loader* loader = furi_record_open(RECORD_LOADER); Loader* loader = furi_record_open(RECORD_LOADER);
NotificationApp* notification = furi_record_open(RECORD_NOTIFICATION); NotificationApp* notification = furi_record_open(RECORD_NOTIFICATION);
@ -197,8 +100,8 @@ void unit_tests_cli(Cli* cli, FuriString* args, void* context) {
break; break;
} }
if(test_suit_to_run) { if(furi_string_size(args)) {
if(furi_string_cmp_str(test_suit_to_run, unit_tests[i].name) == 0) { if(furi_string_cmp_str(args, unit_tests[i].name) == 0) {
unit_tests[i].entry(); unit_tests[i].entry();
} else { } else {
printf("Skipping %s\r\n", unit_tests[i].name); printf("Skipping %s\r\n", unit_tests[i].name);
@ -231,10 +134,6 @@ void unit_tests_cli(Cli* cli, FuriString* args, void* context) {
} }
} }
if(test_suit_to_run) {
furi_string_free(test_suit_to_run);
}
furi_record_close(RECORD_NOTIFICATION); furi_record_close(RECORD_NOTIFICATION);
furi_record_close(RECORD_LOADER); furi_record_close(RECORD_LOADER);
} }

View file

@ -1,5 +1,5 @@
App( App(
appid="sample_apps", appid="example_apps",
name="Sample apps bundle", name="Example apps bundle",
apptype=FlipperAppType.METAPACKAGE, apptype=FlipperAppType.METAPACKAGE,
) )

View file

@ -75,8 +75,8 @@ static const DuckyKey ducky_keys[] = {
{"BREAK", HID_KEYBOARD_PAUSE}, {"BREAK", HID_KEYBOARD_PAUSE},
{"PAUSE", HID_KEYBOARD_PAUSE}, {"PAUSE", HID_KEYBOARD_PAUSE},
{"CAPSLOCK", HID_KEYBOARD_CAPS_LOCK}, {"CAPSLOCK", HID_KEYBOARD_CAPS_LOCK},
{"DELETE", HID_KEYBOARD_DELETE}, {"DELETE", HID_KEYBOARD_DELETE_FORWARD},
{"BACKSPACE", HID_KEYPAD_BACKSPACE}, {"BACKSPACE", HID_KEYBOARD_DELETE},
{"END", HID_KEYBOARD_END}, {"END", HID_KEYBOARD_END},
{"ESC", HID_KEYBOARD_ESCAPE}, {"ESC", HID_KEYBOARD_ESCAPE},
{"ESCAPE", HID_KEYBOARD_ESCAPE}, {"ESCAPE", HID_KEYBOARD_ESCAPE},

View file

@ -39,11 +39,12 @@ static void clock_render_callback(Canvas* const canvas, void* ctx) {
} else { } else {
bool pm = curr_dt.hour > 12; bool pm = curr_dt.hour > 12;
bool pm12 = curr_dt.hour >= 12; bool pm12 = curr_dt.hour >= 12;
bool am12 = curr_dt.hour == 0;
snprintf( snprintf(
time_string, time_string,
TIME_LEN, TIME_LEN,
CLOCK_TIME_FORMAT, CLOCK_TIME_FORMAT,
pm ? curr_dt.hour - 12 : curr_dt.hour, pm ? curr_dt.hour - 12 : (am12 ? 12 : curr_dt.hour),
curr_dt.minute, curr_dt.minute,
curr_dt.second); curr_dt.second);
@ -237,4 +238,4 @@ int32_t clock_app(void* p) {
free(plugin_state); free(plugin_state);
return 0; return 0;
} }

View file

@ -14,9 +14,12 @@ static const char* uart_ch[] = {"13,14", "15,16"};
static const char* flow_pins[] = {"None", "2,3", "6,7", "16,15"}; static const char* flow_pins[] = {"None", "2,3", "6,7", "16,15"};
static const char* baudrate_mode[] = {"Host"}; static const char* baudrate_mode[] = {"Host"};
static const uint32_t baudrate_list[] = { static const uint32_t baudrate_list[] = {
1200,
2400, 2400,
4800,
9600, 9600,
19200, 19200,
28800,
38400, 38400,
57600, 57600,
115200, 115200,

View file

@ -295,6 +295,6 @@ void infrared_signal_transmit(InfraredSignal* signal) {
raw_signal->duty_cycle); raw_signal->duty_cycle);
} else { } else {
InfraredMessage* message = &signal->payload.message; InfraredMessage* message = &signal->payload.message;
infrared_send(message, 2); infrared_send(message, 1);
} }
} }

View file

@ -3,6 +3,7 @@
enum SubmenuIndex { enum SubmenuIndex {
SubmenuIndexUniversalRemotes, SubmenuIndexUniversalRemotes,
SubmenuIndexLearnNewRemote, SubmenuIndexLearnNewRemote,
SubmenuIndexLearnNewRemoteRaw,
SubmenuIndexSavedRemotes, SubmenuIndexSavedRemotes,
SubmenuIndexDebug SubmenuIndexDebug
}; };
@ -37,6 +38,12 @@ void infrared_scene_start_on_enter(void* context) {
infrared); infrared);
if(infrared->app_state.is_debug_enabled) { if(infrared->app_state.is_debug_enabled) {
submenu_add_item(
submenu,
"Learn New Remote RAW",
SubmenuIndexLearnNewRemoteRaw,
infrared_scene_start_submenu_callback,
infrared);
submenu_add_item( submenu_add_item(
submenu, "Debug", SubmenuIndexDebug, infrared_scene_start_submenu_callback, infrared); submenu, "Debug", SubmenuIndexDebug, infrared_scene_start_submenu_callback, infrared);
} }
@ -61,7 +68,15 @@ bool infrared_scene_start_on_event(void* context, SceneManagerEvent event) {
if(submenu_index == SubmenuIndexUniversalRemotes) { if(submenu_index == SubmenuIndexUniversalRemotes) {
scene_manager_next_scene(scene_manager, InfraredSceneUniversal); scene_manager_next_scene(scene_manager, InfraredSceneUniversal);
consumed = true; consumed = true;
} else if(submenu_index == SubmenuIndexLearnNewRemote) { } else if(
submenu_index == SubmenuIndexLearnNewRemote ||
submenu_index == SubmenuIndexLearnNewRemoteRaw) {
// enable automatic signal decoding if "Learn New Remote"
// disable automatic signal decoding if "Learn New Remote (RAW)"
infrared_worker_rx_enable_signal_decoding(
infrared->worker, submenu_index == SubmenuIndexLearnNewRemote);
infrared->app_state.is_learning_new_remote = true; infrared->app_state.is_learning_new_remote = true;
scene_manager_next_scene(scene_manager, InfraredSceneLearn); scene_manager_next_scene(scene_manager, InfraredSceneLearn);
consumed = true; consumed = true;

View file

@ -50,7 +50,6 @@ typedef enum {
SubGhzCustomEventSceneAnalyzerLock, SubGhzCustomEventSceneAnalyzerLock,
SubGhzCustomEventSceneAnalyzerUnlock, SubGhzCustomEventSceneAnalyzerUnlock,
SubGhzCustomEventSceneSettingLock, SubGhzCustomEventSceneSettingLock,
SubGhzCustomEventSceneSettingError,
SubGhzCustomEventSceneExit, SubGhzCustomEventSceneExit,
SubGhzCustomEventSceneStay, SubGhzCustomEventSceneStay,

View file

@ -45,35 +45,6 @@ const float raw_theshold_rssi_value[RAW_THRESHOLD_RSSI_COUNT] = {
-40.0f, -40.0f,
}; };
#define BANDWIDTH_COUNT 16
const char* const bandwidth_labels[BANDWIDTH_COUNT] = {
"58 kHz",
"68 kHz",
"81 kHz",
"102 kHz",
"116 kHz",
"135 kHz",
"162 kHz",
"203 kHz",
"232 kHz",
"270 kHz",
"325 kHz",
"406 kHz",
"464 kHz",
"541 kHz",
"650 kHz",
"812 kHz",
};
// Bandwidths values are ordered from F (58kHz) to 0 (812kHz)
#define BANDWIDTH_INDEX(value) ((uint8_t)15 - ((uint8_t)(value >> 4) & 0x0F))
#define MANCHESTER_FLAG_COUNT 2
const char* const manchester_flag_text[MANCHESTER_FLAG_COUNT] = {
"OFF",
"ON",
};
#define HOPPING_COUNT 2 #define HOPPING_COUNT 2
const char* const hopping_text[HOPPING_COUNT] = { const char* const hopping_text[HOPPING_COUNT] = {
"OFF", "OFF",
@ -128,18 +99,6 @@ const uint32_t speaker_value[SPEAKER_COUNT] = {
SubGhzSpeakerStateEnable, SubGhzSpeakerStateEnable,
}; };
// Allow advanced edit only on specific preset
bool subghz_scene_receiver_config_can_edit_current_preset(SubGhz* subghz) {
SubGhzRadioPreset* preset = subghz->txrx->preset;
bool preset_name_allow_edit =
!strcmp(furi_string_get_cstr(preset->name), ADVANCED_AM_PRESET_NAME) ||
!strcmp(furi_string_get_cstr(preset->name), "CUSTOM");
return preset && preset_name_allow_edit &&
subghz_preset_custom_is_ook_modulation(preset->data, preset->data_size);
}
uint8_t subghz_scene_receiver_config_next_frequency(const uint32_t value, void* context) { uint8_t subghz_scene_receiver_config_next_frequency(const uint32_t value, void* context) {
furi_assert(context); furi_assert(context);
SubGhz* subghz = context; SubGhz* subghz = context;
@ -170,52 +129,6 @@ uint8_t subghz_scene_receiver_config_next_preset(const char* preset_name, void*
return index; return index;
} }
// Advanced settings of preset may change if preset was changed.
// In that case - update values
static void subghz_scene_receiver_config_update_advanced(SubGhz* subghz) {
uint8_t value_index;
if(subghz->variable_item_bandwidth) {
value_index = BANDWIDTH_INDEX(subghz->txrx->raw_bandwidth);
variable_item_set_current_value_index(subghz->variable_item_bandwidth, value_index);
variable_item_set_current_value_text(
subghz->variable_item_bandwidth, bandwidth_labels[value_index]);
}
if(subghz->variable_item_datarate) {
variable_item_set_current_value_index(subghz->variable_item_datarate, 0);
char datarate_str[16] = {0};
subghz_preset_custom_printf_datarate(
subghz->txrx->raw_datarate, datarate_str, sizeof(datarate_str));
variable_item_set_current_value_text(subghz->variable_item_datarate, datarate_str);
}
if(subghz->variable_item_manchester) {
value_index = subghz->txrx->raw_manchester_enabled ? 1 : 0;
variable_item_set_current_value_index(subghz->variable_item_manchester, value_index);
variable_item_set_current_value_text(
subghz->variable_item_manchester, manchester_flag_text[value_index]);
}
}
// Apply advanced configuration to advanced am preset
static void subghz_scene_receiver_config_apply_advanced(SubGhz* subghz) {
if(subghz_scene_receiver_config_can_edit_current_preset(subghz)) {
SubGhzRadioPreset* preset = subghz->txrx->preset;
subghz_preset_custom_set_bandwidth(
preset->data, preset->data_size, subghz->txrx->raw_bandwidth);
subghz_preset_custom_set_machester_enable(
preset->data, preset->data_size, subghz->txrx->raw_manchester_enabled);
subghz_preset_custom_set_datarate(
preset->data, preset->data_size, subghz->txrx->raw_datarate);
}
}
uint8_t subghz_scene_receiver_config_hopper_value_index( uint8_t subghz_scene_receiver_config_hopper_value_index(
const uint32_t value, const uint32_t value,
const uint32_t values[], const uint32_t values[],
@ -301,8 +214,6 @@ static void subghz_scene_receiver_config_set_preset(VariableItem* item) {
subghz->txrx->preset->frequency, subghz->txrx->preset->frequency,
subghz_setting_get_preset_data(subghz->setting, index), subghz_setting_get_preset_data(subghz->setting, index),
subghz_setting_get_preset_data_size(subghz->setting, index)); subghz_setting_get_preset_data_size(subghz->setting, index));
subghz_scene_receiver_config_update_advanced(subghz);
} }
static void subghz_scene_receiver_config_set_rssi_threshold(VariableItem* item) { static void subghz_scene_receiver_config_set_rssi_threshold(VariableItem* item) {
@ -396,107 +307,6 @@ static void subghz_scene_receiver_config_set_raw_threshold_rssi(VariableItem* it
subghz->txrx->raw_threshold_rssi = raw_theshold_rssi_value[index]; subghz->txrx->raw_threshold_rssi = raw_theshold_rssi_value[index];
} }
static void subghz_scene_receiver_config_set_raw_ook_bandwidth(VariableItem* item) {
SubGhz* subghz = variable_item_get_context(item);
if(subghz_scene_receiver_config_can_edit_current_preset(subghz)) {
// update bandwidth value from selected index
uint8_t index = variable_item_get_current_value_index(item);
subghz->txrx->raw_bandwidth = subghz_preset_custom_bandwidth_values[index];
subghz_scene_receiver_config_update_advanced(subghz);
} else {
furi_string_set(
subghz->error_str, "Read-only\nsetting!\nUse '" ADVANCED_AM_PRESET_NAME "'\npreset.");
view_dispatcher_send_custom_event(
subghz->view_dispatcher, SubGhzCustomEventSceneSettingError);
}
}
static void subghz_scene_receiver_config_set_manchester_flag(VariableItem* item) {
SubGhz* subghz = variable_item_get_context(item);
if(subghz_scene_receiver_config_can_edit_current_preset(subghz)) {
// update enable flag from view
uint8_t index = variable_item_get_current_value_index(item);
subghz->txrx->raw_manchester_enabled = index == 0 ? false : true;
subghz_scene_receiver_config_update_advanced(subghz);
} else {
furi_string_set(
subghz->error_str, "Read-only\nsetting!\nUse '" ADVANCED_AM_PRESET_NAME "'\npreset.");
view_dispatcher_send_custom_event(
subghz->view_dispatcher, SubGhzCustomEventSceneSettingError);
}
}
static void subghz_scene_receiver_config_datarate_input_callback(void* context) {
furi_assert(context);
SubGhz* subghz = context;
float value = atoff(subghz->datarate_input_str);
if(value != 0 && value > 0) {
subghz->txrx->raw_datarate = value;
subghz_scene_receiver_config_update_advanced(subghz);
}
// show list view
view_dispatcher_switch_to_view(subghz->view_dispatcher, SubGhzViewIdVariableItemList);
}
static bool subghz_scene_receiver_config_datarate_input_validate(
const char* text,
FuriString* error,
void* context) {
UNUSED(context);
float value = atoff(text);
if(value == 0) {
furi_string_printf(error, "Cannot parse\r\nvalue");
} else if(value < 0) {
furi_string_printf(error, "Value\r\nshould be\r\ngreater\r\nthan 0");
} else {
return true;
}
return false;
}
static void subghz_scene_receiver_config_show_datarate_input(SubGhz* subghz) {
TextInput* text_input = subghz->text_input;
snprintf(
subghz->datarate_input_str,
sizeof(subghz->datarate_input_str),
"%.2f",
(double)subghz->txrx->raw_datarate);
text_input_set_header_text(text_input, "Datarate bauds (not kBauds)");
text_input_set_result_callback(
text_input,
subghz_scene_receiver_config_datarate_input_callback,
subghz,
subghz->datarate_input_str,
sizeof(subghz->datarate_input_str),
false);
text_input_set_validator(
text_input, subghz_scene_receiver_config_datarate_input_validate, NULL);
view_dispatcher_switch_to_view(subghz->view_dispatcher, SubGhzViewIdTextInput);
}
static void subghz_scene_receiver_config_set_datarate(VariableItem* item) {
SubGhz* subghz = variable_item_get_context(item);
if(subghz_scene_receiver_config_can_edit_current_preset(subghz)) {
// reset value index in order to show '>' symbol always
variable_item_set_current_value_index(item, 0);
subghz_scene_receiver_config_show_datarate_input(subghz);
} else {
furi_string_set(
subghz->error_str, "Read-only\nsetting!\nUse '" ADVANCED_AM_PRESET_NAME "'\npreset.");
view_dispatcher_send_custom_event(
subghz->view_dispatcher, SubGhzCustomEventSceneSettingError);
}
}
static void subghz_scene_receiver_config_var_list_enter_callback(void* context, uint32_t index) { static void subghz_scene_receiver_config_var_list_enter_callback(void* context, uint32_t index) {
furi_assert(context); furi_assert(context);
SubGhz* subghz = context; SubGhz* subghz = context;
@ -627,33 +437,6 @@ void subghz_scene_receiver_config_on_enter(void* context) {
subghz->txrx->raw_threshold_rssi, raw_theshold_rssi_value, RAW_THRESHOLD_RSSI_COUNT); subghz->txrx->raw_threshold_rssi, raw_theshold_rssi_value, RAW_THRESHOLD_RSSI_COUNT);
variable_item_set_current_value_index(item, value_index); variable_item_set_current_value_index(item, value_index);
variable_item_set_current_value_text(item, raw_theshold_rssi_text[value_index]); variable_item_set_current_value_text(item, raw_theshold_rssi_text[value_index]);
// Advanced MODEM settings. RW only for ADVANCED_AM_PRESET_NAME
// Bandwidth
subghz->variable_item_bandwidth = variable_item_list_add(
subghz->variable_item_list,
"Bandwidth:",
BANDWIDTH_COUNT,
subghz_scene_receiver_config_set_raw_ook_bandwidth,
subghz);
// Data rate (editable via OK click)
subghz->variable_item_datarate = variable_item_list_add(
subghz->variable_item_list,
"Data rate:",
2,
subghz_scene_receiver_config_set_datarate,
subghz);
// Manchester codec flag
subghz->variable_item_manchester = variable_item_list_add(
subghz->variable_item_list,
"Manch. Enc.:",
MANCHESTER_FLAG_COUNT,
subghz_scene_receiver_config_set_manchester_flag,
subghz);
subghz_scene_receiver_config_update_advanced(subghz);
} }
view_dispatcher_switch_to_view(subghz->view_dispatcher, SubGhzViewIdVariableItemList); view_dispatcher_switch_to_view(subghz->view_dispatcher, SubGhzViewIdVariableItemList);
} }
@ -667,11 +450,6 @@ bool subghz_scene_receiver_config_on_event(void* context, SceneManagerEvent even
subghz->lock = SubGhzLockOn; subghz->lock = SubGhzLockOn;
scene_manager_previous_scene(subghz->scene_manager); scene_manager_previous_scene(subghz->scene_manager);
consumed = true; consumed = true;
} else if(event.event == SubGhzCustomEventSceneSettingError) {
scene_manager_next_scene(subghz->scene_manager, SubGhzSceneShowErrorSub);
scene_manager_set_scene_state(
subghz->scene_manager, SubGhzSceneShowErrorSub, event.event);
consumed = true;
} }
} }
return consumed; return consumed;
@ -679,16 +457,6 @@ bool subghz_scene_receiver_config_on_event(void* context, SceneManagerEvent even
void subghz_scene_receiver_config_on_exit(void* context) { void subghz_scene_receiver_config_on_exit(void* context) {
SubGhz* subghz = context; SubGhz* subghz = context;
// reset UI variable list items (next scene may be not RAW config)
subghz->variable_item_bandwidth = NULL;
subghz->variable_item_datarate = NULL;
subghz->variable_item_manchester = NULL;
text_input_set_validator(subghz->text_input, NULL, NULL);
// apply advanced preset variables (if applicable)
subghz_scene_receiver_config_apply_advanced(subghz);
variable_item_list_set_selected_item(subghz->variable_item_list, 0); variable_item_list_set_selected_item(subghz->variable_item_list, 0);
variable_item_list_reset(subghz->variable_item_list); variable_item_list_reset(subghz->variable_item_list);
subghz_last_settings_save(subghz->last_settings); subghz_last_settings_save(subghz->last_settings);

View file

@ -26,16 +26,8 @@ bool subghz_scene_show_error_sub_on_event(void* context, SceneManagerEvent event
SubGhz* subghz = context; SubGhz* subghz = context;
if(event.type == SceneManagerEventTypeCustom) { if(event.type == SceneManagerEventTypeCustom) {
if(event.event == SubGhzCustomEventSceneShowErrorSub) { if(event.event == SubGhzCustomEventSceneShowErrorSub) {
if(scene_manager_get_scene_state(subghz->scene_manager, SubGhzSceneShowErrorSub) == scene_manager_search_and_switch_to_previous_scene(
SubGhzCustomEventSceneSettingError) { subghz->scene_manager, SubGhzSceneStart);
scene_manager_set_scene_state(
subghz->scene_manager, SubGhzSceneReadRAW, SubGhzCustomEventManagerSet);
scene_manager_search_and_switch_to_previous_scene(
subghz->scene_manager, SubGhzSceneReceiverConfig);
} else {
scene_manager_search_and_switch_to_previous_scene(
subghz->scene_manager, SubGhzSceneStart);
}
return true; return true;
} }
} }

View file

@ -12,25 +12,6 @@ enum SubmenuIndex {
SubmenuIndexReadRAW, SubmenuIndexReadRAW,
}; };
void subghz_scene_start_remove_advanced_preset(SubGhz* subghz) {
// delete operation is harmless
subghz_setting_delete_custom_preset(subghz->setting, ADVANCED_AM_PRESET_NAME);
}
void subghz_scene_start_load_advanced_preset(SubGhz* subghz) {
for(uint8_t i = 0; i < subghz_setting_get_preset_count(subghz->setting); i++) {
if(!strcmp(subghz_setting_get_preset_name(subghz->setting, i), ADVANCED_AM_PRESET_NAME)) {
return; // already exists
}
}
// Load custom advanced AM preset with configurable CFGMDM settings
FlipperFormat* advanced_am_preset = subghz_preset_custom_advanced_am_preset_alloc();
subghz_setting_load_custom_preset(
subghz->setting, ADVANCED_AM_PRESET_NAME, advanced_am_preset);
flipper_format_free(advanced_am_preset);
}
void subghz_scene_start_submenu_callback(void* context, uint32_t index) { void subghz_scene_start_submenu_callback(void* context, uint32_t index) {
SubGhz* subghz = context; SubGhz* subghz = context;
view_dispatcher_send_custom_event(subghz->view_dispatcher, index); view_dispatcher_send_custom_event(subghz->view_dispatcher, index);
@ -92,14 +73,12 @@ bool subghz_scene_start_on_event(void* context, SceneManagerEvent event) {
return true; return true;
} else if(event.type == SceneManagerEventTypeCustom) { } else if(event.type == SceneManagerEventTypeCustom) {
if(event.event == SubmenuIndexReadRAW) { if(event.event == SubmenuIndexReadRAW) {
subghz_scene_start_load_advanced_preset(subghz);
scene_manager_set_scene_state( scene_manager_set_scene_state(
subghz->scene_manager, SubGhzSceneStart, SubmenuIndexReadRAW); subghz->scene_manager, SubGhzSceneStart, SubmenuIndexReadRAW);
subghz->txrx->rx_key_state = SubGhzRxKeyStateIDLE; subghz->txrx->rx_key_state = SubGhzRxKeyStateIDLE;
scene_manager_next_scene(subghz->scene_manager, SubGhzSceneReadRAW); scene_manager_next_scene(subghz->scene_manager, SubGhzSceneReadRAW);
return true; return true;
} else if(event.event == SubmenuIndexRead) { } else if(event.event == SubmenuIndexRead) {
subghz_scene_start_remove_advanced_preset(subghz);
scene_manager_set_scene_state( scene_manager_set_scene_state(
subghz->scene_manager, SubGhzSceneStart, SubmenuIndexRead); subghz->scene_manager, SubGhzSceneStart, SubmenuIndexRead);
scene_manager_next_scene(subghz->scene_manager, SubGhzSceneReceiver); scene_manager_next_scene(subghz->scene_manager, SubGhzSceneReceiver);

View file

@ -30,12 +30,6 @@ void subghz_preset_init(
subghz->txrx->preset->frequency = frequency; subghz->txrx->preset->frequency = frequency;
subghz->txrx->preset->data = preset_data; subghz->txrx->preset->data = preset_data;
subghz->txrx->preset->data_size = preset_data_size; subghz->txrx->preset->data_size = preset_data_size;
subghz->txrx->raw_bandwidth =
subghz_preset_custom_get_bandwidth(preset_data, preset_data_size);
subghz->txrx->raw_manchester_enabled =
subghz_preset_custom_get_machester_enable(preset_data, preset_data_size);
subghz->txrx->raw_datarate = subghz_preset_custom_get_datarate(preset_data, preset_data_size);
} }
bool subghz_set_preset(SubGhz* subghz, const char* preset) { bool subghz_set_preset(SubGhz* subghz, const char* preset) {

View file

@ -3,7 +3,6 @@
#include "helpers/subghz_types.h" #include "helpers/subghz_types.h"
#include "helpers/subghz_error_type.h" #include "helpers/subghz_error_type.h"
#include <lib/subghz/types.h> #include <lib/subghz/types.h>
#include <lib/subghz/helpers/subghz_config_preset_custom.h>
#include "subghz.h" #include "subghz.h"
#include "views/receiver.h" #include "views/receiver.h"
#include "views/transmitter.h" #include "views/transmitter.h"
@ -79,13 +78,6 @@ struct SubGhzTxRx {
float raw_threshold_rssi; float raw_threshold_rssi;
uint8_t raw_threshold_rssi_low_count; uint8_t raw_threshold_rssi_low_count;
// one of the 16 possible bandwidth values
uint8_t raw_bandwidth;
// datarate in bauds
float raw_datarate;
// flag if manchester encoding/decoding enabled
bool raw_manchester_enabled;
}; };
typedef struct SubGhzTxRx SubGhzTxRx; typedef struct SubGhzTxRx SubGhzTxRx;
@ -114,13 +106,6 @@ struct SubGhz {
SubGhzViewTransmitter* subghz_transmitter; SubGhzViewTransmitter* subghz_transmitter;
VariableItemList* variable_item_list; VariableItemList* variable_item_list;
// Advanced config items
VariableItem* variable_item_bandwidth; // specific config list view item: bandwidth
VariableItem* variable_item_datarate; // specific config list view item: data rate
VariableItem* variable_item_manchester; // specific config list view item: manchester enc flag
// Advanced config strings
char datarate_input_str[16];
SubGhzFrequencyAnalyzer* subghz_frequency_analyzer; SubGhzFrequencyAnalyzer* subghz_frequency_analyzer;
SubGhzReadRAW* subghz_read_raw; SubGhzReadRAW* subghz_read_raw;
bool raw_send_only; bool raw_send_only;

View file

@ -36,6 +36,13 @@
#define MIN_PIN_SIZE 4 #define MIN_PIN_SIZE 4
#define MAX_APP_LENGTH 128 #define MAX_APP_LENGTH 128
#define DISPLAY_BATTERY_BAR 0
#define DISPLAY_BATTERY_PERCENT 1
#define DISPLAY_BATTERY_INVERTED_PERCENT 2
#define DISPLAY_BATTERY_RETRO_3 3
#define DISPLAY_BATTERY_RETRO_5 4
#define DISPLAY_BATTERY_BAR_PERCENT 5
#define FAP_LOADER_APP_NAME "Applications" #define FAP_LOADER_APP_NAME "Applications"
typedef struct { typedef struct {

View file

@ -56,7 +56,7 @@ static bool desktop_view_slideshow_input(InputEvent* event, void* context) {
instance->callback(DesktopSlideshowCompleted, instance->context); instance->callback(DesktopSlideshowCompleted, instance->context);
} }
update_view = true; update_view = true;
} else if(event->key == InputKeyOk) { } else if(event->key == InputKeyOk && instance->timer) {
if(event->type == InputTypePress) { if(event->type == InputTypePress) {
furi_timer_start(instance->timer, DESKTOP_SLIDESHOW_POWEROFF_SHORT); furi_timer_start(instance->timer, DESKTOP_SLIDESHOW_POWEROFF_SHORT);
} else if(event->type == InputTypeRelease) { } else if(event->type == InputTypeRelease) {

View file

@ -178,6 +178,47 @@ static void button_menu_process_down(ButtonMenu* button_menu) {
true); true);
} }
static void button_menu_process_right(ButtonMenu* button_menu) {
furi_assert(button_menu);
with_view_model(
button_menu->view,
ButtonMenuModel * model,
{
if(ButtonMenuItemArray_size(model->items) > BUTTONS_PER_SCREEN) {
size_t position_candidate = model->position + BUTTONS_PER_SCREEN;
position_candidate -= position_candidate % BUTTONS_PER_SCREEN;
if(position_candidate < (ButtonMenuItemArray_size(model->items))) {
model->position = position_candidate;
} else {
model->position = 0;
}
}
},
true);
}
static void button_menu_process_left(ButtonMenu* button_menu) {
furi_assert(button_menu);
with_view_model(
button_menu->view,
ButtonMenuModel * model,
{
if(ButtonMenuItemArray_size(model->items) > BUTTONS_PER_SCREEN) {
size_t position_candidate;
if(model->position < BUTTONS_PER_SCREEN) {
position_candidate = (ButtonMenuItemArray_size(model->items) - 1);
} else {
position_candidate = model->position - BUTTONS_PER_SCREEN;
};
position_candidate -= position_candidate % BUTTONS_PER_SCREEN;
model->position = position_candidate;
}
},
true);
}
static void button_menu_process_ok(ButtonMenu* button_menu, InputType type) { static void button_menu_process_ok(ButtonMenu* button_menu, InputType type) {
furi_assert(button_menu); furi_assert(button_menu);
@ -239,6 +280,14 @@ static bool button_menu_view_input_callback(InputEvent* event, void* context) {
consumed = true; consumed = true;
button_menu_process_down(button_menu); button_menu_process_down(button_menu);
break; break;
case InputKeyRight:
consumed = true;
button_menu_process_right(button_menu);
break;
case InputKeyLeft:
consumed = true;
button_menu_process_left(button_menu);
break;
default: default:
break; break;
} }

View file

@ -29,7 +29,7 @@ typedef struct {
TextInputValidatorCallback validator_callback; TextInputValidatorCallback validator_callback;
void* validator_callback_context; void* validator_callback_context;
FuriString* validator_text; FuriString* validator_text;
bool valadator_message_visible; bool validator_message_visible;
} TextInputModel; } TextInputModel;
static const uint8_t keyboard_origin_x = 1; static const uint8_t keyboard_origin_x = 1;
@ -138,7 +138,7 @@ static bool char_is_lowercase(char letter) {
static char char_to_uppercase(const char letter) { static char char_to_uppercase(const char letter) {
if(letter == '_') { if(letter == '_') {
return 0x20; return 0x20;
} else if(isalpha(letter)) { } else if(islower(letter)) {
return (letter - 0x20); return (letter - 0x20);
} else { } else {
return letter; return letter;
@ -254,7 +254,7 @@ static void text_input_view_draw_callback(Canvas* canvas, void* _model) {
} }
} }
} }
if(model->valadator_message_visible) { if(model->validator_message_visible) {
canvas_set_font(canvas, FontSecondary); canvas_set_font(canvas, FontSecondary);
canvas_set_color(canvas, ColorWhite); canvas_set_color(canvas, ColorWhite);
canvas_draw_box(canvas, 8, 10, 110, 48); canvas_draw_box(canvas, 8, 10, 110, 48);
@ -309,7 +309,9 @@ static void text_input_handle_ok(TextInput* text_input, TextInputModel* model, b
char selected = get_selected_char(model); char selected = get_selected_char(model);
size_t text_length = strlen(model->text_buffer); size_t text_length = strlen(model->text_buffer);
if(shift) { bool toogle_case = text_length == 0;
if(shift) toogle_case = !toogle_case;
if(toogle_case) {
selected = char_to_uppercase(selected); selected = char_to_uppercase(selected);
} }
@ -317,7 +319,7 @@ static void text_input_handle_ok(TextInput* text_input, TextInputModel* model, b
if(model->validator_callback && if(model->validator_callback &&
(!model->validator_callback( (!model->validator_callback(
model->text_buffer, model->validator_text, model->validator_callback_context))) { model->text_buffer, model->validator_text, model->validator_callback_context))) {
model->valadator_message_visible = true; model->validator_message_visible = true;
furi_timer_start(text_input->timer, furi_kernel_get_tick_frequency() * 4); furi_timer_start(text_input->timer, furi_kernel_get_tick_frequency() * 4);
} else if(model->callback != 0 && text_length > 0) { } else if(model->callback != 0 && text_length > 0) {
model->callback(model->callback_context); model->callback(model->callback_context);
@ -329,9 +331,6 @@ static void text_input_handle_ok(TextInput* text_input, TextInputModel* model, b
text_length = 0; text_length = 0;
} }
if(text_length < (model->text_buffer_size - 1)) { if(text_length < (model->text_buffer_size - 1)) {
if(text_length == 0 && char_is_lowercase(selected)) {
selected = char_to_uppercase(selected);
}
model->text_buffer[text_length] = selected; model->text_buffer[text_length] = selected;
model->text_buffer[text_length + 1] = 0; model->text_buffer[text_length + 1] = 0;
} }
@ -349,8 +348,8 @@ static bool text_input_view_input_callback(InputEvent* event, void* context) {
TextInputModel* model = view_get_model(text_input->view); TextInputModel* model = view_get_model(text_input->view);
if((!(event->type == InputTypePress) && !(event->type == InputTypeRelease)) && if((!(event->type == InputTypePress) && !(event->type == InputTypeRelease)) &&
model->valadator_message_visible) { model->validator_message_visible) {
model->valadator_message_visible = false; model->validator_message_visible = false;
consumed = true; consumed = true;
} else if(event->type == InputTypeShort) { } else if(event->type == InputTypeShort) {
consumed = true; consumed = true;
@ -436,7 +435,7 @@ void text_input_timer_callback(void* context) {
with_view_model( with_view_model(
text_input->view, text_input->view,
TextInputModel * model, TextInputModel * model,
{ model->valadator_message_visible = false; }, { model->validator_message_visible = false; },
true); true);
} }
@ -496,7 +495,7 @@ void text_input_reset(TextInput* text_input) {
model->validator_callback = NULL; model->validator_callback = NULL;
model->validator_callback_context = NULL; model->validator_callback_context = NULL;
furi_string_reset(model->validator_text); furi_string_reset(model->validator_text);
model->valadator_message_visible = false; model->validator_message_visible = false;
}, },
true); true);
} }

View file

@ -91,7 +91,7 @@ void widget_add_string_element(
* @param[in] text Formatted text. The following formats are available: * @param[in] text Formatted text. The following formats are available:
* "\e#Bold text\e#" - bold font is used * "\e#Bold text\e#" - bold font is used
* "\e*Monospaced text\e*" - monospaced font is used * "\e*Monospaced text\e*" - monospaced font is used
* "\e#Inversed text\e#" - white text on black background * "\e!Inversed text\e!" - white text on black background
* @param strip_to_dots Strip text to ... if does not fit to width * @param strip_to_dots Strip text to ... if does not fit to width
*/ */
void widget_add_text_box_element( void widget_add_text_box_element(

View file

@ -19,7 +19,7 @@ extern "C" {
typedef enum { typedef enum {
InputTypePress, /**< Press event, emitted after debounce */ InputTypePress, /**< Press event, emitted after debounce */
InputTypeRelease, /**< Release event, emitted after debounce */ InputTypeRelease, /**< Release event, emitted after debounce */
InputTypeShort, /**< Short event, emitted after InputTypeRelease done withing INPUT_LONG_PRESS interval */ InputTypeShort, /**< Short event, emitted after InputTypeRelease done within INPUT_LONG_PRESS interval */
InputTypeLong, /**< Long event, emitted after INPUT_LONG_PRESS_COUNTS interval, asynchronous to InputTypeRelease */ InputTypeLong, /**< Long event, emitted after INPUT_LONG_PRESS_COUNTS interval, asynchronous to InputTypeRelease */
InputTypeRepeat, /**< Repeat event, emitted with INPUT_LONG_PRESS_COUNTS period after InputTypeLong event */ InputTypeRepeat, /**< Repeat event, emitted with INPUT_LONG_PRESS_COUNTS period after InputTypeLong event */
InputTypeMAX, /**< Special value for exceptional */ InputTypeMAX, /**< Special value for exceptional */

View file

@ -1,5 +1,5 @@
#include "power_i.h"
#include "desktop/desktop_settings.h" #include "desktop/desktop_settings.h"
#include "power_i.h"
#include <furi.h> #include <furi.h>
#include <furi_hal.h> #include <furi_hal.h>
@ -14,7 +14,7 @@ void power_draw_battery_callback(Canvas* canvas, void* context) {
if(power->info.gauge_is_ok) { if(power->info.gauge_is_ok) {
char batteryPercentile[4]; char batteryPercentile[4];
snprintf(batteryPercentile, sizeof(batteryPercentile), "%d", power->info.charge); snprintf(batteryPercentile, sizeof(batteryPercentile), "%d", power->info.charge);
if((power->displayBatteryPercentage == 1) && if((power->displayBatteryPercentage == DISPLAY_BATTERY_PERCENT) &&
(power->state != (power->state !=
PowerStateCharging)) { //if display battery percentage, black background white text PowerStateCharging)) { //if display battery percentage, black background white text
canvas_set_font(canvas, FontBatteryPercent); canvas_set_font(canvas, FontBatteryPercent);
@ -23,14 +23,14 @@ void power_draw_battery_callback(Canvas* canvas, void* context) {
canvas_set_color(canvas, ColorWhite); canvas_set_color(canvas, ColorWhite);
canvas_draw_str_aligned(canvas, 11, 4, AlignCenter, AlignCenter, batteryPercentile); canvas_draw_str_aligned(canvas, 11, 4, AlignCenter, AlignCenter, batteryPercentile);
} else if( } else if(
(power->displayBatteryPercentage == 2) && (power->displayBatteryPercentage == DISPLAY_BATTERY_INVERTED_PERCENT) &&
(power->state != (power->state !=
PowerStateCharging)) { //if display inverted percentage, white background black text PowerStateCharging)) { //if display inverted percentage, white background black text
canvas_set_font(canvas, FontBatteryPercent); canvas_set_font(canvas, FontBatteryPercent);
canvas_set_color(canvas, ColorBlack); canvas_set_color(canvas, ColorBlack);
canvas_draw_str_aligned(canvas, 11, 4, AlignCenter, AlignCenter, batteryPercentile); canvas_draw_str_aligned(canvas, 11, 4, AlignCenter, AlignCenter, batteryPercentile);
} else if( } else if(
(power->displayBatteryPercentage == 3) && (power->displayBatteryPercentage == DISPLAY_BATTERY_RETRO_3) &&
(power->state != PowerStateCharging)) { //Retro style segmented display, 3 parts (power->state != PowerStateCharging)) { //Retro style segmented display, 3 parts
if(power->info.charge > 25) { if(power->info.charge > 25) {
canvas_draw_box(canvas, 2, 2, 6, 4); canvas_draw_box(canvas, 2, 2, 6, 4);
@ -42,7 +42,7 @@ void power_draw_battery_callback(Canvas* canvas, void* context) {
canvas_draw_box(canvas, 16, 2, 6, 4); canvas_draw_box(canvas, 16, 2, 6, 4);
} }
} else if( } else if(
(power->displayBatteryPercentage == 4) && (power->displayBatteryPercentage == DISPLAY_BATTERY_RETRO_5) &&
(power->state != PowerStateCharging)) { //Retro style segmented display, 5 parts (power->state != PowerStateCharging)) { //Retro style segmented display, 5 parts
if(power->info.charge > 10) { if(power->info.charge > 10) {
canvas_draw_box(canvas, 2, 2, 3, 4); canvas_draw_box(canvas, 2, 2, 3, 4);
@ -59,6 +59,58 @@ void power_draw_battery_callback(Canvas* canvas, void* context) {
if(power->info.charge > 90) { if(power->info.charge > 90) {
canvas_draw_box(canvas, 18, 2, 3, 4); canvas_draw_box(canvas, 18, 2, 3, 4);
} }
} else if(
(power->displayBatteryPercentage == DISPLAY_BATTERY_BAR_PERCENT) &&
(power->state != PowerStateCharging) && // Default bar display with percentage
(power->info.voltage_battery_charging >= 4.2)) { // not looking nice with low voltage indicator
canvas_set_font(canvas, FontBatteryPercent);
// align charge dispaly value with digits to draw
uint8_t bar_charge = power->info.charge;
if(bar_charge > 23 && bar_charge < 38) {
bar_charge = 23;
} else if(bar_charge >= 38 && bar_charge < 62) {
bar_charge = 50;
} else if(bar_charge >= 62 && bar_charge < 74) {
bar_charge = 74;
}
// drawing digits
canvas_set_color(canvas, ColorBlack);
canvas_draw_box(canvas, 1, 1, (bar_charge * 22) / 100, 6);
if(bar_charge < 38) { // both digits are black
canvas_set_color(canvas, ColorBlack);
canvas_draw_str_aligned(
canvas, 11, 4, AlignCenter, AlignCenter, batteryPercentile);
} else if(bar_charge >= 38 && bar_charge < 74) { // first digit is white
canvas_set_color(canvas, ColorWhite);
// first
char batteryPercentileFirstDigit[2];
snprintf(
batteryPercentileFirstDigit,
sizeof(batteryPercentileFirstDigit),
"%c",
batteryPercentile[0]);
canvas_draw_str_aligned(
canvas, 9, 4, AlignCenter, AlignCenter, batteryPercentileFirstDigit);
// second
char batteryPercentileSecondDigit[2];
snprintf(
batteryPercentileSecondDigit,
sizeof(batteryPercentileSecondDigit),
"%c",
batteryPercentile[1]);
canvas_set_color(canvas, ColorBlack);
canvas_draw_str_aligned(
canvas, 15, 4, AlignCenter, AlignCenter, batteryPercentileSecondDigit);
} else { // charge >= 74, both digits are white
canvas_set_color(canvas, ColorWhite);
canvas_draw_str_aligned(
canvas, 11, 4, AlignCenter, AlignCenter, batteryPercentile);
}
} else { //default bar display, added here to serve as fallback/default behaviour. } else { //default bar display, added here to serve as fallback/default behaviour.
canvas_draw_box(canvas, 2, 2, (power->info.charge + 4) / 5, 4); canvas_draw_box(canvas, 2, 2, (power->info.charge + 4) / 5, 4);
} }
@ -82,7 +134,7 @@ void power_draw_battery_callback(Canvas* canvas, void* context) {
if(power->state == PowerStateCharging) { if(power->state == PowerStateCharging) {
canvas_set_bitmap_mode(canvas, 1); canvas_set_bitmap_mode(canvas, 1);
// TODO: replace -1 magic for uint8_t with re-framing // TODO: replace -1 magic for uint8_t with re-framing
if(power->displayBatteryPercentage == 1) { if(power->displayBatteryPercentage == DISPLAY_BATTERY_PERCENT) {
canvas_set_color(canvas, ColorBlack); canvas_set_color(canvas, ColorBlack);
canvas_draw_box(canvas, 1, 1, 22, 6); canvas_draw_box(canvas, 1, 1, 22, 6);
canvas_draw_icon(canvas, 2, -1, &I_Charging_lightning_9x10); canvas_draw_icon(canvas, 2, -1, &I_Charging_lightning_9x10);
@ -91,7 +143,7 @@ void power_draw_battery_callback(Canvas* canvas, void* context) {
canvas_set_font(canvas, FontBatteryPercent); canvas_set_font(canvas, FontBatteryPercent);
canvas_draw_str_aligned( canvas_draw_str_aligned(
canvas, 16, 4, AlignCenter, AlignCenter, batteryPercentile); canvas, 16, 4, AlignCenter, AlignCenter, batteryPercentile);
} else if(power->displayBatteryPercentage == 2) { } else if(power->displayBatteryPercentage == DISPLAY_BATTERY_INVERTED_PERCENT) {
canvas_set_color(canvas, ColorWhite); canvas_set_color(canvas, ColorWhite);
canvas_draw_box(canvas, 1, 1, 22, 6); canvas_draw_box(canvas, 1, 1, 22, 6);
canvas_draw_icon(canvas, 2, -1, &I_Charging_lightning_9x10); canvas_draw_icon(canvas, 2, -1, &I_Charging_lightning_9x10);
@ -100,6 +152,64 @@ void power_draw_battery_callback(Canvas* canvas, void* context) {
canvas_set_font(canvas, FontBatteryPercent); canvas_set_font(canvas, FontBatteryPercent);
canvas_draw_str_aligned( canvas_draw_str_aligned(
canvas, 16, 4, AlignCenter, AlignCenter, batteryPercentile); canvas, 16, 4, AlignCenter, AlignCenter, batteryPercentile);
} else if(power->displayBatteryPercentage == DISPLAY_BATTERY_BAR_PERCENT) {
// clean-up default charging bar display
canvas_set_color(canvas, ColorWhite);
canvas_draw_box(canvas, 1, 1, 22, 6);
// align charge dispaly value with digits to draw
uint8_t bar_charge = power->info.charge;
if(bar_charge > 48 && bar_charge < 63) {
bar_charge = 48;
} else if(bar_charge >= 63 && bar_charge < 84) {
bar_charge = 75;
} else if(bar_charge >= 84 && bar_charge < 96) {
bar_charge = 96;
}
canvas_set_color(canvas, ColorBlack);
canvas_draw_box(canvas, 1, 1, (bar_charge * 22) / 100, 6);
// drawing charge icon
canvas_draw_icon(canvas, 2, -1, &I_Charging_lightning_9x10);
canvas_set_color(canvas, ColorWhite);
canvas_draw_icon(canvas, 2, -1, &I_Charging_lightning_mask_9x10);
// drawing digits
canvas_set_font(canvas, FontBatteryPercent);
if(bar_charge < 64) { // both digits are black
canvas_set_color(canvas, ColorBlack);
canvas_draw_str_aligned(
canvas, 16, 4, AlignCenter, AlignCenter, batteryPercentile);
} else if(bar_charge >= 64 && bar_charge < 84) { // first digit is white
canvas_set_color(canvas, ColorWhite);
// first
char batteryPercentileFirstDigit[2];
snprintf(
batteryPercentileFirstDigit,
sizeof(batteryPercentileFirstDigit),
"%c",
batteryPercentile[0]);
canvas_draw_str_aligned(
canvas, 14, 4, AlignCenter, AlignCenter, batteryPercentileFirstDigit);
// second
char batteryPercentileSecondDigit[2];
snprintf(
batteryPercentileSecondDigit,
sizeof(batteryPercentileSecondDigit),
"%c",
batteryPercentile[1]);
canvas_set_color(canvas, ColorBlack);
canvas_draw_str_aligned(
canvas, 20, 4, AlignCenter, AlignCenter, batteryPercentileSecondDigit);
} else { // charge >= 84, both digits are white
canvas_set_color(canvas, ColorWhite);
canvas_draw_str_aligned(
canvas, 16, 4, AlignCenter, AlignCenter, batteryPercentile);
}
} else { } else {
canvas_set_color(canvas, ColorWhite); canvas_set_color(canvas, ColorWhite);
canvas_draw_icon(canvas, 8, -1, &I_Charging_lightning_mask_9x10); canvas_draw_icon(canvas, 8, -1, &I_Charging_lightning_mask_9x10);

View file

@ -26,7 +26,7 @@ const char* const auto_lock_delay_text[AUTO_LOCK_DELAY_COUNT] = {
const uint32_t auto_lock_delay_value[AUTO_LOCK_DELAY_COUNT] = const uint32_t auto_lock_delay_value[AUTO_LOCK_DELAY_COUNT] =
{0, 10000, 15000, 30000, 60000, 90000, 120000, 300000, 600000}; {0, 10000, 15000, 30000, 60000, 90000, 120000, 300000, 600000};
#define BATTERY_VIEW_COUNT 5 #define BATTERY_VIEW_COUNT 6
const char* const battery_view_count_text[BATTERY_VIEW_COUNT] = { const char* const battery_view_count_text[BATTERY_VIEW_COUNT] = {
"Bar", "Bar",
@ -34,9 +34,17 @@ const char* const battery_view_count_text[BATTERY_VIEW_COUNT] = {
"Inv. %", "Inv. %",
"Retro 3", "Retro 3",
"Retro 5", "Retro 5",
"Bar %"
}; };
const uint32_t displayBatteryPercentage_value[BATTERY_VIEW_COUNT] = {0, 1, 2, 3, 4}; const uint32_t displayBatteryPercentage_value[BATTERY_VIEW_COUNT] = {
DISPLAY_BATTERY_BAR,
DISPLAY_BATTERY_PERCENT,
DISPLAY_BATTERY_INVERTED_PERCENT,
DISPLAY_BATTERY_RETRO_3,
DISPLAY_BATTERY_RETRO_5,
DISPLAY_BATTERY_BAR_PERCENT
};
static void desktop_settings_scene_start_var_list_enter_callback(void* context, uint32_t index) { static void desktop_settings_scene_start_var_list_enter_callback(void* context, uint32_t index) {
DesktopSettingsApp* app = context; DesktopSettingsApp* app = context;

View file

@ -54,13 +54,14 @@ assetsenv.Alias("proto_ver", proto_ver)
# Gather everything into a static lib # Gather everything into a static lib
assets_parts = (icons, proto, dolphin_blocking, dolphin_internal, proto_ver) assets_parts = (icons, proto, dolphin_blocking, dolphin_internal, proto_ver)
env.Replace(FW_ASSETS_HEADERS=assets_parts)
assetslib = assetsenv.Library("${FW_LIB_NAME}", assets_parts) assetslib = assetsenv.Library("${FW_LIB_NAME}", assets_parts)
assetsenv.Install("${LIB_DIST_DIR}", assetslib) assetsenv.Install("${LIB_DIST_DIR}", assetslib)
# Resources for SD card # Resources for SD card
env.SetDefault(FW_RESOURCES=None)
if assetsenv["IS_BASE_FIRMWARE"]: if assetsenv["IS_BASE_FIRMWARE"]:
# External dolphin animations # External dolphin animations
dolphin_external = assetsenv.DolphinExtBuilder( dolphin_external = assetsenv.DolphinExtBuilder(
@ -92,8 +93,7 @@ if assetsenv["IS_BASE_FIRMWARE"]:
) )
# Exporting resources node to external environment # Exporting resources node to external environment
env["FW_ASSETS_HEADERS"] = assets_parts env.Replace(FW_RESOURCES=resources)
env["FW_RESOURCES"] = resources
assetsenv.Alias("resources", resources) assetsenv.Alias("resources", resources)
Return("assetslib") Return("assetslib")

View file

@ -79,7 +79,7 @@ STRING Flipper Zero BadUSB feature is compatible with USB Rubber Ducky script fo
ENTER ENTER
STRING More information about script syntax can be found here: STRING More information about script syntax can be found here:
ENTER ENTER
STRING https://github.com/hak5darren/USB-Rubber-Ducky/wiki/Duckyscript STRING https://github.com/flipperdevices/flipperzero-firmware/blob/dev/documentation/file_formats/BadUsbScriptFormat.md
ENTER ENTER
STRING EOF STRING EOF

View file

@ -80,5 +80,5 @@ STRING Flipper Zero BadUSB feature is compatible with USB Rubber Ducky script fo
ENTER ENTER
STRING More information about script syntax can be found here: STRING More information about script syntax can be found here:
ENTER ENTER
STRING https://github.com/hak5darren/USB-Rubber-Ducky/wiki/Duckyscript STRING https://github.com/flipperdevices/flipperzero-firmware/blob/dev/documentation/file_formats/BadUsbScriptFormat.md
ENTER ENTER

View file

@ -1,7 +1,37 @@
Filetype: IR library file Filetype: IR library file
Version: 1 Version: 1
# Last Updated 7th Jan, 2023 # Last Updated 13th Jan, 2023
# Last Checked 7th Jan, 2023 # Last Checked 13th Jan, 2023
#
name: POWER
type: raw
frequency: 38000
duty_cycle: 0.330000
data: 8714 4338 579 538 551 540 549 542 557 1613 555 1615 553 538 551 540 549 1619 549 1620 558 1612 556 1614 554 1617 551 540 559 1611 557 1612 556 531 558 1613 555 536 553 538 551 1620 558 1612 556 535 554 537 552 535 554 537 552 1618 550 1620 558 533 556 536 553 1617 551 1617 551 1608 549
#
name: MODE
type: raw
frequency: 38000
duty_cycle: 0.330000
data: 8710 4341 576 541 558 533 556 535 554 1616 552 1618 550 542 557 533 556 1612 556 1614 554 1616 552 1618 550 1621 557 534 555 1615 553 1616 552 536 553 538 551 541 558 533 556 1613 555 537 552 539 550 541 558 528 550 1619 559 1610 557 1612 556 536 553 1616 552 1618 550 1619 559 1598 559
#
name: TIMER
type: raw
frequency: 38000
duty_cycle: 0.330000
data: 8717 4334 583 534 555 537 552 539 550 1620 558 1611 557 535 554 536 553 1615 553 1617 551 1619 559 1611 557 1613 555 537 552 1617 551 1619 559 528 550 541 558 1612 556 535 554 1616 552 1619 549 543 556 534 555 532 557 1614 554 537 552 1619 559 533 556 535 554 1616 552 1617 551 1608 549
#
name: TEMP+
type: raw
frequency: 38000
duty_cycle: 0.330000
data: 8714 4337 580 538 551 540 559 533 556 1613 555 1615 553 539 550 541 558 1608 560 1611 557 1587 581 1590 578 1593 575 542 557 1613 555 1614 554 534 555 1615 553 539 550 1620 558 534 555 536 553 539 550 541 558 529 549 541 558 1612 556 536 553 1617 551 1619 559 1611 557 1613 555 1603 554
#
name: TEMP-
type: raw
frequency: 38000
duty_cycle: 0.330000
data: 8711 4341 576 541 558 534 555 536 553 1616 552 1618 549 542 557 533 556 1611 557 1613 555 1614 554 1616 552 1619 559 532 557 1613 555 1614 554 533 556 1614 554 538 551 541 558 1611 557 535 554 537 552 539 550 537 552 540 549 1620 558 1612 556 536 553 1617 550 1619 559 1610 558 1601 556
# #
# POWER_ON # POWER_ON
name: POWER name: POWER

File diff suppressed because it is too large Load diff

View file

@ -1,7 +1,7 @@
Filetype: IR library file Filetype: IR library file
Version: 1 Version: 1
# Last Updated 7th Jan, 2023 # Last Updated 13th Jan, 2023
# Last Checked 7th Jan, 2023 # Last Checked 13th Jan, 2023
# #
name: POWER name: POWER
type: raw type: raw

View file

@ -1,7 +1,7 @@
Filetype: IR library file Filetype: IR library file
Version: 1 Version: 1
# Last Updated 5th Jan, 2023 # Last Updated 13th Jan, 2023
# Last Checked 7th Jan, 2023 # Last Checked 13th Jan, 2023
# #
# ON # ON
name: POWER name: POWER
@ -712,3 +712,69 @@ type: parsed
protocol: NEC protocol: NEC
address: 00 00 00 00 address: 00 00 00 00
command: 8C 00 00 00 command: 8C 00 00 00
#
name: POWER
type: parsed
protocol: NECext
address: 87 45 00 00
command: 17 E8 00 00
#
name: VOL+
type: raw
frequency: 38000
duty_cycle: 0.330000
data: 9064 4354 666 1559 666 1562 662 1586 638 475 636 477 635 477 635 478 635 1590 635 1591 634 478 635 1591 634 478 634 478 635 478 634 1591 635 478 634 1591 634 478 635 478 634 478 635 1591 634 478 634 1591 635 478 634 478 634 1591 634 1591 635 1591 634 478 635 1591 634 478 634 1591 635 40957 9035 2144 634 95483 9047 2155 632 95484 9048 2153 633
#
name: VOL-
type: parsed
protocol: NECext
address: 87 45 00 00
command: 50 AF 00 00
#
name: MUTE
type: raw
frequency: 38000
duty_cycle: 0.330000
data: 9034 4385 638 1587 664 1562 663 1587 637 476 635 478 634 478 635 478 635 1591 634 1591 634 478 635 1591 635 478 634 478 635 478 635 1591 635 478 634 478 634 1591 634 478 635 479 634 1591 635 478 634 1591 635 478 634 1592 634 478 634 1591 635 1591 635 478 634 1592 634 478 634 1591 634 40958 9033 2144 635
#
name: POWER
type: parsed
protocol: NECext
address: FF FF 00 00
command: E8 17 00 00
#
name: VOL+
type: parsed
protocol: NECext
address: FF FF 00 00
command: BD 42 00 00
#
name: VOL-
type: parsed
protocol: NECext
address: FF FF 00 00
command: F2 0D 00 00
#
name: POWER
type: parsed
protocol: Kaseikyo
address: 41 54 32 00
command: 05 00 00 00
#
name: VOL+
type: parsed
protocol: Kaseikyo
address: 41 54 32 00
command: 70 01 00 00
#
name: VOL-
type: parsed
protocol: Kaseikyo
address: 41 54 32 00
command: 71 01 00 00
#
name: POWER
type: parsed
protocol: NEC
address: 31 00 00 00
command: 81 00 00 00

View file

@ -1,7 +1,7 @@
Filetype: IR library file Filetype: IR library file
Version: 1 Version: 1
# Last Updated 7th Jan, 2023 # Last Updated 13th Jan, 2023
# Last Checked 7th Jan, 2023 # Last Checked 13th Jan, 2023
# #
name: POWER name: POWER
type: parsed type: parsed
@ -1785,3 +1785,39 @@ type: parsed
protocol: NEC protocol: NEC
address: 00 00 00 00 address: 00 00 00 00
command: 33 00 00 00 command: 33 00 00 00
#
name: POWER
type: parsed
protocol: NEC
address: 28 00 00 00
command: 0B 00 00 00
#
name: CH+
type: parsed
protocol: NEC
address: 28 00 00 00
command: 0C 00 00 00
#
name: CH-
type: parsed
protocol: NEC
address: 28 00 00 00
command: 0D 00 00 00
#
name: VOL+
type: parsed
protocol: NEC
address: 28 00 00 00
command: 0E 00 00 00
#
name: VOL-
type: parsed
protocol: NEC
address: 28 00 00 00
command: 0F 00 00 00
#
name: MUTE
type: parsed
protocol: NEC
address: 28 00 00 00
command: 10 00 00 00

View file

@ -56,6 +56,7 @@ To run cleanup (think of `make clean`) for specified targets, add the `-c` optio
- `get_stlink` - output serial numbers for attached STLink probes. Used for specifying an adapter with `OPENOCD_ADAPTER_SERIAL=...`. - `get_stlink` - output serial numbers for attached STLink probes. Used for specifying an adapter with `OPENOCD_ADAPTER_SERIAL=...`.
- `lint`, `format` - run clang-format on the C source code to check and reformat it according to the `.clang-format` specs. - `lint`, `format` - run clang-format on the C source code to check and reformat it according to the `.clang-format` specs.
- `lint_py`, `format_py` - run [black](https://black.readthedocs.io/en/stable/index.html) on the Python source code, build system files & application manifests. - `lint_py`, `format_py` - run [black](https://black.readthedocs.io/en/stable/index.html) on the Python source code, build system files & application manifests.
- `firmware_pvs` - generate a PVS Studio report for the firmware. Requires PVS Studio to be availabe on your system's `PATH`.
- `cli` - start a Flipper CLI session over USB. - `cli` - start a Flipper CLI session over USB.
### Firmware targets ### Firmware targets

View file

@ -15,6 +15,7 @@ env = ENV.Clone(
("compilation_db", {"COMPILATIONDB_COMSTR": "\tCDB\t${TARGET}"}), ("compilation_db", {"COMPILATIONDB_COMSTR": "\tCDB\t${TARGET}"}),
"fwbin", "fwbin",
"fbt_apps", "fbt_apps",
"pvsstudio",
], ],
COMPILATIONDB_USE_ABSPATH=False, COMPILATIONDB_USE_ABSPATH=False,
BUILD_DIR=fw_build_meta["build_dir"], BUILD_DIR=fw_build_meta["build_dir"],
@ -69,6 +70,8 @@ env = ENV.Clone(
], ],
}, },
}, },
SDK_APISYMS=None,
_APP_ICONS=None,
) )
@ -128,9 +131,6 @@ if extra_int_apps := GetOption("extra_int_apps"):
fwenv.Append(APPS=extra_int_apps.split(",")) fwenv.Append(APPS=extra_int_apps.split(","))
if fwenv["FAP_EXAMPLES"]:
fwenv.Append(APPDIRS=[("applications/examples", False)])
for app_dir, _ in env["APPDIRS"]: for app_dir, _ in env["APPDIRS"]:
app_dir_node = env.Dir("#").Dir(app_dir) app_dir_node = env.Dir("#").Dir(app_dir)
@ -273,6 +273,24 @@ Precious(fwcdb)
NoClean(fwcdb) NoClean(fwcdb)
Alias(fwenv["FIRMWARE_BUILD_CFG"] + "_cdb", fwcdb) Alias(fwenv["FIRMWARE_BUILD_CFG"] + "_cdb", fwcdb)
pvscheck = fwenv.PVSCheck("pvsreport.log", fwcdb)
Depends(
pvscheck,
[
fwenv["FW_VERSION_JSON"],
fwenv["FW_ASSETS_HEADERS"],
fwenv["SDK_APISYMS"],
fwenv["_APP_ICONS"],
],
)
Alias(fwenv["FIRMWARE_BUILD_CFG"] + "_pvscheck", pvscheck)
AlwaysBuild(pvscheck)
Precious(pvscheck)
pvsreport = fwenv.PVSReport(None, pvscheck, REPORT_DIR=Dir("pvsreport"))
Alias(fwenv["FIRMWARE_BUILD_CFG"] + "_pvs", pvsreport)
AlwaysBuild(pvsreport)
# If current configuration was explicitly requested, generate compilation database # If current configuration was explicitly requested, generate compilation database
# and link its directory as build/latest # and link its directory as build/latest
if should_gen_cdb_and_link_dir(fwenv, BUILD_TARGETS): if should_gen_cdb_and_link_dir(fwenv, BUILD_TARGETS):

View file

@ -1,5 +1,5 @@
entry,status,name,type,params entry,status,name,type,params
Version,+,11.8,, Version,+,11.7,,
Header,+,applications/services/bt/bt_service/bt.h,, Header,+,applications/services/bt/bt_service/bt.h,,
Header,+,applications/services/cli/cli.h,, Header,+,applications/services/cli/cli.h,,
Header,+,applications/services/cli/cli_vcp.h,, Header,+,applications/services/cli/cli_vcp.h,,
@ -1649,6 +1649,7 @@ Function,+,infrared_get_protocol_by_name,InfraredProtocol,const char*
Function,+,infrared_get_protocol_command_length,uint8_t,InfraredProtocol Function,+,infrared_get_protocol_command_length,uint8_t,InfraredProtocol
Function,+,infrared_get_protocol_duty_cycle,float,InfraredProtocol Function,+,infrared_get_protocol_duty_cycle,float,InfraredProtocol
Function,+,infrared_get_protocol_frequency,uint32_t,InfraredProtocol Function,+,infrared_get_protocol_frequency,uint32_t,InfraredProtocol
Function,+,infrared_get_protocol_min_repeat_count,size_t,InfraredProtocol
Function,+,infrared_get_protocol_name,const char*,InfraredProtocol Function,+,infrared_get_protocol_name,const char*,InfraredProtocol
Function,+,infrared_is_protocol_valid,_Bool,InfraredProtocol Function,+,infrared_is_protocol_valid,_Bool,InfraredProtocol
Function,+,infrared_reset_decoder,void,InfraredDecoderHandler* Function,+,infrared_reset_decoder,void,InfraredDecoderHandler*

1 entry status name type params
2 Version + 11.8 11.7
3 Header + applications/services/bt/bt_service/bt.h
4 Header + applications/services/cli/cli.h
5 Header + applications/services/cli/cli_vcp.h
1649 Function + infrared_get_protocol_command_length uint8_t InfraredProtocol
1650 Function + infrared_get_protocol_duty_cycle float InfraredProtocol
1651 Function + infrared_get_protocol_frequency uint32_t InfraredProtocol
1652 Function + infrared_get_protocol_min_repeat_count size_t InfraredProtocol
1653 Function + infrared_get_protocol_name const char* InfraredProtocol
1654 Function + infrared_is_protocol_valid _Bool InfraredProtocol
1655 Function + infrared_reset_decoder void InfraredDecoderHandler*

View file

@ -93,7 +93,11 @@ extern "C" {
#endif #endif
#ifndef FURI_BIT_CLEAR #ifndef FURI_BIT_CLEAR
#define FURI_BIT_CLEAR(x, n) ((x) &= ~(1UL << (n))) #define FURI_BIT_CLEAR(x, n) \
({ \
__typeof__(x) _x = (1); \
(x) &= ~(_x << (n)); \
})
#endif #endif
#define FURI_SW_MEMBARRIER() asm volatile("" : : : "memory") #define FURI_SW_MEMBARRIER() asm volatile("" : : : "memory")

View file

@ -315,6 +315,7 @@ static bool elf_relocate_symbol(ELFFile* elf, Elf32_Addr relAddr, int type, Elf3
FURI_LOG_D(TAG, " R_ARM_ABS32 relocated is 0x%08X", (unsigned int)*((uint32_t*)relAddr)); FURI_LOG_D(TAG, " R_ARM_ABS32 relocated is 0x%08X", (unsigned int)*((uint32_t*)relAddr));
break; break;
case R_ARM_THM_PC22: case R_ARM_THM_PC22:
case R_ARM_CALL:
case R_ARM_THM_JUMP24: case R_ARM_THM_JUMP24:
elf_relocate_jmp_call(elf, relAddr, type, symAddr); elf_relocate_jmp_call(elf, relAddr, type, symAddr);
FURI_LOG_D( FURI_LOG_D(

View file

@ -1,11 +1,8 @@
#include "infrared_common_i.h"
#include <stdlib.h>
#include <core/check.h> #include <core/check.h>
#include <core/common_defines.h> #include <core/common_defines.h>
#include "infrared.h"
#include "infrared_common_i.h"
#include <stdbool.h>
#include <furi.h>
#include "infrared_i.h"
#include <stdint.h>
static void infrared_common_decoder_reset_state(InfraredCommonDecoder* decoder); static void infrared_common_decoder_reset_state(InfraredCommonDecoder* decoder);

View file

@ -1,10 +1,9 @@
#include <core/check.h>
#include "infrared.h"
#include "infrared_common_i.h" #include "infrared_common_i.h"
#include <stdbool.h>
#include <furi.h> #include <stdlib.h>
#include "infrared_i.h" #include <string.h>
#include <stdint.h> #include <core/check.h>
#include <core/common_defines.h>
static InfraredStatus static InfraredStatus
infrared_common_encode_bits(InfraredCommonEncoder* encoder, uint32_t* duration, bool* level) { infrared_common_encode_bits(InfraredCommonEncoder* encoder, uint32_t* duration, bool* level) {

View file

@ -1,140 +0,0 @@
#include "infrared_common_i.h"
#include "infrared_protocol_defs_i.h"
const InfraredCommonProtocolSpec protocol_nec = {
.timings =
{
.preamble_mark = INFRARED_NEC_PREAMBLE_MARK,
.preamble_space = INFRARED_NEC_PREAMBLE_SPACE,
.bit1_mark = INFRARED_NEC_BIT1_MARK,
.bit1_space = INFRARED_NEC_BIT1_SPACE,
.bit0_mark = INFRARED_NEC_BIT0_MARK,
.bit0_space = INFRARED_NEC_BIT0_SPACE,
.preamble_tolerance = INFRARED_NEC_PREAMBLE_TOLERANCE,
.bit_tolerance = INFRARED_NEC_BIT_TOLERANCE,
.silence_time = INFRARED_NEC_SILENCE,
.min_split_time = INFRARED_NEC_MIN_SPLIT_TIME,
},
.databit_len[0] = 42,
.databit_len[1] = 32,
.no_stop_bit = false,
.decode = infrared_common_decode_pdwm,
.encode = infrared_common_encode_pdwm,
.interpret = infrared_decoder_nec_interpret,
.decode_repeat = infrared_decoder_nec_decode_repeat,
.encode_repeat = infrared_encoder_nec_encode_repeat,
};
const InfraredCommonProtocolSpec protocol_samsung32 = {
.timings =
{
.preamble_mark = INFRARED_SAMSUNG_PREAMBLE_MARK,
.preamble_space = INFRARED_SAMSUNG_PREAMBLE_SPACE,
.bit1_mark = INFRARED_SAMSUNG_BIT1_MARK,
.bit1_space = INFRARED_SAMSUNG_BIT1_SPACE,
.bit0_mark = INFRARED_SAMSUNG_BIT0_MARK,
.bit0_space = INFRARED_SAMSUNG_BIT0_SPACE,
.preamble_tolerance = INFRARED_SAMSUNG_PREAMBLE_TOLERANCE,
.bit_tolerance = INFRARED_SAMSUNG_BIT_TOLERANCE,
.silence_time = INFRARED_SAMSUNG_SILENCE,
.min_split_time = INFRARED_SAMSUNG_MIN_SPLIT_TIME,
},
.databit_len[0] = 32,
.no_stop_bit = false,
.decode = infrared_common_decode_pdwm,
.encode = infrared_common_encode_pdwm,
.interpret = infrared_decoder_samsung32_interpret,
.decode_repeat = infrared_decoder_samsung32_decode_repeat,
.encode_repeat = infrared_encoder_samsung32_encode_repeat,
};
const InfraredCommonProtocolSpec protocol_rc6 = {
.timings =
{
.preamble_mark = INFRARED_RC6_PREAMBLE_MARK,
.preamble_space = INFRARED_RC6_PREAMBLE_SPACE,
.bit1_mark = INFRARED_RC6_BIT,
.preamble_tolerance = INFRARED_RC6_PREAMBLE_TOLERANCE,
.bit_tolerance = INFRARED_RC6_BIT_TOLERANCE,
.silence_time = INFRARED_RC6_SILENCE,
.min_split_time = INFRARED_RC6_MIN_SPLIT_TIME,
},
.databit_len[0] =
1 + 3 + 1 + 8 +
8, // start_bit + 3 mode bits, + 1 toggle bit (x2 timing) + 8 address + 8 command
.manchester_start_from_space = false,
.decode = infrared_decoder_rc6_decode_manchester,
.encode = infrared_encoder_rc6_encode_manchester,
.interpret = infrared_decoder_rc6_interpret,
.decode_repeat = NULL,
.encode_repeat = NULL,
};
const InfraredCommonProtocolSpec protocol_rc5 = {
.timings =
{
.preamble_mark = 0,
.preamble_space = 0,
.bit1_mark = INFRARED_RC5_BIT,
.preamble_tolerance = 0,
.bit_tolerance = INFRARED_RC5_BIT_TOLERANCE,
.silence_time = INFRARED_RC5_SILENCE,
.min_split_time = INFRARED_RC5_MIN_SPLIT_TIME,
},
.databit_len[0] = 1 + 1 + 1 + 5 +
6, // start_bit + start_bit/command_bit + toggle_bit + 5 address + 6 command
.manchester_start_from_space = true,
.decode = infrared_common_decode_manchester,
.encode = infrared_common_encode_manchester,
.interpret = infrared_decoder_rc5_interpret,
.decode_repeat = NULL,
.encode_repeat = NULL,
};
const InfraredCommonProtocolSpec protocol_sirc = {
.timings =
{
.preamble_mark = INFRARED_SIRC_PREAMBLE_MARK,
.preamble_space = INFRARED_SIRC_PREAMBLE_SPACE,
.bit1_mark = INFRARED_SIRC_BIT1_MARK,
.bit1_space = INFRARED_SIRC_BIT1_SPACE,
.bit0_mark = INFRARED_SIRC_BIT0_MARK,
.bit0_space = INFRARED_SIRC_BIT0_SPACE,
.preamble_tolerance = INFRARED_SIRC_PREAMBLE_TOLERANCE,
.bit_tolerance = INFRARED_SIRC_BIT_TOLERANCE,
.silence_time = INFRARED_SIRC_SILENCE,
.min_split_time = INFRARED_SIRC_MIN_SPLIT_TIME,
},
.databit_len[0] = 20,
.databit_len[1] = 15,
.databit_len[2] = 12,
.no_stop_bit = true,
.decode = infrared_common_decode_pdwm,
.encode = infrared_common_encode_pdwm,
.interpret = infrared_decoder_sirc_interpret,
.decode_repeat = NULL,
.encode_repeat = infrared_encoder_sirc_encode_repeat,
};
const InfraredCommonProtocolSpec protocol_kaseikyo = {
.timings =
{
.preamble_mark = INFRARED_KASEIKYO_PREAMBLE_MARK,
.preamble_space = INFRARED_KASEIKYO_PREAMBLE_SPACE,
.bit1_mark = INFRARED_KASEIKYO_BIT1_MARK,
.bit1_space = INFRARED_KASEIKYO_BIT1_SPACE,
.bit0_mark = INFRARED_KASEIKYO_BIT0_MARK,
.bit0_space = INFRARED_KASEIKYO_BIT0_SPACE,
.preamble_tolerance = INFRARED_KASEIKYO_PREAMBLE_TOLERANCE,
.bit_tolerance = INFRARED_KASEIKYO_BIT_TOLERANCE,
.silence_time = INFRARED_KASEIKYO_SILENCE,
.min_split_time = INFRARED_KASEIKYO_MIN_SPLIT_TIME,
},
.databit_len[0] = 48,
.no_stop_bit = false,
.decode = infrared_common_decode_pdwm,
.encode = infrared_common_encode_pdwm,
.interpret = infrared_decoder_kaseikyo_interpret,
.decode_repeat = NULL,
.encode_repeat = NULL,
};

View file

@ -1,13 +1,16 @@
#include "infrared.h" #include "infrared.h"
#include <core/check.h>
#include "common/infrared_common_i.h"
#include "infrared_protocol_defs_i.h"
#include <stdbool.h>
#include <stdint.h>
#include <stdlib.h> #include <stdlib.h>
#include <furi.h> #include <string.h>
#include "infrared_i.h" #include <core/check.h>
#include <furi_hal_infrared.h> #include <core/common_defines.h>
#include "nec/infrared_protocol_nec.h"
#include "samsung/infrared_protocol_samsung.h"
#include "rc5/infrared_protocol_rc5.h"
#include "rc6/infrared_protocol_rc6.h"
#include "sirc/infrared_protocol_sirc.h"
#include "kaseikyo/infrared_protocol_kaseikyo.h"
typedef struct { typedef struct {
InfraredAlloc alloc; InfraredAlloc alloc;
@ -36,7 +39,7 @@ struct InfraredEncoderHandler {
typedef struct { typedef struct {
InfraredEncoders encoder; InfraredEncoders encoder;
InfraredDecoders decoder; InfraredDecoders decoder;
InfraredGetProtocolSpec get_protocol_spec; InfraredGetProtocolVariant get_protocol_variant;
} InfraredEncoderDecoder; } InfraredEncoderDecoder;
static const InfraredEncoderDecoder infrared_encoder_decoder[] = { static const InfraredEncoderDecoder infrared_encoder_decoder[] = {
@ -52,7 +55,7 @@ static const InfraredEncoderDecoder infrared_encoder_decoder[] = {
.encode = infrared_encoder_nec_encode, .encode = infrared_encoder_nec_encode,
.reset = infrared_encoder_nec_reset, .reset = infrared_encoder_nec_reset,
.free = infrared_encoder_nec_free}, .free = infrared_encoder_nec_free},
.get_protocol_spec = infrared_nec_get_spec, .get_protocol_variant = infrared_protocol_nec_get_variant,
}, },
{ {
.decoder = .decoder =
@ -66,7 +69,7 @@ static const InfraredEncoderDecoder infrared_encoder_decoder[] = {
.encode = infrared_encoder_samsung32_encode, .encode = infrared_encoder_samsung32_encode,
.reset = infrared_encoder_samsung32_reset, .reset = infrared_encoder_samsung32_reset,
.free = infrared_encoder_samsung32_free}, .free = infrared_encoder_samsung32_free},
.get_protocol_spec = infrared_samsung32_get_spec, .get_protocol_variant = infrared_protocol_samsung32_get_variant,
}, },
{ {
.decoder = .decoder =
@ -80,7 +83,7 @@ static const InfraredEncoderDecoder infrared_encoder_decoder[] = {
.encode = infrared_encoder_rc5_encode, .encode = infrared_encoder_rc5_encode,
.reset = infrared_encoder_rc5_reset, .reset = infrared_encoder_rc5_reset,
.free = infrared_encoder_rc5_free}, .free = infrared_encoder_rc5_free},
.get_protocol_spec = infrared_rc5_get_spec, .get_protocol_variant = infrared_protocol_rc5_get_variant,
}, },
{ {
.decoder = .decoder =
@ -94,7 +97,7 @@ static const InfraredEncoderDecoder infrared_encoder_decoder[] = {
.encode = infrared_encoder_rc6_encode, .encode = infrared_encoder_rc6_encode,
.reset = infrared_encoder_rc6_reset, .reset = infrared_encoder_rc6_reset,
.free = infrared_encoder_rc6_free}, .free = infrared_encoder_rc6_free},
.get_protocol_spec = infrared_rc6_get_spec, .get_protocol_variant = infrared_protocol_rc6_get_variant,
}, },
{ {
.decoder = .decoder =
@ -108,7 +111,7 @@ static const InfraredEncoderDecoder infrared_encoder_decoder[] = {
.encode = infrared_encoder_sirc_encode, .encode = infrared_encoder_sirc_encode,
.reset = infrared_encoder_sirc_reset, .reset = infrared_encoder_sirc_reset,
.free = infrared_encoder_sirc_free}, .free = infrared_encoder_sirc_free},
.get_protocol_spec = infrared_sirc_get_spec, .get_protocol_variant = infrared_protocol_sirc_get_variant,
}, },
{ {
.decoder = .decoder =
@ -122,13 +125,12 @@ static const InfraredEncoderDecoder infrared_encoder_decoder[] = {
.encode = infrared_encoder_kaseikyo_encode, .encode = infrared_encoder_kaseikyo_encode,
.reset = infrared_encoder_kaseikyo_reset, .reset = infrared_encoder_kaseikyo_reset,
.free = infrared_encoder_kaseikyo_free}, .free = infrared_encoder_kaseikyo_free},
.get_protocol_spec = infrared_kaseikyo_get_spec, .get_protocol_variant = infrared_protocol_kaseikyo_get_variant,
}, },
}; };
static int infrared_find_index_by_protocol(InfraredProtocol protocol); static int infrared_find_index_by_protocol(InfraredProtocol protocol);
static const InfraredProtocolSpecification* static const InfraredProtocolVariant* infrared_get_variant_by_protocol(InfraredProtocol protocol);
infrared_get_spec_by_protocol(InfraredProtocol protocol);
const InfraredMessage* const InfraredMessage*
infrared_decode(InfraredDecoderHandler* handler, bool level, uint32_t duration) { infrared_decode(InfraredDecoderHandler* handler, bool level, uint32_t duration) {
@ -224,7 +226,7 @@ void infrared_free_encoder(InfraredEncoderHandler* handler) {
static int infrared_find_index_by_protocol(InfraredProtocol protocol) { static int infrared_find_index_by_protocol(InfraredProtocol protocol) {
for(size_t i = 0; i < COUNT_OF(infrared_encoder_decoder); ++i) { for(size_t i = 0; i < COUNT_OF(infrared_encoder_decoder); ++i) {
if(infrared_encoder_decoder[i].get_protocol_spec(protocol)) { if(infrared_encoder_decoder[i].get_protocol_variant(protocol)) {
return i; return i;
} }
} }
@ -282,34 +284,37 @@ InfraredProtocol infrared_get_protocol_by_name(const char* protocol_name) {
return InfraredProtocolUnknown; return InfraredProtocolUnknown;
} }
static const InfraredProtocolSpecification* static const InfraredProtocolVariant* infrared_get_variant_by_protocol(InfraredProtocol protocol) {
infrared_get_spec_by_protocol(InfraredProtocol protocol) {
int index = infrared_find_index_by_protocol(protocol); int index = infrared_find_index_by_protocol(protocol);
const InfraredProtocolSpecification* spec = NULL; const InfraredProtocolVariant* variant = NULL;
if(index >= 0) { if(index >= 0) {
spec = infrared_encoder_decoder[index].get_protocol_spec(protocol); variant = infrared_encoder_decoder[index].get_protocol_variant(protocol);
} }
furi_assert(spec); furi_assert(variant);
return spec; return variant;
} }
const char* infrared_get_protocol_name(InfraredProtocol protocol) { const char* infrared_get_protocol_name(InfraredProtocol protocol) {
return infrared_get_spec_by_protocol(protocol)->name; return infrared_get_variant_by_protocol(protocol)->name;
} }
uint8_t infrared_get_protocol_address_length(InfraredProtocol protocol) { uint8_t infrared_get_protocol_address_length(InfraredProtocol protocol) {
return infrared_get_spec_by_protocol(protocol)->address_length; return infrared_get_variant_by_protocol(protocol)->address_length;
} }
uint8_t infrared_get_protocol_command_length(InfraredProtocol protocol) { uint8_t infrared_get_protocol_command_length(InfraredProtocol protocol) {
return infrared_get_spec_by_protocol(protocol)->command_length; return infrared_get_variant_by_protocol(protocol)->command_length;
} }
uint32_t infrared_get_protocol_frequency(InfraredProtocol protocol) { uint32_t infrared_get_protocol_frequency(InfraredProtocol protocol) {
return infrared_get_spec_by_protocol(protocol)->frequency; return infrared_get_variant_by_protocol(protocol)->frequency;
} }
float infrared_get_protocol_duty_cycle(InfraredProtocol protocol) { float infrared_get_protocol_duty_cycle(InfraredProtocol protocol) {
return infrared_get_spec_by_protocol(protocol)->duty_cycle; return infrared_get_variant_by_protocol(protocol)->duty_cycle;
}
size_t infrared_get_protocol_min_repeat_count(InfraredProtocol protocol) {
return infrared_get_variant_by_protocol(protocol)->repeat_count;
} }

View file

@ -1,6 +1,7 @@
#pragma once #pragma once
#include <stdbool.h> #include <stdbool.h>
#include <stddef.h>
#include <stdint.h> #include <stdint.h>
#ifdef __cplusplus #ifdef __cplusplus
@ -201,6 +202,15 @@ uint32_t infrared_get_protocol_frequency(InfraredProtocol protocol);
*/ */
float infrared_get_protocol_duty_cycle(InfraredProtocol protocol); float infrared_get_protocol_duty_cycle(InfraredProtocol protocol);
/**
* Get the minimum count of signal repeats for the selected protocol
*
* \param[in] protocol - protocol to get the repeat count from
*
* \return repeat count
*/
size_t infrared_get_protocol_min_repeat_count(InfraredProtocol protocol);
#ifdef __cplusplus #ifdef __cplusplus
} }
#endif #endif

View file

@ -22,9 +22,10 @@ typedef struct {
uint8_t command_length; uint8_t command_length;
uint32_t frequency; uint32_t frequency;
float duty_cycle; float duty_cycle;
} InfraredProtocolSpecification; size_t repeat_count;
} InfraredProtocolVariant;
typedef const InfraredProtocolSpecification* (*InfraredGetProtocolSpec)(InfraredProtocol protocol); typedef const InfraredProtocolVariant* (*InfraredGetProtocolVariant)(InfraredProtocol protocol);
typedef void* (*InfraredAlloc)(void); typedef void* (*InfraredAlloc)(void);
typedef void (*InfraredFree)(void*); typedef void (*InfraredFree)(void*);

View file

@ -1,320 +0,0 @@
#pragma once
#include <stddef.h>
#include <stdbool.h>
#include <stdint.h>
#include "infrared.h"
#include "common/infrared_common_i.h"
/***************************************************************************************************
* NEC protocol description
* https://radioparty.ru/manuals/encyclopedia/213-ircontrol?start=1
****************************************************************************************************
* Preamble Preamble Pulse Distance/Width Pause Preamble Preamble Stop
* mark space Modulation up to period repeat repeat bit
* mark space
*
* 9000 4500 32 bit + stop bit ...110000 9000 2250
* __________ _ _ _ _ _ _ _ _ _ _ _ _ _ ___________ _
* ____ __________ _ _ _ __ __ __ _ _ __ __ _ _ ________________ ____________ ___
*
***************************************************************************************************/
#define INFRARED_NEC_PREAMBLE_MARK 9000
#define INFRARED_NEC_PREAMBLE_SPACE 4500
#define INFRARED_NEC_BIT1_MARK 560
#define INFRARED_NEC_BIT1_SPACE 1690
#define INFRARED_NEC_BIT0_MARK 560
#define INFRARED_NEC_BIT0_SPACE 560
#define INFRARED_NEC_REPEAT_PERIOD 110000
#define INFRARED_NEC_SILENCE INFRARED_NEC_REPEAT_PERIOD
#define INFRARED_NEC_MIN_SPLIT_TIME INFRARED_NEC_REPEAT_PAUSE_MIN
#define INFRARED_NEC_REPEAT_PAUSE_MIN 4000
#define INFRARED_NEC_REPEAT_PAUSE_MAX 150000
#define INFRARED_NEC_REPEAT_MARK 9000
#define INFRARED_NEC_REPEAT_SPACE 2250
#define INFRARED_NEC_PREAMBLE_TOLERANCE 200 // us
#define INFRARED_NEC_BIT_TOLERANCE 120 // us
void* infrared_decoder_nec_alloc(void);
void infrared_decoder_nec_reset(void* decoder);
void infrared_decoder_nec_free(void* decoder);
InfraredMessage* infrared_decoder_nec_check_ready(void* decoder);
InfraredMessage* infrared_decoder_nec_decode(void* decoder, bool level, uint32_t duration);
void* infrared_encoder_nec_alloc(void);
InfraredStatus infrared_encoder_nec_encode(void* encoder_ptr, uint32_t* duration, bool* level);
void infrared_encoder_nec_reset(void* encoder_ptr, const InfraredMessage* message);
void infrared_encoder_nec_free(void* encoder_ptr);
bool infrared_decoder_nec_interpret(InfraredCommonDecoder* decoder);
InfraredStatus infrared_decoder_nec_decode_repeat(InfraredCommonDecoder* decoder);
InfraredStatus infrared_encoder_nec_encode_repeat(
InfraredCommonEncoder* encoder,
uint32_t* duration,
bool* level);
const InfraredProtocolSpecification* infrared_nec_get_spec(InfraredProtocol protocol);
extern const InfraredCommonProtocolSpec protocol_nec;
/***************************************************************************************************
* SAMSUNG32 protocol description
* https://www.mikrocontroller.net/articles/IRMP_-_english#SAMSUNG
****************************************************************************************************
* Preamble Preamble Pulse Distance/Width Pause Preamble Preamble Bit1 Stop
* mark space Modulation repeat repeat bit
* mark space
*
* 4500 4500 32 bit + stop bit 40000/100000 4500 4500
* __________ _ _ _ _ _ _ _ _ _ _ _ ___________ _ _
* _ __________ __ _ __ __ __ _ _ __ __ _ ________________ ____________ ____ ___
*
***************************************************************************************************/
#define INFRARED_SAMSUNG_PREAMBLE_MARK 4500
#define INFRARED_SAMSUNG_PREAMBLE_SPACE 4500
#define INFRARED_SAMSUNG_BIT1_MARK 550
#define INFRARED_SAMSUNG_BIT1_SPACE 1650
#define INFRARED_SAMSUNG_BIT0_MARK 550
#define INFRARED_SAMSUNG_BIT0_SPACE 550
#define INFRARED_SAMSUNG_REPEAT_PAUSE_MIN 30000
#define INFRARED_SAMSUNG_REPEAT_PAUSE1 46000
#define INFRARED_SAMSUNG_REPEAT_PAUSE2 97000
/* Samsung silence have to be greater than REPEAT MAX
* otherwise there can be problems during unit tests parsing
* of some data. Real tolerances we don't know, but in real life
* silence time should be greater than max repeat time. This is
* because of similar preambule timings for repeat and first messages. */
#define INFRARED_SAMSUNG_MIN_SPLIT_TIME 5000
#define INFRARED_SAMSUNG_SILENCE 145000
#define INFRARED_SAMSUNG_REPEAT_PAUSE_MAX 140000
#define INFRARED_SAMSUNG_REPEAT_MARK 4500
#define INFRARED_SAMSUNG_REPEAT_SPACE 4500
#define INFRARED_SAMSUNG_PREAMBLE_TOLERANCE 200 // us
#define INFRARED_SAMSUNG_BIT_TOLERANCE 120 // us
void* infrared_decoder_samsung32_alloc(void);
void infrared_decoder_samsung32_reset(void* decoder);
void infrared_decoder_samsung32_free(void* decoder);
InfraredMessage* infrared_decoder_samsung32_check_ready(void* ctx);
InfraredMessage* infrared_decoder_samsung32_decode(void* decoder, bool level, uint32_t duration);
InfraredStatus
infrared_encoder_samsung32_encode(void* encoder_ptr, uint32_t* duration, bool* level);
void infrared_encoder_samsung32_reset(void* encoder_ptr, const InfraredMessage* message);
void* infrared_encoder_samsung32_alloc(void);
void infrared_encoder_samsung32_free(void* encoder_ptr);
bool infrared_decoder_samsung32_interpret(InfraredCommonDecoder* decoder);
InfraredStatus infrared_decoder_samsung32_decode_repeat(InfraredCommonDecoder* decoder);
InfraredStatus infrared_encoder_samsung32_encode_repeat(
InfraredCommonEncoder* encoder,
uint32_t* duration,
bool* level);
const InfraredProtocolSpecification* infrared_samsung32_get_spec(InfraredProtocol protocol);
extern const InfraredCommonProtocolSpec protocol_samsung32;
/***************************************************************************************************
* RC6 protocol description
* https://www.mikrocontroller.net/articles/IRMP_-_english#RC6_.2B_RC6A
****************************************************************************************************
* Preamble Manchester/biphase Silence
* mark/space Modulation
*
* 2666 889 444/888 - bit (x2 for toggle bit) 2666
*
* ________ __ __ __ __ ____ __ __ __ __ __ __ __ __
* _ _________ ____ __ __ ____ __ __ __ __ __ __ __ __ _______________
* | 1 | 0 | 0 | 0 | 0 | ... | ... | |
* s m2 m1 m0 T address (MSB) command (MSB)
*
* s - start bit (always 1)
* m0-2 - mode (000 for RC6)
* T - toggle bit, twice longer
* address - 8 bit
* command - 8 bit
***************************************************************************************************/
#define INFRARED_RC6_CARRIER_FREQUENCY 36000
#define INFRARED_RC6_DUTY_CYCLE 0.33
#define INFRARED_RC6_PREAMBLE_MARK 2666
#define INFRARED_RC6_PREAMBLE_SPACE 889
#define INFRARED_RC6_BIT 444 // half of time-quant for 1 bit
#define INFRARED_RC6_PREAMBLE_TOLERANCE 200 // us
#define INFRARED_RC6_BIT_TOLERANCE 120 // us
/* protocol allows 2700 silence, but it is hard to send 1 message without repeat */
#define INFRARED_RC6_SILENCE (2700 * 10)
#define INFRARED_RC6_MIN_SPLIT_TIME 2700
void* infrared_decoder_rc6_alloc(void);
void infrared_decoder_rc6_reset(void* decoder);
void infrared_decoder_rc6_free(void* decoder);
InfraredMessage* infrared_decoder_rc6_check_ready(void* ctx);
InfraredMessage* infrared_decoder_rc6_decode(void* decoder, bool level, uint32_t duration);
void* infrared_encoder_rc6_alloc(void);
void infrared_encoder_rc6_reset(void* encoder_ptr, const InfraredMessage* message);
void infrared_encoder_rc6_free(void* decoder);
InfraredStatus infrared_encoder_rc6_encode(void* encoder_ptr, uint32_t* duration, bool* polarity);
bool infrared_decoder_rc6_interpret(InfraredCommonDecoder* decoder);
InfraredStatus infrared_decoder_rc6_decode_manchester(
InfraredCommonDecoder* decoder,
bool level,
uint32_t timing);
InfraredStatus infrared_encoder_rc6_encode_manchester(
InfraredCommonEncoder* encoder_ptr,
uint32_t* duration,
bool* polarity);
const InfraredProtocolSpecification* infrared_rc6_get_spec(InfraredProtocol protocol);
extern const InfraredCommonProtocolSpec protocol_rc6;
/***************************************************************************************************
* RC5 protocol description
* https://www.mikrocontroller.net/articles/IRMP_-_english#RC5_.2B_RC5X
****************************************************************************************************
* Manchester/biphase
* Modulation
*
* 888/1776 - bit (x2 for toggle bit)
*
* __ ____ __ __ __ __ __ __ __ __
* __ __ ____ __ __ __ __ __ __ __ _
* | 1 | 1 | 0 | ... | ... |
* s si T address (MSB) command (MSB)
*
* Note: manchester starts from space timing, so it have to be handled properly
* s - start bit (always 1)
* si - RC5: start bit (always 1), RC5X - 7-th bit of address (in our case always 0)
* T - toggle bit, change it's value every button press
* address - 5 bit
* command - 6/7 bit
***************************************************************************************************/
#define INFRARED_RC5_CARRIER_FREQUENCY 36000
#define INFRARED_RC5_DUTY_CYCLE 0.33
#define INFRARED_RC5_PREAMBLE_MARK 0
#define INFRARED_RC5_PREAMBLE_SPACE 0
#define INFRARED_RC5_BIT 888 // half of time-quant for 1 bit
#define INFRARED_RC5_PREAMBLE_TOLERANCE 200 // us
#define INFRARED_RC5_BIT_TOLERANCE 120 // us
/* protocol allows 2700 silence, but it is hard to send 1 message without repeat */
#define INFRARED_RC5_SILENCE (2700 * 10)
#define INFRARED_RC5_MIN_SPLIT_TIME 2700
void* infrared_decoder_rc5_alloc(void);
void infrared_decoder_rc5_reset(void* decoder);
void infrared_decoder_rc5_free(void* decoder);
InfraredMessage* infrared_decoder_rc5_check_ready(void* ctx);
InfraredMessage* infrared_decoder_rc5_decode(void* decoder, bool level, uint32_t duration);
void* infrared_encoder_rc5_alloc(void);
void infrared_encoder_rc5_reset(void* encoder_ptr, const InfraredMessage* message);
void infrared_encoder_rc5_free(void* decoder);
InfraredStatus infrared_encoder_rc5_encode(void* encoder_ptr, uint32_t* duration, bool* polarity);
bool infrared_decoder_rc5_interpret(InfraredCommonDecoder* decoder);
const InfraredProtocolSpecification* infrared_rc5_get_spec(InfraredProtocol protocol);
extern const InfraredCommonProtocolSpec protocol_rc5;
/***************************************************************************************************
* Sony SIRC protocol description
* https://www.sbprojects.net/knowledge/ir/sirc.php
* http://picprojects.org.uk/
****************************************************************************************************
* Preamble Preamble Pulse Width Modulation Pause Entirely repeat
* mark space up to period message..
*
* 2400 600 12/15/20 bits (600,1200) ...45000 2400 600
* __________ _ _ _ _ _ _ _ _ _ _ _ _ _ __________ _ _
* ____ __________ _ _ _ __ __ __ _ _ __ __ _ _ ____________________ __________ _
* | command | address |
* SIRC | 7b LSB | 5b LSB |
* SIRC15 | 7b LSB | 8b LSB |
* SIRC20 | 7b LSB | 13b LSB |
*
* No way to determine either next message is repeat or not,
* so recognize only fact message received. Sony remotes always send at least 3 messages.
* Assume 8 last extended bits for SIRC20 are address bits.
***************************************************************************************************/
#define INFRARED_SIRC_CARRIER_FREQUENCY 40000
#define INFRARED_SIRC_DUTY_CYCLE 0.33
#define INFRARED_SIRC_PREAMBLE_MARK 2400
#define INFRARED_SIRC_PREAMBLE_SPACE 600
#define INFRARED_SIRC_BIT1_MARK 1200
#define INFRARED_SIRC_BIT1_SPACE 600
#define INFRARED_SIRC_BIT0_MARK 600
#define INFRARED_SIRC_BIT0_SPACE 600
#define INFRARED_SIRC_PREAMBLE_TOLERANCE 200 // us
#define INFRARED_SIRC_BIT_TOLERANCE 120 // us
#define INFRARED_SIRC_SILENCE 10000
#define INFRARED_SIRC_MIN_SPLIT_TIME (INFRARED_SIRC_SILENCE - 1000)
#define INFRARED_SIRC_REPEAT_PERIOD 45000
void* infrared_decoder_sirc_alloc(void);
void infrared_decoder_sirc_reset(void* decoder);
InfraredMessage* infrared_decoder_sirc_check_ready(void* decoder);
uint32_t infrared_decoder_sirc_get_timeout(void* decoder);
void infrared_decoder_sirc_free(void* decoder);
InfraredMessage* infrared_decoder_sirc_decode(void* decoder, bool level, uint32_t duration);
void* infrared_encoder_sirc_alloc(void);
void infrared_encoder_sirc_reset(void* encoder_ptr, const InfraredMessage* message);
void infrared_encoder_sirc_free(void* decoder);
InfraredStatus infrared_encoder_sirc_encode(void* encoder_ptr, uint32_t* duration, bool* polarity);
bool infrared_decoder_sirc_interpret(InfraredCommonDecoder* decoder);
const InfraredProtocolSpecification* infrared_sirc_get_spec(InfraredProtocol protocol);
InfraredStatus infrared_encoder_sirc_encode_repeat(
InfraredCommonEncoder* encoder,
uint32_t* duration,
bool* level);
extern const InfraredCommonProtocolSpec protocol_sirc;
/***************************************************************************************************
* Kaseikyo protocol description
* https://github.com/Arduino-IRremote/Arduino-IRremote/blob/master/src/ir_Kaseikyo.hpp
****************************************************************************************************
* Preamble Preamble Pulse Distance/Width Pause Preamble Preamble
* mark space Modulation up to period repeat repeat
* mark space
*
* 3360 1665 48 bit ...130000 3456 1728
* __________ _ _ _ _ _ _ _ _ _ _ _ _ _ ___________
* ____ __________ _ _ _ __ __ __ _ _ __ __ _ _ ________________ ___________
*
***************************************************************************************************/
#define INFRARED_KASEIKYO_UNIT 432
#define INFRARED_KASEIKYO_PREAMBLE_MARK (8 * INFRARED_KASEIKYO_UNIT)
#define INFRARED_KASEIKYO_PREAMBLE_SPACE (4 * INFRARED_KASEIKYO_UNIT)
#define INFRARED_KASEIKYO_BIT1_MARK INFRARED_KASEIKYO_UNIT
#define INFRARED_KASEIKYO_BIT1_SPACE (3 * INFRARED_KASEIKYO_UNIT)
#define INFRARED_KASEIKYO_BIT0_MARK INFRARED_KASEIKYO_UNIT
#define INFRARED_KASEIKYO_BIT0_SPACE INFRARED_KASEIKYO_UNIT
#define INFRARED_KASEIKYO_REPEAT_PERIOD 130000
#define INFRARED_KASEIKYO_SILENCE INFRARED_KASEIKYO_REPEAT_PERIOD
#define INFRARED_KASEIKYO_MIN_SPLIT_TIME INFRARED_KASEIKYO_REPEAT_PAUSE_MIN
#define INFRARED_KASEIKYO_REPEAT_PAUSE_MIN 4000
#define INFRARED_KASEIKYO_REPEAT_PAUSE_MAX 150000
#define INFRARED_KASEIKYO_REPEAT_MARK INFRARED_KASEIKYO_PREAMBLE_MARK
#define INFRARED_KASEIKYO_REPEAT_SPACE (INFRARED_KASEIKYO_REPEAT_PERIOD - 56000)
#define INFRARED_KASEIKYO_PREAMBLE_TOLERANCE 200 // us
#define INFRARED_KASEIKYO_BIT_TOLERANCE 120 // us
void* infrared_decoder_kaseikyo_alloc(void);
void infrared_decoder_kaseikyo_reset(void* decoder);
void infrared_decoder_kaseikyo_free(void* decoder);
InfraredMessage* infrared_decoder_kaseikyo_check_ready(void* decoder);
InfraredMessage* infrared_decoder_kaseikyo_decode(void* decoder, bool level, uint32_t duration);
void* infrared_encoder_kaseikyo_alloc(void);
InfraredStatus
infrared_encoder_kaseikyo_encode(void* encoder_ptr, uint32_t* duration, bool* level);
void infrared_encoder_kaseikyo_reset(void* encoder_ptr, const InfraredMessage* message);
void infrared_encoder_kaseikyo_free(void* encoder_ptr);
bool infrared_decoder_kaseikyo_interpret(InfraredCommonDecoder* decoder);
InfraredStatus infrared_decoder_kaseikyo_decode_repeat(InfraredCommonDecoder* decoder);
InfraredStatus infrared_encoder_kaseikyo_encode_repeat(
InfraredCommonEncoder* encoder,
uint32_t* duration,
bool* level);
const InfraredProtocolSpecification* infrared_kaseikyo_get_spec(InfraredProtocol protocol);
extern const InfraredCommonProtocolSpec protocol_kaseikyo;

View file

@ -1,9 +1,5 @@
#include "infrared.h" #include "infrared_protocol_kaseikyo_i.h"
#include "infrared_protocol_defs_i.h" #include <core/check.h>
#include <stdbool.h>
#include <stdint.h>
#include <furi.h>
#include "../infrared_i.h"
InfraredMessage* infrared_decoder_kaseikyo_check_ready(void* ctx) { InfraredMessage* infrared_decoder_kaseikyo_check_ready(void* ctx) {
return infrared_common_decoder_check_ready(ctx); return infrared_common_decoder_check_ready(ctx);
@ -38,7 +34,7 @@ bool infrared_decoder_kaseikyo_interpret(InfraredCommonDecoder* decoder) {
} }
void* infrared_decoder_kaseikyo_alloc(void) { void* infrared_decoder_kaseikyo_alloc(void) {
return infrared_common_decoder_alloc(&protocol_kaseikyo); return infrared_common_decoder_alloc(&infrared_protocol_kaseikyo);
} }
InfraredMessage* infrared_decoder_kaseikyo_decode(void* decoder, bool level, uint32_t duration) { InfraredMessage* infrared_decoder_kaseikyo_decode(void* decoder, bool level, uint32_t duration) {

View file

@ -1,9 +1,5 @@
#include "infrared_protocol_kaseikyo_i.h"
#include <core/check.h> #include <core/check.h>
#include "common/infrared_common_i.h"
#include <stdint.h>
#include "../infrared_i.h"
#include "infrared_protocol_defs_i.h"
#include <furi.h>
void infrared_encoder_kaseikyo_reset(void* encoder_ptr, const InfraredMessage* message) { void infrared_encoder_kaseikyo_reset(void* encoder_ptr, const InfraredMessage* message) {
furi_assert(encoder_ptr); furi_assert(encoder_ptr);
@ -32,7 +28,7 @@ void infrared_encoder_kaseikyo_reset(void* encoder_ptr, const InfraredMessage* m
} }
void* infrared_encoder_kaseikyo_alloc(void) { void* infrared_encoder_kaseikyo_alloc(void) {
return infrared_common_encoder_alloc(&protocol_kaseikyo); return infrared_common_encoder_alloc(&infrared_protocol_kaseikyo);
} }
void infrared_encoder_kaseikyo_free(void* encoder_ptr) { void infrared_encoder_kaseikyo_free(void* encoder_ptr) {

View file

@ -1,17 +0,0 @@
#include "../infrared_i.h"
#include "infrared_protocol_defs_i.h"
static const InfraredProtocolSpecification infrared_kaseikyo_protocol_specification = {
.name = "Kaseikyo",
.address_length = 26,
.command_length = 10,
.frequency = INFRARED_COMMON_CARRIER_FREQUENCY,
.duty_cycle = INFRARED_COMMON_DUTY_CYCLE,
};
const InfraredProtocolSpecification* infrared_kaseikyo_get_spec(InfraredProtocol protocol) {
if(protocol == InfraredProtocolKaseikyo)
return &infrared_kaseikyo_protocol_specification;
else
return NULL;
}

View file

@ -0,0 +1,40 @@
#include "infrared_protocol_kaseikyo_i.h"
const InfraredCommonProtocolSpec infrared_protocol_kaseikyo = {
.timings =
{
.preamble_mark = INFRARED_KASEIKYO_PREAMBLE_MARK,
.preamble_space = INFRARED_KASEIKYO_PREAMBLE_SPACE,
.bit1_mark = INFRARED_KASEIKYO_BIT1_MARK,
.bit1_space = INFRARED_KASEIKYO_BIT1_SPACE,
.bit0_mark = INFRARED_KASEIKYO_BIT0_MARK,
.bit0_space = INFRARED_KASEIKYO_BIT0_SPACE,
.preamble_tolerance = INFRARED_KASEIKYO_PREAMBLE_TOLERANCE,
.bit_tolerance = INFRARED_KASEIKYO_BIT_TOLERANCE,
.silence_time = INFRARED_KASEIKYO_SILENCE,
.min_split_time = INFRARED_KASEIKYO_MIN_SPLIT_TIME,
},
.databit_len[0] = 48,
.no_stop_bit = false,
.decode = infrared_common_decode_pdwm,
.encode = infrared_common_encode_pdwm,
.interpret = infrared_decoder_kaseikyo_interpret,
.decode_repeat = NULL,
.encode_repeat = NULL,
};
static const InfraredProtocolVariant infrared_protocol_variant_kaseikyo = {
.name = "Kaseikyo",
.address_length = 26,
.command_length = 10,
.frequency = INFRARED_COMMON_CARRIER_FREQUENCY,
.duty_cycle = INFRARED_COMMON_DUTY_CYCLE,
.repeat_count = INFRARED_KASEIKYO_REPEAT_COUNT_MIN,
};
const InfraredProtocolVariant* infrared_protocol_kaseikyo_get_variant(InfraredProtocol protocol) {
if(protocol == InfraredProtocolKaseikyo)
return &infrared_protocol_variant_kaseikyo;
else
return NULL;
}

View file

@ -0,0 +1,31 @@
#pragma once
#include "../infrared_i.h"
/***************************************************************************************************
* Kaseikyo protocol description
* https://github.com/Arduino-IRremote/Arduino-IRremote/blob/master/src/ir_Kaseikyo.hpp
****************************************************************************************************
* Preamble Preamble Pulse Distance/Width Pause Preamble Preamble
* mark space Modulation up to period repeat repeat
* mark space
*
* 3360 1665 48 bit ...130000 3456 1728
* __________ _ _ _ _ _ _ _ _ _ _ _ _ _ ___________
* ____ __________ _ _ _ __ __ __ _ _ __ __ _ _ ________________ ___________
*
***************************************************************************************************/
void* infrared_decoder_kaseikyo_alloc(void);
void infrared_decoder_kaseikyo_reset(void* decoder);
void infrared_decoder_kaseikyo_free(void* decoder);
InfraredMessage* infrared_decoder_kaseikyo_check_ready(void* decoder);
InfraredMessage* infrared_decoder_kaseikyo_decode(void* decoder, bool level, uint32_t duration);
void* infrared_encoder_kaseikyo_alloc(void);
InfraredStatus
infrared_encoder_kaseikyo_encode(void* encoder_ptr, uint32_t* duration, bool* level);
void infrared_encoder_kaseikyo_reset(void* encoder_ptr, const InfraredMessage* message);
void infrared_encoder_kaseikyo_free(void* encoder_ptr);
const InfraredProtocolVariant* infrared_protocol_kaseikyo_get_variant(InfraredProtocol protocol);

View file

@ -0,0 +1,30 @@
#pragma once
#include "../common/infrared_common_i.h"
#define INFRARED_KASEIKYO_UNIT 432
#define INFRARED_KASEIKYO_PREAMBLE_MARK (8 * INFRARED_KASEIKYO_UNIT)
#define INFRARED_KASEIKYO_PREAMBLE_SPACE (4 * INFRARED_KASEIKYO_UNIT)
#define INFRARED_KASEIKYO_BIT1_MARK INFRARED_KASEIKYO_UNIT
#define INFRARED_KASEIKYO_BIT1_SPACE (3 * INFRARED_KASEIKYO_UNIT)
#define INFRARED_KASEIKYO_BIT0_MARK INFRARED_KASEIKYO_UNIT
#define INFRARED_KASEIKYO_BIT0_SPACE INFRARED_KASEIKYO_UNIT
#define INFRARED_KASEIKYO_REPEAT_PERIOD 130000
#define INFRARED_KASEIKYO_SILENCE INFRARED_KASEIKYO_REPEAT_PERIOD
#define INFRARED_KASEIKYO_MIN_SPLIT_TIME INFRARED_KASEIKYO_REPEAT_PAUSE_MIN
#define INFRARED_KASEIKYO_REPEAT_PAUSE_MIN 4000
#define INFRARED_KASEIKYO_REPEAT_PAUSE_MAX 150000
#define INFRARED_KASEIKYO_REPEAT_COUNT_MIN 1
#define INFRARED_KASEIKYO_REPEAT_MARK INFRARED_KASEIKYO_PREAMBLE_MARK
#define INFRARED_KASEIKYO_REPEAT_SPACE (INFRARED_KASEIKYO_REPEAT_PERIOD - 56000)
#define INFRARED_KASEIKYO_PREAMBLE_TOLERANCE 200 // us
#define INFRARED_KASEIKYO_BIT_TOLERANCE 120 // us
extern const InfraredCommonProtocolSpec infrared_protocol_kaseikyo;
bool infrared_decoder_kaseikyo_interpret(InfraredCommonDecoder* decoder);
InfraredStatus infrared_decoder_kaseikyo_decode_repeat(InfraredCommonDecoder* decoder);
InfraredStatus infrared_encoder_kaseikyo_encode_repeat(
InfraredCommonEncoder* encoder,
uint32_t* duration,
bool* level);

View file

@ -1,10 +1,5 @@
#include "common/infrared_common_i.h" #include "infrared_protocol_nec_i.h"
#include "infrared.h" #include <core/check.h>
#include "infrared_protocol_defs_i.h"
#include <stdbool.h>
#include <stdint.h>
#include <furi.h>
#include "../infrared_i.h"
InfraredMessage* infrared_decoder_nec_check_ready(void* ctx) { InfraredMessage* infrared_decoder_nec_check_ready(void* ctx) {
return infrared_common_decoder_check_ready(ctx); return infrared_common_decoder_check_ready(ctx);
@ -86,7 +81,7 @@ InfraredStatus infrared_decoder_nec_decode_repeat(InfraredCommonDecoder* decoder
} }
void* infrared_decoder_nec_alloc(void) { void* infrared_decoder_nec_alloc(void) {
return infrared_common_decoder_alloc(&protocol_nec); return infrared_common_decoder_alloc(&infrared_protocol_nec);
} }
InfraredMessage* infrared_decoder_nec_decode(void* decoder, bool level, uint32_t duration) { InfraredMessage* infrared_decoder_nec_decode(void* decoder, bool level, uint32_t duration) {

View file

@ -1,10 +1,7 @@
#include "infrared_protocol_nec_i.h"
#include <core/core_defines.h>
#include <core/check.h> #include <core/check.h>
#include "infrared.h"
#include "common/infrared_common_i.h"
#include <stdint.h>
#include "../infrared_i.h"
#include "infrared_protocol_defs_i.h"
#include <furi.h>
static const uint32_t repeat_timings[] = { static const uint32_t repeat_timings[] = {
INFRARED_NEC_REPEAT_PERIOD - INFRARED_NEC_REPEAT_MARK - INFRARED_NEC_REPEAT_SPACE - INFRARED_NEC_REPEAT_PERIOD - INFRARED_NEC_REPEAT_MARK - INFRARED_NEC_REPEAT_SPACE -
@ -81,7 +78,7 @@ InfraredStatus infrared_encoder_nec_encode_repeat(
} }
void* infrared_encoder_nec_alloc(void) { void* infrared_encoder_nec_alloc(void) {
return infrared_common_encoder_alloc(&protocol_nec); return infrared_common_encoder_alloc(&infrared_protocol_nec);
} }
void infrared_encoder_nec_free(void* encoder_ptr) { void infrared_encoder_nec_free(void* encoder_ptr) {

View file

@ -1,47 +0,0 @@
#include "../infrared_i.h"
#include "infrared_protocol_defs_i.h"
static const InfraredProtocolSpecification infrared_nec_protocol_specification = {
.name = "NEC",
.address_length = 8,
.command_length = 8,
.frequency = INFRARED_COMMON_CARRIER_FREQUENCY,
.duty_cycle = INFRARED_COMMON_DUTY_CYCLE,
};
static const InfraredProtocolSpecification infrared_necext_protocol_specification = {
.name = "NECext",
.address_length = 16,
.command_length = 16,
.frequency = INFRARED_COMMON_CARRIER_FREQUENCY,
.duty_cycle = INFRARED_COMMON_DUTY_CYCLE,
};
static const InfraredProtocolSpecification infrared_nec42_protocol_specification = {
.name = "NEC42",
.address_length = 13,
.command_length = 8,
.frequency = INFRARED_COMMON_CARRIER_FREQUENCY,
.duty_cycle = INFRARED_COMMON_DUTY_CYCLE,
};
static const InfraredProtocolSpecification infrared_nec42ext_protocol_specification = {
.name = "NEC42ext",
.address_length = 26,
.command_length = 16,
.frequency = INFRARED_COMMON_CARRIER_FREQUENCY,
.duty_cycle = INFRARED_COMMON_DUTY_CYCLE,
};
const InfraredProtocolSpecification* infrared_nec_get_spec(InfraredProtocol protocol) {
if(protocol == InfraredProtocolNEC)
return &infrared_nec_protocol_specification;
else if(protocol == InfraredProtocolNECext)
return &infrared_necext_protocol_specification;
else if(protocol == InfraredProtocolNEC42)
return &infrared_nec42_protocol_specification;
else if(protocol == InfraredProtocolNEC42ext)
return &infrared_nec42ext_protocol_specification;
else
return NULL;
}

View file

@ -0,0 +1,74 @@
#include "infrared_protocol_nec_i.h"
const InfraredCommonProtocolSpec infrared_protocol_nec = {
.timings =
{
.preamble_mark = INFRARED_NEC_PREAMBLE_MARK,
.preamble_space = INFRARED_NEC_PREAMBLE_SPACE,
.bit1_mark = INFRARED_NEC_BIT1_MARK,
.bit1_space = INFRARED_NEC_BIT1_SPACE,
.bit0_mark = INFRARED_NEC_BIT0_MARK,
.bit0_space = INFRARED_NEC_BIT0_SPACE,
.preamble_tolerance = INFRARED_NEC_PREAMBLE_TOLERANCE,
.bit_tolerance = INFRARED_NEC_BIT_TOLERANCE,
.silence_time = INFRARED_NEC_SILENCE,
.min_split_time = INFRARED_NEC_MIN_SPLIT_TIME,
},
.databit_len[0] = 42,
.databit_len[1] = 32,
.no_stop_bit = false,
.decode = infrared_common_decode_pdwm,
.encode = infrared_common_encode_pdwm,
.interpret = infrared_decoder_nec_interpret,
.decode_repeat = infrared_decoder_nec_decode_repeat,
.encode_repeat = infrared_encoder_nec_encode_repeat,
};
static const InfraredProtocolVariant infrared_protocol_variant_nec = {
.name = "NEC",
.address_length = 8,
.command_length = 8,
.frequency = INFRARED_COMMON_CARRIER_FREQUENCY,
.duty_cycle = INFRARED_COMMON_DUTY_CYCLE,
.repeat_count = INFRARED_NEC_REPEAT_COUNT_MIN,
};
static const InfraredProtocolVariant infrared_protocol_variant_necext = {
.name = "NECext",
.address_length = 16,
.command_length = 16,
.frequency = INFRARED_COMMON_CARRIER_FREQUENCY,
.duty_cycle = INFRARED_COMMON_DUTY_CYCLE,
.repeat_count = INFRARED_NEC_REPEAT_COUNT_MIN,
};
static const InfraredProtocolVariant infrared_protocol_variant_nec42 = {
.name = "NEC42",
.address_length = 13,
.command_length = 8,
.frequency = INFRARED_COMMON_CARRIER_FREQUENCY,
.duty_cycle = INFRARED_COMMON_DUTY_CYCLE,
.repeat_count = INFRARED_NEC_REPEAT_COUNT_MIN,
};
static const InfraredProtocolVariant infrared_protocol_variant_nec42ext = {
.name = "NEC42ext",
.address_length = 26,
.command_length = 16,
.frequency = INFRARED_COMMON_CARRIER_FREQUENCY,
.duty_cycle = INFRARED_COMMON_DUTY_CYCLE,
.repeat_count = INFRARED_NEC_REPEAT_COUNT_MIN,
};
const InfraredProtocolVariant* infrared_protocol_nec_get_variant(InfraredProtocol protocol) {
if(protocol == InfraredProtocolNEC)
return &infrared_protocol_variant_nec;
else if(protocol == InfraredProtocolNECext)
return &infrared_protocol_variant_necext;
else if(protocol == InfraredProtocolNEC42)
return &infrared_protocol_variant_nec42;
else if(protocol == InfraredProtocolNEC42ext)
return &infrared_protocol_variant_nec42ext;
else
return NULL;
}

View file

@ -0,0 +1,30 @@
#pragma once
#include "../infrared_i.h"
/***************************************************************************************************
* NEC protocol description
* https://radioparty.ru/manuals/encyclopedia/213-ircontrol?start=1
****************************************************************************************************
* Preamble Preamble Pulse Distance/Width Pause Preamble Preamble Stop
* mark space Modulation up to period repeat repeat bit
* mark space
*
* 9000 4500 32 bit + stop bit ...110000 9000 2250
* __________ _ _ _ _ _ _ _ _ _ _ _ _ _ ___________ _
* ____ __________ _ _ _ __ __ __ _ _ __ __ _ _ ________________ ____________ ___
*
***************************************************************************************************/
void* infrared_decoder_nec_alloc(void);
void infrared_decoder_nec_reset(void* decoder);
void infrared_decoder_nec_free(void* decoder);
InfraredMessage* infrared_decoder_nec_check_ready(void* decoder);
InfraredMessage* infrared_decoder_nec_decode(void* decoder, bool level, uint32_t duration);
void* infrared_encoder_nec_alloc(void);
InfraredStatus infrared_encoder_nec_encode(void* encoder_ptr, uint32_t* duration, bool* level);
void infrared_encoder_nec_reset(void* encoder_ptr, const InfraredMessage* message);
void infrared_encoder_nec_free(void* encoder_ptr);
const InfraredProtocolVariant* infrared_protocol_nec_get_variant(InfraredProtocol protocol);

View file

@ -0,0 +1,29 @@
#pragma once
#include "../common/infrared_common_i.h"
#define INFRARED_NEC_PREAMBLE_MARK 9000
#define INFRARED_NEC_PREAMBLE_SPACE 4500
#define INFRARED_NEC_BIT1_MARK 560
#define INFRARED_NEC_BIT1_SPACE 1690
#define INFRARED_NEC_BIT0_MARK 560
#define INFRARED_NEC_BIT0_SPACE 560
#define INFRARED_NEC_REPEAT_PERIOD 110000
#define INFRARED_NEC_SILENCE INFRARED_NEC_REPEAT_PERIOD
#define INFRARED_NEC_MIN_SPLIT_TIME INFRARED_NEC_REPEAT_PAUSE_MIN
#define INFRARED_NEC_REPEAT_PAUSE_MIN 4000
#define INFRARED_NEC_REPEAT_PAUSE_MAX 150000
#define INFRARED_NEC_REPEAT_COUNT_MIN 1
#define INFRARED_NEC_REPEAT_MARK 9000
#define INFRARED_NEC_REPEAT_SPACE 2250
#define INFRARED_NEC_PREAMBLE_TOLERANCE 200 // us
#define INFRARED_NEC_BIT_TOLERANCE 120 // us
extern const InfraredCommonProtocolSpec infrared_protocol_nec;
bool infrared_decoder_nec_interpret(InfraredCommonDecoder* decoder);
InfraredStatus infrared_decoder_nec_decode_repeat(InfraredCommonDecoder* decoder);
InfraredStatus infrared_encoder_nec_encode_repeat(
InfraredCommonEncoder* encoder,
uint32_t* duration,
bool* level);

View file

@ -1,10 +1,7 @@
#include "infrared.h" #include "infrared_protocol_rc5_i.h"
#include <stdbool.h>
#include <stddef.h> #include <stdlib.h>
#include <stdint.h> #include <core/check.h>
#include <furi.h>
#include "../infrared_i.h"
#include "../infrared_protocol_defs_i.h"
typedef struct { typedef struct {
InfraredCommonDecoder* common_decoder; InfraredCommonDecoder* common_decoder;
@ -60,7 +57,7 @@ bool infrared_decoder_rc5_interpret(InfraredCommonDecoder* decoder) {
void* infrared_decoder_rc5_alloc(void) { void* infrared_decoder_rc5_alloc(void) {
InfraredRc5Decoder* decoder = malloc(sizeof(InfraredRc5Decoder)); InfraredRc5Decoder* decoder = malloc(sizeof(InfraredRc5Decoder));
decoder->toggle = false; decoder->toggle = false;
decoder->common_decoder = infrared_common_decoder_alloc(&protocol_rc5); decoder->common_decoder = infrared_common_decoder_alloc(&infrared_protocol_rc5);
decoder->common_decoder->context = decoder; decoder->common_decoder->context = decoder;
return decoder; return decoder;
} }

View file

@ -1,9 +1,7 @@
#include <core/memmgr.h> #include "infrared_protocol_rc5_i.h"
#include "infrared.h"
#include "common/infrared_common_i.h" #include <stdlib.h>
#include "infrared_protocol_defs_i.h" #include <core/check.h>
#include <stdint.h>
#include "../infrared_i.h"
typedef struct InfraredEncoderRC5 { typedef struct InfraredEncoderRC5 {
InfraredCommonEncoder* common_encoder; InfraredCommonEncoder* common_encoder;
@ -41,7 +39,7 @@ InfraredStatus infrared_encoder_rc5_encode(void* encoder_ptr, uint32_t* duration
void* infrared_encoder_rc5_alloc(void) { void* infrared_encoder_rc5_alloc(void) {
InfraredEncoderRC5* encoder = malloc(sizeof(InfraredEncoderRC5)); InfraredEncoderRC5* encoder = malloc(sizeof(InfraredEncoderRC5));
encoder->common_encoder = infrared_common_encoder_alloc(&protocol_rc5); encoder->common_encoder = infrared_common_encoder_alloc(&infrared_protocol_rc5);
encoder->toggle_bit = false; encoder->toggle_bit = false;
return encoder; return encoder;
} }

View file

@ -0,0 +1,49 @@
#include "infrared_protocol_rc5_i.h"
const InfraredCommonProtocolSpec infrared_protocol_rc5 = {
.timings =
{
.preamble_mark = 0,
.preamble_space = 0,
.bit1_mark = INFRARED_RC5_BIT,
.preamble_tolerance = 0,
.bit_tolerance = INFRARED_RC5_BIT_TOLERANCE,
.silence_time = INFRARED_RC5_SILENCE,
.min_split_time = INFRARED_RC5_MIN_SPLIT_TIME,
},
.databit_len[0] = 1 + 1 + 1 + 5 +
6, // start_bit + start_bit/command_bit + toggle_bit + 5 address + 6 command
.manchester_start_from_space = true,
.decode = infrared_common_decode_manchester,
.encode = infrared_common_encode_manchester,
.interpret = infrared_decoder_rc5_interpret,
.decode_repeat = NULL,
.encode_repeat = NULL,
};
static const InfraredProtocolVariant infrared_protocol_variant_rc5 = {
.name = "RC5",
.address_length = 5,
.command_length = 6,
.frequency = INFRARED_RC5_CARRIER_FREQUENCY,
.duty_cycle = INFRARED_RC5_DUTY_CYCLE,
.repeat_count = INFRARED_RC5_REPEAT_COUNT_MIN,
};
static const InfraredProtocolVariant infrared_protocol_variant_rc5x = {
.name = "RC5X",
.address_length = 5,
.command_length = 7,
.frequency = INFRARED_RC5_CARRIER_FREQUENCY,
.duty_cycle = INFRARED_RC5_DUTY_CYCLE,
.repeat_count = INFRARED_RC5_REPEAT_COUNT_MIN,
};
const InfraredProtocolVariant* infrared_protocol_rc5_get_variant(InfraredProtocol protocol) {
if(protocol == InfraredProtocolRC5)
return &infrared_protocol_variant_rc5;
else if(protocol == InfraredProtocolRC5X)
return &infrared_protocol_variant_rc5x;
else
return NULL;
}

View file

@ -0,0 +1,38 @@
#pragma once
#include "../infrared_i.h"
/***************************************************************************************************
* RC5 protocol description
* https://www.mikrocontroller.net/articles/IRMP_-_english#RC5_.2B_RC5X
****************************************************************************************************
* Manchester/biphase
* Modulation
*
* 888/1776 - bit (x2 for toggle bit)
*
* __ ____ __ __ __ __ __ __ __ __
* __ __ ____ __ __ __ __ __ __ __ _
* | 1 | 1 | 0 | ... | ... |
* s si T address (MSB) command (MSB)
*
* Note: manchester starts from space timing, so it have to be handled properly
* s - start bit (always 1)
* si - RC5: start bit (always 1), RC5X - 7-th bit of address (in our case always 0)
* T - toggle bit, change it's value every button press
* address - 5 bit
* command - 6/7 bit
***************************************************************************************************/
void* infrared_decoder_rc5_alloc(void);
void infrared_decoder_rc5_reset(void* decoder);
void infrared_decoder_rc5_free(void* decoder);
InfraredMessage* infrared_decoder_rc5_check_ready(void* ctx);
InfraredMessage* infrared_decoder_rc5_decode(void* decoder, bool level, uint32_t duration);
void* infrared_encoder_rc5_alloc(void);
void infrared_encoder_rc5_reset(void* encoder_ptr, const InfraredMessage* message);
void infrared_encoder_rc5_free(void* decoder);
InfraredStatus infrared_encoder_rc5_encode(void* encoder_ptr, uint32_t* duration, bool* polarity);
const InfraredProtocolVariant* infrared_protocol_rc5_get_variant(InfraredProtocol protocol);

View file

@ -0,0 +1,20 @@
#pragma once
#include "../common/infrared_common_i.h"
#define INFRARED_RC5_CARRIER_FREQUENCY 36000
#define INFRARED_RC5_DUTY_CYCLE 0.33
#define INFRARED_RC5_PREAMBLE_MARK 0
#define INFRARED_RC5_PREAMBLE_SPACE 0
#define INFRARED_RC5_BIT 888 // half of time-quant for 1 bit
#define INFRARED_RC5_PREAMBLE_TOLERANCE 200 // us
#define INFRARED_RC5_BIT_TOLERANCE 120 // us
/* protocol allows 2700 silence, but it is hard to send 1 message without repeat */
#define INFRARED_RC5_SILENCE (2700 * 10)
#define INFRARED_RC5_MIN_SPLIT_TIME 2700
#define INFRARED_RC5_REPEAT_COUNT_MIN 1
extern const InfraredCommonProtocolSpec infrared_protocol_rc5;
bool infrared_decoder_rc5_interpret(InfraredCommonDecoder* decoder);

View file

@ -1,27 +0,0 @@
#include "../infrared_i.h"
#include "infrared_protocol_defs_i.h"
static const InfraredProtocolSpecification infrared_rc5_protocol_specification = {
.name = "RC5",
.address_length = 5,
.command_length = 6,
.frequency = INFRARED_RC5_CARRIER_FREQUENCY,
.duty_cycle = INFRARED_RC5_DUTY_CYCLE,
};
static const InfraredProtocolSpecification infrared_rc5x_protocol_specification = {
.name = "RC5X",
.address_length = 5,
.command_length = 7,
.frequency = INFRARED_RC5_CARRIER_FREQUENCY,
.duty_cycle = INFRARED_RC5_DUTY_CYCLE,
};
const InfraredProtocolSpecification* infrared_rc5_get_spec(InfraredProtocol protocol) {
if(protocol == InfraredProtocolRC5)
return &infrared_rc5_protocol_specification;
else if(protocol == InfraredProtocolRC5X)
return &infrared_rc5x_protocol_specification;
else
return NULL;
}

View file

@ -1,10 +1,7 @@
#include "infrared.h" #include "infrared_protocol_rc6_i.h"
#include <stdbool.h>
#include <stddef.h> #include <stdlib.h>
#include <stdint.h> #include <core/check.h>
#include <furi.h>
#include "../infrared_i.h"
#include "../infrared_protocol_defs_i.h"
typedef struct { typedef struct {
InfraredCommonDecoder* common_decoder; InfraredCommonDecoder* common_decoder;
@ -93,7 +90,7 @@ InfraredStatus infrared_decoder_rc6_decode_manchester(
void* infrared_decoder_rc6_alloc(void) { void* infrared_decoder_rc6_alloc(void) {
InfraredRc6Decoder* decoder = malloc(sizeof(InfraredRc6Decoder)); InfraredRc6Decoder* decoder = malloc(sizeof(InfraredRc6Decoder));
decoder->toggle = false; decoder->toggle = false;
decoder->common_decoder = infrared_common_decoder_alloc(&protocol_rc6); decoder->common_decoder = infrared_common_decoder_alloc(&infrared_protocol_rc6);
decoder->common_decoder->context = decoder; decoder->common_decoder->context = decoder;
return decoder; return decoder;
} }

View file

@ -1,9 +1,7 @@
#include <core/memmgr.h> #include "infrared_protocol_rc6_i.h"
#include "infrared.h"
#include "common/infrared_common_i.h" #include <stdlib.h>
#include "infrared_protocol_defs_i.h" #include <core/check.h>
#include <stdint.h>
#include "../infrared_i.h"
typedef struct InfraredEncoderRC6 { typedef struct InfraredEncoderRC6 {
InfraredCommonEncoder* common_encoder; InfraredCommonEncoder* common_encoder;
@ -35,7 +33,7 @@ InfraredStatus infrared_encoder_rc6_encode(void* encoder_ptr, uint32_t* duration
void* infrared_encoder_rc6_alloc(void) { void* infrared_encoder_rc6_alloc(void) {
InfraredEncoderRC6* encoder = malloc(sizeof(InfraredEncoderRC6)); InfraredEncoderRC6* encoder = malloc(sizeof(InfraredEncoderRC6));
encoder->common_encoder = infrared_common_encoder_alloc(&protocol_rc6); encoder->common_encoder = infrared_common_encoder_alloc(&infrared_protocol_rc6);
encoder->toggle_bit = false; encoder->toggle_bit = false;
return encoder; return encoder;
} }

View file

@ -0,0 +1,39 @@
#include "infrared_protocol_rc6_i.h"
const InfraredCommonProtocolSpec infrared_protocol_rc6 = {
.timings =
{
.preamble_mark = INFRARED_RC6_PREAMBLE_MARK,
.preamble_space = INFRARED_RC6_PREAMBLE_SPACE,
.bit1_mark = INFRARED_RC6_BIT,
.preamble_tolerance = INFRARED_RC6_PREAMBLE_TOLERANCE,
.bit_tolerance = INFRARED_RC6_BIT_TOLERANCE,
.silence_time = INFRARED_RC6_SILENCE,
.min_split_time = INFRARED_RC6_MIN_SPLIT_TIME,
},
.databit_len[0] =
1 + 3 + 1 + 8 +
8, // start_bit + 3 mode bits, + 1 toggle bit (x2 timing) + 8 address + 8 command
.manchester_start_from_space = false,
.decode = infrared_decoder_rc6_decode_manchester,
.encode = infrared_encoder_rc6_encode_manchester,
.interpret = infrared_decoder_rc6_interpret,
.decode_repeat = NULL,
.encode_repeat = NULL,
};
static const InfraredProtocolVariant infrared_protocol_variant_rc6 = {
.name = "RC6",
.address_length = 8,
.command_length = 8,
.frequency = INFRARED_RC6_CARRIER_FREQUENCY,
.duty_cycle = INFRARED_RC6_DUTY_CYCLE,
.repeat_count = INFRARED_RC6_REPEAT_COUNT_MIN,
};
const InfraredProtocolVariant* infrared_protocol_rc6_get_variant(InfraredProtocol protocol) {
if(protocol == InfraredProtocolRC6)
return &infrared_protocol_variant_rc6;
else
return NULL;
}

View file

@ -0,0 +1,37 @@
#pragma once
#include "../infrared_i.h"
/***************************************************************************************************
* RC6 protocol description
* https://www.mikrocontroller.net/articles/IRMP_-_english#RC6_.2B_RC6A
****************************************************************************************************
* Preamble Manchester/biphase Silence
* mark/space Modulation
*
* 2666 889 444/888 - bit (x2 for toggle bit) 2666
*
* ________ __ __ __ __ ____ __ __ __ __ __ __ __ __
* _ _________ ____ __ __ ____ __ __ __ __ __ __ __ __ _______________
* | 1 | 0 | 0 | 0 | 0 | ... | ... | |
* s m2 m1 m0 T address (MSB) command (MSB)
*
* s - start bit (always 1)
* m0-2 - mode (000 for RC6)
* T - toggle bit, twice longer
* address - 8 bit
* command - 8 bit
***************************************************************************************************/
void* infrared_decoder_rc6_alloc(void);
void infrared_decoder_rc6_reset(void* decoder);
void infrared_decoder_rc6_free(void* decoder);
InfraredMessage* infrared_decoder_rc6_check_ready(void* ctx);
InfraredMessage* infrared_decoder_rc6_decode(void* decoder, bool level, uint32_t duration);
void* infrared_encoder_rc6_alloc(void);
void infrared_encoder_rc6_reset(void* encoder_ptr, const InfraredMessage* message);
void infrared_encoder_rc6_free(void* decoder);
InfraredStatus infrared_encoder_rc6_encode(void* encoder_ptr, uint32_t* duration, bool* polarity);
const InfraredProtocolVariant* infrared_protocol_rc6_get_variant(InfraredProtocol protocol);

View file

@ -0,0 +1,28 @@
#pragma once
#include "../common/infrared_common_i.h"
#define INFRARED_RC6_CARRIER_FREQUENCY 36000
#define INFRARED_RC6_DUTY_CYCLE 0.33
#define INFRARED_RC6_PREAMBLE_MARK 2666
#define INFRARED_RC6_PREAMBLE_SPACE 889
#define INFRARED_RC6_BIT 444 // half of time-quant for 1 bit
#define INFRARED_RC6_PREAMBLE_TOLERANCE 200 // us
#define INFRARED_RC6_BIT_TOLERANCE 120 // us
/* protocol allows 2700 silence, but it is hard to send 1 message without repeat */
#define INFRARED_RC6_SILENCE (2700 * 10)
#define INFRARED_RC6_MIN_SPLIT_TIME 2700
#define INFRARED_RC6_REPEAT_COUNT_MIN 1
extern const InfraredCommonProtocolSpec infrared_protocol_rc6;
bool infrared_decoder_rc6_interpret(InfraredCommonDecoder* decoder);
InfraredStatus infrared_decoder_rc6_decode_manchester(
InfraredCommonDecoder* decoder,
bool level,
uint32_t timing);
InfraredStatus infrared_encoder_rc6_encode_manchester(
InfraredCommonEncoder* encoder_ptr,
uint32_t* duration,
bool* polarity);

View file

@ -1,17 +0,0 @@
#include "../infrared_i.h"
#include "infrared_protocol_defs_i.h"
static const InfraredProtocolSpecification infrared_rc6_protocol_specification = {
.name = "RC6",
.address_length = 8,
.command_length = 8,
.frequency = INFRARED_RC6_CARRIER_FREQUENCY,
.duty_cycle = INFRARED_RC6_DUTY_CYCLE,
};
const InfraredProtocolSpecification* infrared_rc6_get_spec(InfraredProtocol protocol) {
if(protocol == InfraredProtocolRC6)
return &infrared_rc6_protocol_specification;
else
return NULL;
}

View file

@ -1,9 +1,5 @@
#include "infrared.h" #include "infrared_protocol_samsung_i.h"
#include "infrared_protocol_defs_i.h" #include <core/check.h>
#include <stdbool.h>
#include <stdint.h>
#include <furi.h>
#include "../infrared_i.h"
InfraredMessage* infrared_decoder_samsung32_check_ready(void* ctx) { InfraredMessage* infrared_decoder_samsung32_check_ready(void* ctx) {
return infrared_common_decoder_check_ready(ctx); return infrared_common_decoder_check_ready(ctx);
@ -57,7 +53,7 @@ InfraredStatus infrared_decoder_samsung32_decode_repeat(InfraredCommonDecoder* d
} }
void* infrared_decoder_samsung32_alloc(void) { void* infrared_decoder_samsung32_alloc(void) {
return infrared_common_decoder_alloc(&protocol_samsung32); return infrared_common_decoder_alloc(&infrared_protocol_samsung32);
} }
InfraredMessage* infrared_decoder_samsung32_decode(void* decoder, bool level, uint32_t duration) { InfraredMessage* infrared_decoder_samsung32_decode(void* decoder, bool level, uint32_t duration) {

View file

@ -1,9 +1,7 @@
#include "infrared_protocol_samsung_i.h"
#include <core/check.h> #include <core/check.h>
#include "common/infrared_common_i.h" #include <core/common_defines.h>
#include <stdint.h>
#include "../infrared_i.h"
#include "infrared_protocol_defs_i.h"
#include <furi.h>
static const uint32_t repeat_timings[] = { static const uint32_t repeat_timings[] = {
INFRARED_SAMSUNG_REPEAT_PAUSE2, INFRARED_SAMSUNG_REPEAT_PAUSE2,
@ -58,7 +56,7 @@ InfraredStatus infrared_encoder_samsung32_encode_repeat(
} }
void* infrared_encoder_samsung32_alloc(void) { void* infrared_encoder_samsung32_alloc(void) {
return infrared_common_encoder_alloc(&protocol_samsung32); return infrared_common_encoder_alloc(&infrared_protocol_samsung32);
} }
void infrared_encoder_samsung32_free(void* encoder_ptr) { void infrared_encoder_samsung32_free(void* encoder_ptr) {

View file

@ -0,0 +1,40 @@
#include "infrared_protocol_samsung_i.h"
const InfraredCommonProtocolSpec infrared_protocol_samsung32 = {
.timings =
{
.preamble_mark = INFRARED_SAMSUNG_PREAMBLE_MARK,
.preamble_space = INFRARED_SAMSUNG_PREAMBLE_SPACE,
.bit1_mark = INFRARED_SAMSUNG_BIT1_MARK,
.bit1_space = INFRARED_SAMSUNG_BIT1_SPACE,
.bit0_mark = INFRARED_SAMSUNG_BIT0_MARK,
.bit0_space = INFRARED_SAMSUNG_BIT0_SPACE,
.preamble_tolerance = INFRARED_SAMSUNG_PREAMBLE_TOLERANCE,
.bit_tolerance = INFRARED_SAMSUNG_BIT_TOLERANCE,
.silence_time = INFRARED_SAMSUNG_SILENCE,
.min_split_time = INFRARED_SAMSUNG_MIN_SPLIT_TIME,
},
.databit_len[0] = 32,
.no_stop_bit = false,
.decode = infrared_common_decode_pdwm,
.encode = infrared_common_encode_pdwm,
.interpret = infrared_decoder_samsung32_interpret,
.decode_repeat = infrared_decoder_samsung32_decode_repeat,
.encode_repeat = infrared_encoder_samsung32_encode_repeat,
};
static const InfraredProtocolVariant infrared_protocol_variant_samsung32 = {
.name = "Samsung32",
.address_length = 8,
.command_length = 8,
.frequency = INFRARED_COMMON_CARRIER_FREQUENCY,
.duty_cycle = INFRARED_COMMON_DUTY_CYCLE,
.repeat_count = INFRARED_SAMSUNG_REPEAT_COUNT_MIN,
};
const InfraredProtocolVariant* infrared_protocol_samsung32_get_variant(InfraredProtocol protocol) {
if(protocol == InfraredProtocolSamsung32)
return &infrared_protocol_variant_samsung32;
else
return NULL;
}

View file

@ -0,0 +1,31 @@
#pragma once
#include "../infrared_i.h"
/***************************************************************************************************
* SAMSUNG32 protocol description
* https://www.mikrocontroller.net/articles/IRMP_-_english#SAMSUNG
****************************************************************************************************
* Preamble Preamble Pulse Distance/Width Pause Preamble Preamble Bit1 Stop
* mark space Modulation repeat repeat bit
* mark space
*
* 4500 4500 32 bit + stop bit 40000/100000 4500 4500
* __________ _ _ _ _ _ _ _ _ _ _ _ ___________ _ _
* _ __________ __ _ __ __ __ _ _ __ __ _ ________________ ____________ ____ ___
*
***************************************************************************************************/
void* infrared_decoder_samsung32_alloc(void);
void infrared_decoder_samsung32_reset(void* decoder);
void infrared_decoder_samsung32_free(void* decoder);
InfraredMessage* infrared_decoder_samsung32_check_ready(void* ctx);
InfraredMessage* infrared_decoder_samsung32_decode(void* decoder, bool level, uint32_t duration);
InfraredStatus
infrared_encoder_samsung32_encode(void* encoder_ptr, uint32_t* duration, bool* level);
void infrared_encoder_samsung32_reset(void* encoder_ptr, const InfraredMessage* message);
void* infrared_encoder_samsung32_alloc(void);
void infrared_encoder_samsung32_free(void* encoder_ptr);
const InfraredProtocolVariant* infrared_protocol_samsung32_get_variant(InfraredProtocol protocol);

View file

@ -0,0 +1,35 @@
#pragma once
#include "../common/infrared_common_i.h"
#define INFRARED_SAMSUNG_PREAMBLE_MARK 4500
#define INFRARED_SAMSUNG_PREAMBLE_SPACE 4500
#define INFRARED_SAMSUNG_BIT1_MARK 550
#define INFRARED_SAMSUNG_BIT1_SPACE 1650
#define INFRARED_SAMSUNG_BIT0_MARK 550
#define INFRARED_SAMSUNG_BIT0_SPACE 550
#define INFRARED_SAMSUNG_REPEAT_PAUSE_MIN 30000
#define INFRARED_SAMSUNG_REPEAT_PAUSE_MAX 140000
#define INFRARED_SAMSUNG_REPEAT_PAUSE1 46000
#define INFRARED_SAMSUNG_REPEAT_PAUSE2 97000
#define INFRARED_SAMSUNG_REPEAT_COUNT_MIN 1
/* Samsung silence have to be greater than REPEAT MAX
* otherwise there can be problems during unit tests parsing
* of some data. Real tolerances we don't know, but in real life
* silence time should be greater than max repeat time. This is
* because of similar preambule timings for repeat and first messages. */
#define INFRARED_SAMSUNG_MIN_SPLIT_TIME 5000
#define INFRARED_SAMSUNG_SILENCE 145000
#define INFRARED_SAMSUNG_REPEAT_MARK 4500
#define INFRARED_SAMSUNG_REPEAT_SPACE 4500
#define INFRARED_SAMSUNG_PREAMBLE_TOLERANCE 200 // us
#define INFRARED_SAMSUNG_BIT_TOLERANCE 120 // us
bool infrared_decoder_samsung32_interpret(InfraredCommonDecoder* decoder);
InfraredStatus infrared_decoder_samsung32_decode_repeat(InfraredCommonDecoder* decoder);
InfraredStatus infrared_encoder_samsung32_encode_repeat(
InfraredCommonEncoder* encoder,
uint32_t* duration,
bool* level);
extern const InfraredCommonProtocolSpec infrared_protocol_samsung32;

View file

@ -1,17 +0,0 @@
#include "../infrared_i.h"
#include "infrared_protocol_defs_i.h"
static const InfraredProtocolSpecification infrared_samsung32_protocol_specification = {
.name = "Samsung32",
.address_length = 8,
.command_length = 8,
.frequency = INFRARED_COMMON_CARRIER_FREQUENCY,
.duty_cycle = INFRARED_COMMON_DUTY_CYCLE,
};
const InfraredProtocolSpecification* infrared_samsung32_get_spec(InfraredProtocol protocol) {
if(protocol == InfraredProtocolSamsung32)
return &infrared_samsung32_protocol_specification;
else
return NULL;
}

View file

@ -1,10 +1,5 @@
#include "common/infrared_common_i.h" #include "infrared_protocol_sirc_i.h"
#include "infrared.h" #include <core/check.h>
#include "infrared_protocol_defs_i.h"
#include <stdbool.h>
#include <stdint.h>
#include <furi.h>
#include "../infrared_i.h"
InfraredMessage* infrared_decoder_sirc_check_ready(void* ctx) { InfraredMessage* infrared_decoder_sirc_check_ready(void* ctx) {
return infrared_common_decoder_check_ready(ctx); return infrared_common_decoder_check_ready(ctx);
@ -44,7 +39,7 @@ bool infrared_decoder_sirc_interpret(InfraredCommonDecoder* decoder) {
} }
void* infrared_decoder_sirc_alloc(void) { void* infrared_decoder_sirc_alloc(void) {
return infrared_common_decoder_alloc(&protocol_sirc); return infrared_common_decoder_alloc(&infrared_protocol_sirc);
} }
InfraredMessage* infrared_decoder_sirc_decode(void* decoder, bool level, uint32_t duration) { InfraredMessage* infrared_decoder_sirc_decode(void* decoder, bool level, uint32_t duration) {

View file

@ -1,10 +1,5 @@
#include "infrared_protocol_sirc_i.h"
#include <core/check.h> #include <core/check.h>
#include "infrared.h"
#include "common/infrared_common_i.h"
#include <stdint.h>
#include "../infrared_i.h"
#include "infrared_protocol_defs_i.h"
#include <furi.h>
void infrared_encoder_sirc_reset(void* encoder_ptr, const InfraredMessage* message) { void infrared_encoder_sirc_reset(void* encoder_ptr, const InfraredMessage* message) {
furi_assert(encoder_ptr); furi_assert(encoder_ptr);
@ -53,7 +48,7 @@ InfraredStatus infrared_encoder_sirc_encode_repeat(
} }
void* infrared_encoder_sirc_alloc(void) { void* infrared_encoder_sirc_alloc(void) {
return infrared_common_encoder_alloc(&protocol_sirc); return infrared_common_encoder_alloc(&infrared_protocol_sirc);
} }
void infrared_encoder_sirc_free(void* encoder_ptr) { void infrared_encoder_sirc_free(void* encoder_ptr) {

View file

@ -0,0 +1,64 @@
#include "infrared_protocol_sirc_i.h"
const InfraredCommonProtocolSpec infrared_protocol_sirc = {
.timings =
{
.preamble_mark = INFRARED_SIRC_PREAMBLE_MARK,
.preamble_space = INFRARED_SIRC_PREAMBLE_SPACE,
.bit1_mark = INFRARED_SIRC_BIT1_MARK,
.bit1_space = INFRARED_SIRC_BIT1_SPACE,
.bit0_mark = INFRARED_SIRC_BIT0_MARK,
.bit0_space = INFRARED_SIRC_BIT0_SPACE,
.preamble_tolerance = INFRARED_SIRC_PREAMBLE_TOLERANCE,
.bit_tolerance = INFRARED_SIRC_BIT_TOLERANCE,
.silence_time = INFRARED_SIRC_SILENCE,
.min_split_time = INFRARED_SIRC_MIN_SPLIT_TIME,
},
.databit_len[0] = 20,
.databit_len[1] = 15,
.databit_len[2] = 12,
.no_stop_bit = true,
.decode = infrared_common_decode_pdwm,
.encode = infrared_common_encode_pdwm,
.interpret = infrared_decoder_sirc_interpret,
.decode_repeat = NULL,
.encode_repeat = infrared_encoder_sirc_encode_repeat,
};
static const InfraredProtocolVariant infrared_protocol_variant_sirc = {
.name = "SIRC",
.address_length = 5,
.command_length = 7,
.frequency = INFRARED_SIRC_CARRIER_FREQUENCY,
.duty_cycle = INFRARED_SIRC_DUTY_CYCLE,
.repeat_count = INFRARED_SIRC_REPEAT_COUNT_MIN,
};
static const InfraredProtocolVariant infrared_protocol_variant_sirc15 = {
.name = "SIRC15",
.address_length = 8,
.command_length = 7,
.frequency = INFRARED_SIRC_CARRIER_FREQUENCY,
.duty_cycle = INFRARED_SIRC_DUTY_CYCLE,
.repeat_count = INFRARED_SIRC_REPEAT_COUNT_MIN,
};
static const InfraredProtocolVariant infrared_protocol_variant_sirc20 = {
.name = "SIRC20",
.address_length = 13,
.command_length = 7,
.frequency = INFRARED_SIRC_CARRIER_FREQUENCY,
.duty_cycle = INFRARED_SIRC_DUTY_CYCLE,
.repeat_count = INFRARED_SIRC_REPEAT_COUNT_MIN,
};
const InfraredProtocolVariant* infrared_protocol_sirc_get_variant(InfraredProtocol protocol) {
if(protocol == InfraredProtocolSIRC)
return &infrared_protocol_variant_sirc;
else if(protocol == InfraredProtocolSIRC15)
return &infrared_protocol_variant_sirc15;
else if(protocol == InfraredProtocolSIRC20)
return &infrared_protocol_variant_sirc20;
else
return NULL;
}

View file

@ -0,0 +1,37 @@
#pragma once
#include "../infrared_i.h"
/***************************************************************************************************
* Sony SIRC protocol description
* https://www.sbprojects.net/knowledge/ir/sirc.php
* http://picprojects.org.uk/
****************************************************************************************************
* Preamble Preamble Pulse Width Modulation Pause Entirely repeat
* mark space up to period message..
*
* 2400 600 12/15/20 bits (600,1200) ...45000 2400 600
* __________ _ _ _ _ _ _ _ _ _ _ _ _ _ __________ _ _
* ____ __________ _ _ _ __ __ __ _ _ __ __ _ _ ____________________ __________ _
* | command | address |
* SIRC | 7b LSB | 5b LSB |
* SIRC15 | 7b LSB | 8b LSB |
* SIRC20 | 7b LSB | 13b LSB |
*
* No way to determine either next message is repeat or not,
* so recognize only fact message received. Sony remotes always send at least 3 messages.
* Assume 8 last extended bits for SIRC20 are address bits.
***************************************************************************************************/
void* infrared_decoder_sirc_alloc(void);
void infrared_decoder_sirc_reset(void* decoder);
InfraredMessage* infrared_decoder_sirc_check_ready(void* decoder);
void infrared_decoder_sirc_free(void* decoder);
InfraredMessage* infrared_decoder_sirc_decode(void* decoder, bool level, uint32_t duration);
void* infrared_encoder_sirc_alloc(void);
void infrared_encoder_sirc_reset(void* encoder_ptr, const InfraredMessage* message);
void infrared_encoder_sirc_free(void* decoder);
InfraredStatus infrared_encoder_sirc_encode(void* encoder_ptr, uint32_t* duration, bool* polarity);
const InfraredProtocolVariant* infrared_protocol_sirc_get_variant(InfraredProtocol protocol);

View file

@ -0,0 +1,26 @@
#pragma once
#include "../common/infrared_common_i.h"
#define INFRARED_SIRC_CARRIER_FREQUENCY 40000
#define INFRARED_SIRC_DUTY_CYCLE 0.33
#define INFRARED_SIRC_PREAMBLE_MARK 2400
#define INFRARED_SIRC_PREAMBLE_SPACE 600
#define INFRARED_SIRC_BIT1_MARK 1200
#define INFRARED_SIRC_BIT1_SPACE 600
#define INFRARED_SIRC_BIT0_MARK 600
#define INFRARED_SIRC_BIT0_SPACE 600
#define INFRARED_SIRC_PREAMBLE_TOLERANCE 200 // us
#define INFRARED_SIRC_BIT_TOLERANCE 120 // us
#define INFRARED_SIRC_SILENCE 10000
#define INFRARED_SIRC_MIN_SPLIT_TIME (INFRARED_SIRC_SILENCE - 1000)
#define INFRARED_SIRC_REPEAT_PERIOD 45000
#define INFRARED_SIRC_REPEAT_COUNT_MIN 3
extern const InfraredCommonProtocolSpec infrared_protocol_sirc;
bool infrared_decoder_sirc_interpret(InfraredCommonDecoder* decoder);
InfraredStatus infrared_encoder_sirc_encode_repeat(
InfraredCommonEncoder* encoder,
uint32_t* duration,
bool* level);

View file

@ -1,37 +0,0 @@
#include "../infrared_i.h"
#include "infrared_protocol_defs_i.h"
static const InfraredProtocolSpecification infrared_sirc_protocol_specification = {
.name = "SIRC",
.address_length = 5,
.command_length = 7,
.frequency = INFRARED_SIRC_CARRIER_FREQUENCY,
.duty_cycle = INFRARED_SIRC_DUTY_CYCLE,
};
static const InfraredProtocolSpecification infrared_sirc15_protocol_specification = {
.name = "SIRC15",
.address_length = 8,
.command_length = 7,
.frequency = INFRARED_SIRC_CARRIER_FREQUENCY,
.duty_cycle = INFRARED_SIRC_DUTY_CYCLE,
};
static const InfraredProtocolSpecification infrared_sirc20_protocol_specification = {
.name = "SIRC20",
.address_length = 13,
.command_length = 7,
.frequency = INFRARED_SIRC_CARRIER_FREQUENCY,
.duty_cycle = INFRARED_SIRC_DUTY_CYCLE,
};
const InfraredProtocolSpecification* infrared_sirc_get_spec(InfraredProtocol protocol) {
if(protocol == InfraredProtocolSIRC)
return &infrared_sirc_protocol_specification;
else if(protocol == InfraredProtocolSIRC15)
return &infrared_sirc15_protocol_specification;
else if(protocol == InfraredProtocolSIRC20)
return &infrared_sirc20_protocol_specification;
else
return NULL;
}

View file

@ -101,7 +101,8 @@ void infrared_send(const InfraredMessage* message, int times) {
InfraredEncoderHandler* handler = infrared_alloc_encoder(); InfraredEncoderHandler* handler = infrared_alloc_encoder();
infrared_reset_encoder(handler, message); infrared_reset_encoder(handler, message);
infrared_tx_number_of_transmissions = times; infrared_tx_number_of_transmissions =
MAX((int)infrared_get_protocol_min_repeat_count(message->protocol), times);
uint32_t frequency = infrared_get_protocol_frequency(message->protocol); uint32_t frequency = infrared_get_protocol_frequency(message->protocol);
float duty_cycle = infrared_get_protocol_duty_cycle(message->protocol); float duty_cycle = infrared_get_protocol_duty_cycle(message->protocol);

View file

@ -1,13 +1,10 @@
#include "infrared_worker.h"
#include <furi_hal_infrared.h>
#include <float_tools.h>
#include <core/check.h> #include <core/check.h>
#include <core/common_defines.h> #include <core/common_defines.h>
#include "sys/_stdint.h"
#include "infrared_worker.h"
#include <infrared.h>
#include <furi_hal_infrared.h>
#include <limits.h>
#include <stdint.h>
#include <furi.h>
#include <float_tools.h>
#include <notification/notification_messages.h> #include <notification/notification_messages.h>
@ -471,18 +468,23 @@ static int32_t infrared_worker_tx_thread(void* thread_context) {
furi_assert(instance->state == InfraredWorkerStateStartTx); furi_assert(instance->state == InfraredWorkerStateStartTx);
furi_assert(thread_context); furi_assert(thread_context);
size_t repeats_left =
instance->signal.decoded ?
infrared_get_protocol_min_repeat_count(instance->signal.message.protocol) :
1;
uint32_t events = 0; uint32_t events = 0;
bool new_data_available = true;
bool exit = false;
exit = !infrared_get_new_signal(instance); bool exit_pending = false;
furi_assert(!exit);
while(!exit) { bool running = infrared_get_new_signal(instance);
furi_assert(running);
while(running) {
switch(instance->state) { switch(instance->state) {
case InfraredWorkerStateStartTx: case InfraredWorkerStateStartTx:
--repeats_left; /* The first message does not result in TX_MESSAGE_SENT event for some reason */
instance->tx.need_reinitialization = false; instance->tx.need_reinitialization = false;
new_data_available = infrared_worker_tx_fill_buffer(instance); const bool new_data_available = infrared_worker_tx_fill_buffer(instance);
furi_hal_infrared_async_tx_start(instance->tx.frequency, instance->tx.duty_cycle); furi_hal_infrared_async_tx_start(instance->tx.frequency, instance->tx.duty_cycle);
if(!new_data_available) { if(!new_data_available) {
@ -496,7 +498,7 @@ static int32_t infrared_worker_tx_thread(void* thread_context) {
break; break;
case InfraredWorkerStateStopTx: case InfraredWorkerStateStopTx:
furi_hal_infrared_async_tx_stop(); furi_hal_infrared_async_tx_stop();
exit = true; running = false;
break; break;
case InfraredWorkerStateWaitTxEnd: case InfraredWorkerStateWaitTxEnd:
furi_hal_infrared_async_tx_wait_termination(); furi_hal_infrared_async_tx_wait_termination();
@ -504,18 +506,18 @@ static int32_t infrared_worker_tx_thread(void* thread_context) {
events = furi_thread_flags_get(); events = furi_thread_flags_get();
if(events & INFRARED_WORKER_EXIT) { if(events & INFRARED_WORKER_EXIT) {
exit = true; running = false;
break; break;
} }
break; break;
case InfraredWorkerStateRunTx: case InfraredWorkerStateRunTx:
events = furi_thread_flags_wait(INFRARED_WORKER_ALL_TX_EVENTS, 0, FuriWaitForever); events = furi_thread_flags_wait(
INFRARED_WORKER_ALL_TX_EVENTS, FuriFlagWaitAny, FuriWaitForever);
furi_check(events & INFRARED_WORKER_ALL_TX_EVENTS); /* at least one caught */ furi_check(events & INFRARED_WORKER_ALL_TX_EVENTS); /* at least one caught */
if(events & INFRARED_WORKER_EXIT) { if(events & INFRARED_WORKER_EXIT) {
instance->state = InfraredWorkerStateStopTx; exit_pending = true;
break;
} }
if(events & INFRARED_WORKER_TX_FILL_BUFFER) { if(events & INFRARED_WORKER_TX_FILL_BUFFER) {
@ -527,9 +529,19 @@ static int32_t infrared_worker_tx_thread(void* thread_context) {
} }
if(events & INFRARED_WORKER_TX_MESSAGE_SENT) { if(events & INFRARED_WORKER_TX_MESSAGE_SENT) {
if(instance->tx.message_sent_callback) if(repeats_left > 0) {
--repeats_left;
}
if(instance->tx.message_sent_callback) {
instance->tx.message_sent_callback(instance->tx.message_sent_context); instance->tx.message_sent_callback(instance->tx.message_sent_context);
}
} }
if(exit_pending && repeats_left == 0) {
instance->state = InfraredWorkerStateStopTx;
}
break; break;
default: default:
furi_assert(0); furi_assert(0);

View file

@ -244,7 +244,7 @@ LevelDuration protocol_fdx_b_encoder_yield(ProtocolFDXB* protocol) {
static uint64_t protocol_fdx_b_get_national_code(const uint8_t* data) { static uint64_t protocol_fdx_b_get_national_code(const uint8_t* data) {
uint64_t national_code = bit_lib_get_bits_32(data, 0, 32); uint64_t national_code = bit_lib_get_bits_32(data, 0, 32);
national_code = national_code << 32; national_code = national_code << 32;
national_code |= bit_lib_get_bits_32(data, 32, 6) << (32 - 6); national_code |= (uint64_t)bit_lib_get_bits_32(data, 32, 6) << (32 - 6);
bit_lib_reverse_bits((uint8_t*)&national_code, 0, 64); bit_lib_reverse_bits((uint8_t*)&national_code, 0, 64);
return national_code; return national_code;
} }

View file

@ -5,8 +5,16 @@
#include <stddef.h> #include <stddef.h>
#define bit_read(value, bit) (((value) >> (bit)) & 0x01) #define bit_read(value, bit) (((value) >> (bit)) & 0x01)
#define bit_set(value, bit) ((value) |= (1UL << (bit))) #define bit_set(value, bit) \
#define bit_clear(value, bit) ((value) &= ~(1UL << (bit))) ({ \
__typeof__(value) _one = (1); \
(value) |= (_one << (bit)); \
})
#define bit_clear(value, bit) \
({ \
__typeof__(value) _one = (1); \
(value) &= ~(_one << (bit)); \
})
#define bit_write(value, bit, bitvalue) (bitvalue ? bit_set(value, bit) : bit_clear(value, bit)) #define bit_write(value, bit, bitvalue) (bitvalue ? bit_set(value, bit) : bit_clear(value, bit))
#define DURATION_DIFF(x, y) (((x) < (y)) ? ((y) - (x)) : ((x) - (y))) #define DURATION_DIFF(x, y) (((x) < (y)) ? ((y) - (x)) : ((x) - (y)))

View file

@ -1,326 +0,0 @@
#include "subghz_config_preset_custom.h"
#include <stdio.h>
#include <core/log.h>
#include <core/core_defines.h> // UNUSED()
#include <core/check.h> // furi_assert()
#include <math.h> // log2(), floor()
#include <flipper_format/flipper_format.h>
// https://www.ti.com/lit/ds/symlink/cc1101.pdf?ts=1671943815135
// page 35.
// 12 Data Rate Programming
//
#define DATARATE_FUNC_CHIP_FOSC 26000000.0 /* 26MHz */
#define DATARATE_FUNC_DIVIDER (1 << 28) /* 2 pow 28 */
#define DATARATE_FUNC_MULTIPLIER \
(DATARATE_FUNC_CHIP_FOSC / DATARATE_FUNC_DIVIDER) /* should be 0.09685754 */
#define DATARATE_EXP_FORMULA_DIVISIBLE (1 << 20) /* 2 pow 20 */
#define DATARATE_EXP_FORMULA_MULTIPLIER \
(DATARATE_EXP_FORMULA_DIVISIBLE / DATARATE_FUNC_CHIP_FOSC) /* should be 0.04032984 */
#define DATARATE_MNT_FORMULA_DIVISIBLE (1 << 28) /* 2 pow 28 */
#define DATARATE_MNT_FORMULA_MULTIPLIER \
(DATARATE_MNT_FORMULA_DIVISIBLE / DATARATE_FUNC_CHIP_FOSC) /* should be 10.3244406 */
//
#define SUGHZ_CONFIG_TAG "SubGHz_Config"
uint8_t furi_hal_subghz_preset_ook_custom_async_regs[PRESET_OOK_CUSTOM_ADVANCED_AM_SIZE] = {0};
/** Check if cursom preset is AM (OOK) modulation
*
* This will check MOD_FORMAT bits in CC1101_MDMCFG2 register
* If preset data doesn have this register - will return false.
* This function will not fail in any case
*
* @param preset_data Custom preset data (registers and patable)
* @param data_len Data length
*/
bool subghz_preset_custom_is_ook_modulation(const uint8_t* preset_data, uint8_t data_len) {
if(preset_data != NULL) {
for(uint8_t i = 2; i <= data_len; i += 2) {
if(preset_data[i - 2] == CC1101_MDMCFG2) {
return (preset_data[i - 1] & 0b01110000) == 0x30;
}
}
}
return false;
}
/** Get bandwidth value from preset data.
*
* This will get HIGHER bits in CC1101_MDMCFG4 register
* If CC1101_MDMCFG4 is not found in preset data - will return
* CH_BANDWIDTH_INVALID (0xFF)
* If there is ANY low 4 bits in returned value - the value is invalid
*
* @param preset_data Custom preset data (registers and patable)
* @param data_len Data length
*/
uint8_t subghz_preset_custom_get_bandwidth(const uint8_t* preset_data, uint8_t data_len) {
if(preset_data != NULL) {
for(uint8_t i = 2; i <= data_len; i += 2) {
if(preset_data[i - 2] == CC1101_MDMCFG4) {
return (preset_data[i - 1] & 0b11110000);
}
}
}
return CH_BANDWIDTH_INVALID;
}
/** Set bandwidth value to preset data.
*
* This will set HIGHER bits in CC1101_MDMCFG4 register
* If CC1101_MDMCFG4 is not found in preset data - will do nothing and return false
* If there are ANY low 4 bits in provided value - they will be ignored
*
* @param preset_data Custom preset data (registers and patable)
* @param data_len Data length
* @param value New bandwidth value. See macros definition for possible values
*/
bool subghz_preset_custom_set_bandwidth(uint8_t* preset_data, uint8_t data_len, uint8_t value) {
if(preset_data != NULL) {
for(uint8_t i = 2; i <= data_len; i += 2) {
if(preset_data[i - 2] == CC1101_MDMCFG4) {
preset_data[i - 1] = (preset_data[i - 1] & 0b00001111) | (0b11110000 & value);
return true;
}
}
}
return false;
}
/** Get data rate value from preset data.
*
* This will get DRATE_M and DRATE_E bits from CC1101_MDMCFG3 and CC1101_MDMCFG4 registers
* and calculate the value for 26MHz chip oscillator by formula from datasheet.
*
* If CC1101_MDMCFG[3:4] are not found in preset data - will return `-1`
*
* @param preset_data Custom preset data (registers and patable)
* @param data_len Data length
*/
float subghz_preset_custom_get_datarate(const uint8_t* preset_data, uint8_t data_len) {
if(preset_data != NULL) {
uint8_t mantissa = 0xFF;
uint8_t exponent = 0xFF; // Invalid, only 4 lower bits are singificant
uint8_t step = 0;
for(uint8_t i = 2; i <= data_len && step < 2; i += 2) {
if(preset_data[i - 2] == CC1101_MDMCFG4) {
exponent = preset_data[i - 1] & 0b00001111;
step++;
} else if(preset_data[i - 2] == CC1101_MDMCFG3) {
mantissa = preset_data[i - 1];
step++;
}
}
if(step == 2) {
return (float)((256 + mantissa) * (1 << exponent) * DATARATE_FUNC_MULTIPLIER);
}
}
return -1;
}
/** Set data rate value to preset data.
*
* This will update DRATE_M and DRATE_E bits from CC1101_MDMCFG3 and CC1101_MDMCFG4 registers
* with calculated values for 26MHz chip oscillator by formula from datasheet.
*
* If CC1101_MDMCFG[3:4] are not found in preset data - will return false
*
* @param preset_data Custom preset data (registers and patable)
* @param data_len Data length
* @param value value in kBaud
*/
bool subghz_preset_custom_set_datarate(uint8_t* preset_data, uint8_t data_len, float value) {
if(preset_data != NULL) {
uint8_t* pMantissa = NULL;
uint8_t* pExponent = NULL;
uint8_t step = 0;
for(uint8_t i = 2; i <= data_len && step < 2; i += 2) {
if(preset_data[i - 2] == CC1101_MDMCFG4) {
pExponent = &preset_data[i - 1];
step++;
} else if(preset_data[i - 2] == CC1101_MDMCFG3) {
pMantissa = &preset_data[i - 1];
step++;
}
}
// Has both registers in data - calculate values
if(step == 2) {
// │ value * 2^20 │
// DRATE_E = │log2(──────────────)│
// └ Fosc ┘
double exponent = floor(log2(value * DATARATE_EXP_FORMULA_MULTIPLIER));
uint8_t datarate_e = (uint8_t)exponent;
// value * 2^28
// DRATE_M = (────────────────────) - 256
// Fosc * 2^DRATE_E
double mantissa =
floor((value * DATARATE_MNT_FORMULA_MULTIPLIER) / (1 << datarate_e) + 0.5) - 256;
// If DRATE_M is rounded to the nearest integer and becomes 256, increment DRATE_E and use DRATE_M = 0.
if(mantissa >= 256) {
mantissa = 0;
datarate_e += 1;
}
uint8_t datarate_m = (uint8_t)mantissa;
*pExponent = (*pExponent & 0b11110000) | (datarate_e & 0b00001111);
*pMantissa = datarate_m;
return true;
}
}
return false;
}
/** Print datarate value to string
*
* This is just convenience function
*
* @param datarate datarate obtained from `subghz_preset_custom_get_datarate` function
* @param string Target print buffer
* @param size Target print buffer size
*/
void subghz_preset_custom_printf_datarate(float datarate, char* string, uint8_t size) {
float kBaudRate = datarate / 1000.0f;
snprintf(
string,
size,
"%lu.%02lu kBd",
(uint32_t)(kBaudRate), // decimal part
(uint32_t)((kBaudRate - (uint32_t)kBaudRate) * 100) // fractional part multiplied by 100
);
}
/** Get Manchester encoding/decoding flag value from preset data.
*
* This will get MANCHESTER_EN (3-rd) bit in CC1101_MDMCFG2 register
* If CC1101_MDMCFG2 is not found in preset data - will return false
*
* @param preset_data Custom preset data (registers and patable)
* @param data_len Data length
*/
bool subghz_preset_custom_get_machester_enable(const uint8_t* preset_data, uint8_t data_len) {
if(preset_data != NULL) {
for(uint8_t i = 2; i <= data_len; i += 2) {
if(preset_data[i - 2] == CC1101_MDMCFG2) {
return (preset_data[i - 1] & 0b00001000);
}
}
}
return false;
}
/** Set Manchester encoding/decoding flag value to preset data.
*
* This will set MANCHESTER_EN (3-rd) bit in CC1101_MDMCFG2 register
* If CC1101_MDMCFG2 is not found in preset data - will return false
*
* @param preset_data Custom preset data (registers and patable)
* @param data_len Data length
*/
bool subghz_preset_custom_set_machester_enable(uint8_t* preset_data, uint8_t data_len, bool value) {
if(preset_data != NULL) {
for(uint8_t i = 2; i <= data_len; i += 2) {
if(preset_data[i - 2] == CC1101_MDMCFG2) {
preset_data[i - 1] = (preset_data[i - 1] & 0b11110111) | (0b00001000 * value);
return true;
}
}
}
return false;
}
/**
* Initialize custom preset data
*/
void subghz_preset_custom_init_advanced_am_preset() {
FURI_LOG_D(SUGHZ_CONFIG_TAG, "Initializing AM preset with custom Modem configuration");
if(furi_hal_subghz_preset_ook_custom_async_regs[0]) {
// already initialized
FURI_LOG_D(SUGHZ_CONFIG_TAG, "Already initialized");
return;
}
// Copy default AM270 preset
memcpy(
&furi_hal_subghz_preset_ook_custom_async_regs,
&furi_hal_subghz_preset_ook_270khz_async_regs,
sizeof(furi_hal_subghz_preset_ook_270khz_async_regs));
const uint8_t ModemConfigStart = 4;
#if FURI_DEBUG
const uint8_t ModemConfigEnd = ModemConfigStart + MODEM_CONFIG_REGISTERS_COUNT;
for(uint8_t i = ModemConfigStart; i < ModemConfigEnd; ++i) {
// Check we'll overwrite correct settings
furi_assert(
furi_hal_subghz_preset_ook_custom_async_regs[i * 2 + 0] ==
furi_hal_subghz_custom_modulation_regs[i - ModemConfigStart][0]);
}
#endif
// Copy CUSTOM Modem preset
memcpy(
&furi_hal_subghz_preset_ook_custom_async_regs[ModemConfigStart * 2],
&furi_hal_subghz_custom_modulation_regs,
sizeof(furi_hal_subghz_custom_modulation_regs));
// Copy default AM270 patable
memcpy(
&furi_hal_subghz_preset_ook_custom_async_regs[sizeof(
furi_hal_subghz_preset_ook_270khz_async_regs)],
&furi_hal_subghz_preset_ook_async_patable,
sizeof(furi_hal_subghz_preset_ook_async_patable));
// Here at the end we should have
// <AM270 bytes> <CFGMDM regs> <AM270 bytes> 00 00 <AM270 patable>
#if FURI_DEBUG
FURI_LOG_D(SUGHZ_CONFIG_TAG, "Custom OOK preset created");
for(uint8_t i = 0; i < PRESET_OOK_CUSTOM_ADVANCED_AM_SIZE; i += 2) {
FURI_LOG_D(
SUGHZ_CONFIG_TAG,
"Register: 0x%hhX, Value: 0x%hhX",
furi_hal_subghz_preset_ook_custom_async_regs[i * 2 + 0],
furi_hal_subghz_preset_ook_custom_async_regs[i * 2 + 1]);
}
#endif
FURI_LOG_D(SUGHZ_CONFIG_TAG, "Done");
}
/**
* Create subghz preset file with custom am preset
* this is used for preset initialization if subghz app
*/
FlipperFormat* subghz_preset_custom_advanced_am_preset_alloc() {
FlipperFormat* advanced_am_preset = flipper_format_string_alloc();
subghz_preset_custom_init_advanced_am_preset();
flipper_format_write_hex(
advanced_am_preset,
(const char*)"Custom_preset_data",
(const uint8_t*)&furi_hal_subghz_preset_ook_custom_async_regs[0],
sizeof(furi_hal_subghz_preset_ook_custom_async_regs));
flipper_format_rewind(advanced_am_preset);
return advanced_am_preset;
}

View file

@ -1,193 +0,0 @@
#pragma once
#include <furi_hal_subghz_configs.h>
#include <string.h> /* memcpy() */
#define ADVANCED_AM_PRESET_NAME "AM*"
// Awailable bandwidth values
// Setup in MDMCFG4 register
#define CH_BANDWIDTH_058 0b11110000
#define CH_BANDWIDTH_068 0b11100000
#define CH_BANDWIDTH_081 0b11010000
#define CH_BANDWIDTH_102 0b11000000
#define CH_BANDWIDTH_116 0b10110000
#define CH_BANDWIDTH_135 0b10100000
#define CH_BANDWIDTH_162 0b10010000
#define CH_BANDWIDTH_203 0b10000000
#define CH_BANDWIDTH_232 0b01110000
#define CH_BANDWIDTH_270 0b01100000
#define CH_BANDWIDTH_325 0b01010000
#define CH_BANDWIDTH_406 0b01000000
#define CH_BANDWIDTH_464 0b00110000
#define CH_BANDWIDTH_541 0b00100000
#define CH_BANDWIDTH_650 0b00010000
#define CH_BANDWIDTH_812 0b00000000
#define CH_BANDWIDTH_INVALID 0xFF
static const uint8_t subghz_preset_custom_bandwidth_values[] = {
CH_BANDWIDTH_058,
CH_BANDWIDTH_068,
CH_BANDWIDTH_081,
CH_BANDWIDTH_102,
CH_BANDWIDTH_116,
CH_BANDWIDTH_135,
CH_BANDWIDTH_162,
CH_BANDWIDTH_203,
CH_BANDWIDTH_232,
CH_BANDWIDTH_270,
CH_BANDWIDTH_325,
CH_BANDWIDTH_406,
CH_BANDWIDTH_464,
CH_BANDWIDTH_541,
CH_BANDWIDTH_650,
CH_BANDWIDTH_812,
};
#define CH_BANDWIDTH_NUM (sizeof(subghz_preset_custom_bandwidth_values) / sizeof(uint8_t))
#define DATARATE_EXPONENT_3_79_kBaud 0b00000111 // 7
#define DATARATE_MANTISSA_3_79_kBaud 0x32
#define CHANNEL_SPACING_25_EXPONENT 0b00000000 /* last bit */
#define CHANNEL_SPACING_25_MANTISSA 0x00
#define MODEM_CONFIG_REGISTERS_COUNT 5
#define PRESET_OOK_CUSTOM_ADVANCED_AM_SIZE \
sizeof(furi_hal_subghz_preset_ook_270khz_async_regs) + \
sizeof(furi_hal_subghz_preset_ook_async_patable)
extern uint8_t furi_hal_subghz_preset_ook_custom_async_regs[PRESET_OOK_CUSTOM_ADVANCED_AM_SIZE];
static const uint8_t furi_hal_subghz_custom_modulation_regs[MODEM_CONFIG_REGISTERS_COUNT][2] = {
// Channel spacing is 25kHz, no Forward Error Correction, 2 preamble bytes (will be ignored)
{CC1101_MDMCFG0, CHANNEL_SPACING_25_MANTISSA},
{CC1101_MDMCFG1, 0x00 | CHANNEL_SPACING_25_EXPONENT},
// [0:2] SYNC_MODE = 00 // No preamble/sync
// [3:3] MANCHESTER_EN = 0 // Disable
// [4:6] MOD_FORMAT = 03 // Format ASK/OOK
// [7:7] DEM_DCFILT_OFF = 0 // Enable
{CC1101_MDMCFG2, 0x30},
// 3.79 kBaud data rate (mantissa in 3rd register)
{CC1101_MDMCFG3, DATARATE_MANTISSA_3_79_kBaud},
// 270.8333 kHz Rx BW filer (hi) and 3.79 kBaud data rate (exponent in 4th register)
{CC1101_MDMCFG4, DATARATE_EXPONENT_3_79_kBaud | CH_BANDWIDTH_270},
};
#ifdef __cplusplus
extern "C" {
#endif
/** Check if cursom preset is AM (OOK) modulation
*
* This will check MOD_FORMAT bits in CC1101_MDMCFG2 register
* If preset data doesn have this register - will return false.
* This function will not fail in any case
*
* @param preset_data Custom preset data (registers and patable)
* @param data_len Data length
*/
bool subghz_preset_custom_is_ook_modulation(const uint8_t* preset_data, uint8_t data_len);
/** Get bandwidth value from preset data.
*
* This will get HIGHER bits in CC1101_MDMCFG4 register
* If CC1101_MDMCFG4 is not found in preset data - will return
* CH_BANDWIDTH_INVALID (0xFF)
* If there is ANY low 4 bits in returned value - the value is invalid
*
* @param preset_data Custom preset data (registers and patable)
* @param data_len Data length
*/
uint8_t subghz_preset_custom_get_bandwidth(const uint8_t* preset_data, uint8_t data_len);
/** Set bandwidth value to preset data.
*
* This will set HIGHER bits in CC1101_MDMCFG4 register
* If CC1101_MDMCFG4 is not found in preset data - will do nothing and return false
* If there are ANY low 4 bits in provided value - they will be ignored
*
* @param preset_data Custom preset data (registers and patable)
* @param data_len Data length
* @param value New bandwidth value. See macros definition for possible values
*/
bool subghz_preset_custom_set_bandwidth(uint8_t* preset_data, uint8_t data_len, uint8_t value);
/** Get data rate value from preset data.
*
* This will get DRATE_M and DRATE_E bits from CC1101_MDMCFG3 and CC1101_MDMCFG4 registers
* and calculate the value for 26MHz chip oscillator by formula from datasheet.
*
* If CC1101_MDMCFG[3:4] are not found in preset data - will return `-1`
*
* @param preset_data Custom preset data (registers and patable)
* @param data_len Data length
*/
float subghz_preset_custom_get_datarate(const uint8_t* preset_data, uint8_t data_len);
/** Set data rate value to preset data.
*
* This will update DRATE_M and DRATE_E bits from CC1101_MDMCFG3 and CC1101_MDMCFG4 registers
* with calculated values for 26MHz chip oscillator by formula from datasheet.
*
* If CC1101_MDMCFG[3:4] are not found in preset data - will return false
*
* @param preset_data Custom preset data (registers and patable)
* @param data_len Data length
* @param value value in kBaud
*/
bool subghz_preset_custom_set_datarate(uint8_t* preset_data, uint8_t data_len, float value);
/** Print datarate value to string
*
* This is just conviniece function
*
* @param datarate datarate obtained from `subghz_preset_custom_get_datarate` function
* @param string Target print buffer
* @param size Target print buffer size
*/
void subghz_preset_custom_printf_datarate(float datarate, char* string, uint8_t size);
/** Get Manchester encoding/decoding flag value from preset data.
*
* This will get MANCHESTER_EN (3-rd) bit in CC1101_MDMCFG2 register
* If CC1101_MDMCFG2 is not found in preset data - will return false
*
* @param preset_data Custom preset data (registers and patable)
* @param data_len Data length
*/
bool subghz_preset_custom_get_machester_enable(const uint8_t* preset_data, uint8_t data_len);
/** Set Manchester encoding/decoding flag value to preset data.
*
* This will set MANCHESTER_EN (3-rd) bit in CC1101_MDMCFG2 register
* If CC1101_MDMCFG2 is not found in preset data - will return false
*
* @param preset_data Custom preset data (registers and patable)
* @param data_len Data length
*/
bool subghz_preset_custom_set_machester_enable(uint8_t* preset_data, uint8_t data_len, bool value);
/**
* Initialize advanced am custom preset
*/
void subghz_preset_custom_init_advanced_am_preset();
/**
* Create subghz preset file with custom am preset
* this is used for preset initialization if subghz app
*/
struct FlipperFormat* subghz_preset_custom_advanced_am_preset_alloc();
#ifdef __cplusplus
}
#endif

View file

@ -280,9 +280,9 @@ static bool subghz_protocol_chamb_code_to_bit(uint64_t* data, uint8_t size) {
uint64_t data_tmp = data[0]; uint64_t data_tmp = data[0];
uint64_t data_res = 0; uint64_t data_res = 0;
for(uint8_t i = 0; i < size; i++) { for(uint8_t i = 0; i < size; i++) {
if((data_tmp & 0xF) == CHAMBERLAIN_CODE_BIT_0) { if((data_tmp & 0xFll) == CHAMBERLAIN_CODE_BIT_0) {
bit_write(data_res, i, 0); bit_write(data_res, i, 0);
} else if((data_tmp & 0xF) == CHAMBERLAIN_CODE_BIT_1) { } else if((data_tmp & 0xFll) == CHAMBERLAIN_CODE_BIT_1) {
bit_write(data_res, i, 1); bit_write(data_res, i, 1);
} else { } else {
return false; return false;

View file

@ -224,7 +224,7 @@ static bool subghz_protocol_secplus_v1_encode(SubGhzProtocolEncoderSecPlus_v1* i
instance->generic.data &= 0xFFFFFFFF00000000; instance->generic.data &= 0xFFFFFFFF00000000;
instance->generic.data |= rolling; instance->generic.data |= rolling;
if(rolling > 0xFFFFFFFF) { if(rolling == 0xFFFFFFFF) {
rolling = 0xE6000000; rolling = 0xE6000000;
} }
if(fixed > 0xCFD41B90) { if(fixed > 0xCFD41B90) {

View file

@ -7,7 +7,7 @@ from SCons.Node import NodeList
import SCons.Warnings import SCons.Warnings
from fbt.elfmanifest import assemble_manifest_data from fbt.elfmanifest import assemble_manifest_data
from fbt.appmanifest import FlipperApplication, FlipperManifestException from fbt.appmanifest import FlipperApplication, FlipperManifestException, FlipperAppType
from fbt.sdk.cache import SdkCache from fbt.sdk.cache import SdkCache
from fbt.util import extract_abs_dir_path from fbt.util import extract_abs_dir_path
@ -32,6 +32,7 @@ def BuildAppElf(env, app):
ext_apps_work_dir = env.subst("$EXT_APPS_WORK_DIR") ext_apps_work_dir = env.subst("$EXT_APPS_WORK_DIR")
app_work_dir = os.path.join(ext_apps_work_dir, app.appid) app_work_dir = os.path.join(ext_apps_work_dir, app.appid)
env.SetDefault(_APP_ICONS=[])
env.VariantDir(app_work_dir, app._appdir, duplicate=False) env.VariantDir(app_work_dir, app._appdir, duplicate=False)
app_env = env.Clone(FAP_SRC_DIR=app._appdir, FAP_WORK_DIR=app_work_dir) app_env = env.Clone(FAP_SRC_DIR=app._appdir, FAP_WORK_DIR=app_work_dir)
@ -63,6 +64,7 @@ def BuildAppElf(env, app):
icon_bundle_name=f"{app.fap_icon_assets_symbol if app.fap_icon_assets_symbol else app.appid }_icons", icon_bundle_name=f"{app.fap_icon_assets_symbol if app.fap_icon_assets_symbol else app.appid }_icons",
) )
app_env.Alias("_fap_icons", fap_icons) app_env.Alias("_fap_icons", fap_icons)
env.Append(_APP_ICONS=[fap_icons])
private_libs = [] private_libs = []
@ -232,11 +234,18 @@ def GetExtAppFromPath(env, app_dir):
return app_artifacts return app_artifacts
def fap_dist_emitter(target, source, env): def resources_fap_dist_emitter(target, source, env):
target_dir = target[0] target_dir = target[0]
target = [] target = []
for _, app_artifacts in env["EXT_APPS"].items(): for _, app_artifacts in env["EXT_APPS"].items():
# We don't deploy example apps & debug tools with SD card resources
if (
app_artifacts.app.apptype == FlipperAppType.DEBUG
or app_artifacts.app.fap_category == "Examples"
):
continue
source.extend(app_artifacts.compact) source.extend(app_artifacts.compact)
target.append( target.append(
target_dir.Dir(app_artifacts.app.fap_category).File( target_dir.Dir(app_artifacts.app.fap_category).File(
@ -247,7 +256,7 @@ def fap_dist_emitter(target, source, env):
return (target, source) return (target, source)
def fap_dist_action(target, source, env): def resources_fap_dist_action(target, source, env):
# FIXME # FIXME
target_dir = env.Dir("#/assets/resources/apps") target_dir = env.Dir("#/assets/resources/apps")
@ -280,10 +289,10 @@ def generate(env, **kw):
BUILDERS={ BUILDERS={
"FapDist": Builder( "FapDist": Builder(
action=Action( action=Action(
fap_dist_action, resources_fap_dist_action,
"$FAPDISTCOMSTR", "$FAPDISTCOMSTR",
), ),
emitter=fap_dist_emitter, emitter=resources_fap_dist_emitter,
), ),
"EmbedAppMetadata": Builder( "EmbedAppMetadata": Builder(
action=[ action=[

View file

@ -11,6 +11,8 @@ Building:
Build all FAP apps Build all FAP apps
fap_{APPID}, launch_app APPSRC={APPID}: fap_{APPID}, launch_app APPSRC={APPID}:
Build FAP app with appid={APPID}; upload & start it over USB Build FAP app with appid={APPID}; upload & start it over USB
fap_deploy:
Build and upload all FAP apps over USB
Flashing & debugging: Flashing & debugging:
flash, flash_blackmagic, jflash: flash, flash_blackmagic, jflash:
@ -29,6 +31,8 @@ Other:
run linters run linters
format, format_py: format, format_py:
run code formatters run code formatters
firmware_pvs:
generate a PVS-Studio report
For more targets & info, see documentation/fbt.md For more targets & info, see documentation/fbt.md
""" """

View file

@ -0,0 +1,106 @@
from SCons.Builder import Builder
from SCons.Action import Action
from SCons.Script import Delete, Mkdir, GetBuildFailures
import multiprocessing
import webbrowser
import atexit
import sys
import subprocess
__no_browser = False
def _set_browser_action(target, source, env):
if env["PVSNOBROWSER"]:
global __no_browser
__no_browser = True
def emit_pvsreport(target, source, env):
target_dir = env["REPORT_DIR"]
if env["PLATFORM"] == "win32":
# Report generator on Windows emits to a subfolder of given output folder
target_dir = target_dir.Dir("fullhtml")
return [target_dir.File("index.html")], source
def atexist_handler():
global __no_browser
if __no_browser:
return
for bf in GetBuildFailures():
if bf.node.exists and bf.node.name.endswith(".html"):
# macOS
if sys.platform == "darwin":
subprocess.run(["open", bf.node.abspath])
else:
webbrowser.open(bf.node.abspath)
break
def generate(env):
env.SetDefault(
PVSNCORES=multiprocessing.cpu_count(),
PVSOPTIONS=[
"@.pvsoptions",
"-j${PVSNCORES}",
# "--incremental", # kinda broken on PVS side
],
PVSCONVOPTIONS=[
"-a",
"GA:1,2,3",
"-t",
"fullhtml",
"--indicate-warnings",
],
)
if env["PLATFORM"] == "win32":
env.SetDefault(
PVSCHECKBIN="CompilerCommandsAnalyzer.exe",
PVSCONVBIN="PlogConverter.exe",
)
else:
env.SetDefault(
PVSCHECKBIN="pvs-studio-analyzer",
PVSCONVBIN="plog-converter",
)
if not env["VERBOSE"]:
env.SetDefault(
PVSCHECKCOMSTR="\tPVS\t${TARGET}",
PVSCONVCOMSTR="\tPVSREP\t${TARGET}",
)
env.Append(
BUILDERS={
"PVSCheck": Builder(
action=Action(
'${PVSCHECKBIN} analyze ${PVSOPTIONS} -f "${SOURCE}" -o "${TARGET}"',
"${PVSCHECKCOMSTR}",
),
suffix=".log",
src_suffix=".json",
),
"PVSReport": Builder(
action=Action(
[
Delete("${TARGET.dir}"),
# PlogConverter.exe and plog-converter have different behavior
Mkdir("${TARGET.dir}") if env["PLATFORM"] == "win32" else None,
Action(_set_browser_action, None),
'${PVSCONVBIN} ${PVSCONVOPTIONS} "${SOURCE}" -o "${REPORT_DIR}"',
],
"${PVSCONVCOMSTR}",
),
emitter=emit_pvsreport,
src_suffix=".log",
),
}
)
atexit.register(atexist_handler)
def exists(env):
return True

View file

@ -15,6 +15,13 @@ import serial.tools.list_ports as list_ports
class Main(App): class Main(App):
def init(self): def init(self):
self.parser.add_argument("-p", "--port", help="CDC Port", default="auto") self.parser.add_argument("-p", "--port", help="CDC Port", default="auto")
self.parser.add_argument(
"-n",
"--no-launch",
dest="launch_app",
action="store_false",
help="Don't launch app",
)
self.parser.add_argument("fap_src_path", help="App file to upload") self.parser.add_argument("fap_src_path", help="App file to upload")
self.parser.add_argument( self.parser.add_argument(
@ -84,11 +91,14 @@ class Main(App):
self.logger.error(f"Error: upload failed: {storage.last_error}") self.logger.error(f"Error: upload failed: {storage.last_error}")
return -3 return -3
storage.send_and_wait_eol(f'loader open "Applications" {fap_dst_path}\r') if self.args.launch_app:
result = storage.read.until(storage.CLI_EOL) storage.send_and_wait_eol(
if len(result): f'loader open "Applications" {fap_dst_path}\r'
self.logger.error(f"Unexpected response: {result.decode('ascii')}") )
return -4 result = storage.read.until(storage.CLI_EOL)
if len(result):
self.logger.error(f"Unexpected response: {result.decode('ascii')}")
return -4
return 0 return 0
finally: finally:

View file

@ -43,9 +43,11 @@ fbtenv_restore_env()
PYTHONNOUSERSITE="$SAVED_PYTHONNOUSERSITE"; PYTHONNOUSERSITE="$SAVED_PYTHONNOUSERSITE";
PYTHONPATH="$SAVED_PYTHONPATH"; PYTHONPATH="$SAVED_PYTHONPATH";
PYTHONHOME="$SAVED_PYTHONHOME";
unset SAVED_PYTHONNOUSERSITE; unset SAVED_PYTHONNOUSERSITE;
unset SAVED_PYTHONPATH; unset SAVED_PYTHONPATH;
unset SAVED_PYTHONHOME;
unset SCRIPT_PATH; unset SCRIPT_PATH;
unset FBT_TOOLCHAIN_VERSION; unset FBT_TOOLCHAIN_VERSION;
@ -69,7 +71,7 @@ fbtenv_check_sourced()
return 1; return 1;
} }
fbtenv_chck_many_source() fbtenv_check_if_sourced_multiple_times()
{ {
if ! echo "${PS1:-""}" | grep -qF "[fbt]"; then if ! echo "${PS1:-""}" | grep -qF "[fbt]"; then
if ! echo "${PROMPT:-""}" | grep -qF "[fbt]"; then if ! echo "${PROMPT:-""}" | grep -qF "[fbt]"; then
@ -285,7 +287,7 @@ fbtenv_main()
fbtenv_restore_env; fbtenv_restore_env;
return 0; return 0;
fi fi
fbtenv_chck_many_source; # many source it's just a warning fbtenv_check_if_sourced_multiple_times; # many source it's just a warning
fbtenv_check_script_path || return 1; fbtenv_check_script_path || return 1;
fbtenv_check_download_toolchain || return 1; fbtenv_check_download_toolchain || return 1;
fbtenv_set_shell_prompt; fbtenv_set_shell_prompt;
@ -293,12 +295,14 @@ fbtenv_main()
PATH="$TOOLCHAIN_ARCH_DIR/bin:$PATH"; PATH="$TOOLCHAIN_ARCH_DIR/bin:$PATH";
PATH="$TOOLCHAIN_ARCH_DIR/protobuf/bin:$PATH"; PATH="$TOOLCHAIN_ARCH_DIR/protobuf/bin:$PATH";
PATH="$TOOLCHAIN_ARCH_DIR/openocd/bin:$PATH"; PATH="$TOOLCHAIN_ARCH_DIR/openocd/bin:$PATH";
SAVED_PYTHONNOUSERSITE="${PYTHONNOUSERSITE:-""}"; SAVED_PYTHONNOUSERSITE="${PYTHONNOUSERSITE:-""}";
SAVED_PYTHONPATH="${PYTHONPATH:-""}"; SAVED_PYTHONPATH="${PYTHONPATH:-""}";
SAVED_PYTHONHOME="${PYTHONHOME:-""}";
PYTHONNOUSERSITE=1; PYTHONNOUSERSITE=1;
PYTHONPATH=; PYTHONPATH=;
PYTHONHOME=;
} }
fbtenv_main "${1:-""}"; fbtenv_main "${1:-""}";

View file

@ -81,16 +81,6 @@ vars.AddVariables(
"7", "7",
], ],
), ),
BoolVariable(
"DEBUG_TOOLS",
help="Enable debug tools to be built",
default=False,
),
BoolVariable(
"FAP_EXAMPLES",
help="Enable example applications to be built",
default=False,
),
( (
"DIST_SUFFIX", "DIST_SUFFIX",
"Suffix for binaries in build output for dist targets", "Suffix for binaries in build output for dist targets",
@ -242,9 +232,15 @@ vars.AddVariables(
("applications/system", False), ("applications/system", False),
("applications/debug", False), ("applications/debug", False),
("applications/plugins", False), ("applications/plugins", False),
("applications/examples", False),
("applications_user", False), ("applications_user", False),
], ],
), ),
BoolVariable(
"PVSNOBROWSER",
help="Don't open browser after generating error repots",
default=False,
),
) )
Return("vars") Return("vars")

View file

@ -65,9 +65,8 @@ class FlipperExtAppBuildArtifacts:
apps_to_build_as_faps = [ apps_to_build_as_faps = [
FlipperAppType.PLUGIN, FlipperAppType.PLUGIN,
FlipperAppType.EXTERNAL, FlipperAppType.EXTERNAL,
FlipperAppType.DEBUG,
] ]
if appenv["DEBUG_TOOLS"]:
apps_to_build_as_faps.append(FlipperAppType.DEBUG)
known_extapps = [ known_extapps = [
app app
@ -143,6 +142,11 @@ sdk_apisyms = appenv.SDKSymGenerator(
"${BUILD_DIR}/assets/compiled/symbols.h", appenv["SDK_DEFINITION"] "${BUILD_DIR}/assets/compiled/symbols.h", appenv["SDK_DEFINITION"]
) )
Alias("api_syms", sdk_apisyms) Alias("api_syms", sdk_apisyms)
ENV.Replace(
SDK_APISYMS=sdk_apisyms,
_APP_ICONS=appenv["_APP_ICONS"],
)
if appenv["FORCE"]: if appenv["FORCE"]:
appenv.AlwaysBuild(sdk_source, sdk_tree, sdk_apicheck, sdk_apisyms) appenv.AlwaysBuild(sdk_source, sdk_tree, sdk_apicheck, sdk_apisyms)