diff --git a/applications/debug/unit_tests/application.fam b/applications/debug/unit_tests/application.fam index 252eb57c54..3190db3f04 100644 --- a/applications/debug/unit_tests/application.fam +++ b/applications/debug/unit_tests/application.fam @@ -131,6 +131,7 @@ App( apptype=FlipperAppType.PLUGIN, entry_point="get_api", requires=["unit_tests"], + fap_libs=["infrared"], ) App( diff --git a/applications/debug/unit_tests/tests/infrared/infrared_test.c b/applications/debug/unit_tests/tests/infrared/infrared_test.c index e64b630b2e..9ca78c2f43 100644 --- a/applications/debug/unit_tests/tests/infrared/infrared_test.c +++ b/applications/debug/unit_tests/tests/infrared/infrared_test.c @@ -2,6 +2,7 @@ #include #include #include +#include #include "../test.h" // IWYU pragma: keep #define IR_TEST_FILES_DIR EXT_PATH("unit_tests/infrared/") @@ -13,6 +14,7 @@ typedef struct { InfraredEncoderHandler* encoder_handler; FuriString* file_path; FlipperFormat* ff; + InfraredBruteForce* brutedb; } InfraredTest; static InfraredTest* test; @@ -24,12 +26,14 @@ static void infrared_test_alloc(void) { test->encoder_handler = infrared_alloc_encoder(); test->ff = flipper_format_buffered_file_alloc(storage); test->file_path = furi_string_alloc(); + test->brutedb = infrared_brute_force_alloc(); } static void infrared_test_free(void) { furi_check(test); infrared_free_decoder(test->decoder_handler); infrared_free_encoder(test->encoder_handler); + infrared_brute_force_free(test->brutedb); flipper_format_free(test->ff); furi_string_free(test->file_path); furi_record_close(RECORD_STORAGE); @@ -523,6 +527,74 @@ MU_TEST(infrared_test_encoder_decoder_all) { infrared_test_run_encoder_decoder(InfraredProtocolPioneer, 1); } +MU_TEST(infrared_test_ac_database) { + infrared_brute_force_set_db_filename(test->brutedb, EXT_PATH("infrared/assets/ac.ir")); + uint32_t i = 0; + infrared_brute_force_add_record(test->brutedb, i++, "Off"); + infrared_brute_force_add_record(test->brutedb, i++, "Dh"); + infrared_brute_force_add_record(test->brutedb, i++, "Cool_hi"); + infrared_brute_force_add_record(test->brutedb, i++, "Heat_hi"); + infrared_brute_force_add_record(test->brutedb, i++, "Cool_lo"); + infrared_brute_force_add_record(test->brutedb, i++, "Heat_lo"); + + mu_assert( + infrared_brute_force_calculate_messages(test->brutedb) == InfraredErrorCodeNone, + "universal ac database is invalid"); + + infrared_brute_force_reset(test->brutedb); +} + +MU_TEST(infrared_test_audio_database) { + infrared_brute_force_set_db_filename(test->brutedb, EXT_PATH("infrared/assets/audio.ir")); + uint32_t i = 0; + infrared_brute_force_add_record(test->brutedb, i++, "Power"); + infrared_brute_force_add_record(test->brutedb, i++, "Mute"); + infrared_brute_force_add_record(test->brutedb, i++, "Play"); + infrared_brute_force_add_record(test->brutedb, i++, "Pause"); + infrared_brute_force_add_record(test->brutedb, i++, "Prev"); + infrared_brute_force_add_record(test->brutedb, i++, "Next"); + infrared_brute_force_add_record(test->brutedb, i++, "Vol_dn"); + infrared_brute_force_add_record(test->brutedb, i++, "Vol_up"); + + mu_assert( + infrared_brute_force_calculate_messages(test->brutedb) == InfraredErrorCodeNone, + "universal audio database is invalid"); + + infrared_brute_force_reset(test->brutedb); +} + +MU_TEST(infrared_test_projector_database) { + infrared_brute_force_set_db_filename(test->brutedb, EXT_PATH("infrared/assets/projector.ir")); + uint32_t i = 0; + infrared_brute_force_add_record(test->brutedb, i++, "Power"); + infrared_brute_force_add_record(test->brutedb, i++, "Mute"); + infrared_brute_force_add_record(test->brutedb, i++, "Vol_up"); + infrared_brute_force_add_record(test->brutedb, i++, "Vol_dn"); + + mu_assert( + infrared_brute_force_calculate_messages(test->brutedb) == InfraredErrorCodeNone, + "universal projector database is invalid"); + + infrared_brute_force_reset(test->brutedb); +} + +MU_TEST(infrared_test_tv_database) { + infrared_brute_force_set_db_filename(test->brutedb, EXT_PATH("infrared/assets/tv.ir")); + uint32_t i = 0; + infrared_brute_force_add_record(test->brutedb, i++, "Power"); + infrared_brute_force_add_record(test->brutedb, i++, "Mute"); + infrared_brute_force_add_record(test->brutedb, i++, "Vol_up"); + infrared_brute_force_add_record(test->brutedb, i++, "Ch_next"); + infrared_brute_force_add_record(test->brutedb, i++, "Vol_dn"); + infrared_brute_force_add_record(test->brutedb, i++, "Ch_prev"); + + mu_assert( + infrared_brute_force_calculate_messages(test->brutedb) == InfraredErrorCodeNone, + "universal tv database is invalid"); + + infrared_brute_force_reset(test->brutedb); +} + MU_TEST_SUITE(infrared_test) { MU_SUITE_CONFIGURE(&infrared_test_alloc, &infrared_test_free); @@ -543,6 +615,10 @@ MU_TEST_SUITE(infrared_test) { MU_RUN_TEST(infrared_test_decoder_pioneer); MU_RUN_TEST(infrared_test_decoder_mixed); MU_RUN_TEST(infrared_test_encoder_decoder_all); + MU_RUN_TEST(infrared_test_ac_database); + MU_RUN_TEST(infrared_test_audio_database); + MU_RUN_TEST(infrared_test_projector_database); + MU_RUN_TEST(infrared_test_tv_database); } int run_minunit_test_infrared(void) { diff --git a/applications/main/infrared/application.fam b/applications/main/infrared/application.fam index 79b3fdbfad..3ed928ad80 100644 --- a/applications/main/infrared/application.fam +++ b/applications/main/infrared/application.fam @@ -9,7 +9,7 @@ App( order=40, sources=["*.c", "!infrared_cli.c"], resources="resources", - fap_libs=["assets"], + fap_libs=["assets", "infrared"], fap_icon="icon.png", fap_category="Infrared", ) @@ -20,9 +20,5 @@ App( apptype=FlipperAppType.PLUGIN, entry_point="cli_ir_ep", requires=["cli"], - sources=[ - "infrared_cli.c", - "infrared_brute_force.c", - "infrared_signal.c", - ], + sources=["infrared_cli.c"], ) diff --git a/applications/main/infrared/infrared_app.h b/applications/main/infrared/infrared_app.h index a6f87402a9..ef41f8f799 100644 --- a/applications/main/infrared/infrared_app.h +++ b/applications/main/infrared/infrared_app.h @@ -3,9 +3,7 @@ * @brief Infrared application - start here. * * @see infrared_app_i.h for the main application data structure and functions. - * @see infrared_signal.h for the infrared signal library - loading, storing and transmitting signals. - * @see infrared_remote.hl for the infrared remote library - loading, storing and manipulating remotes. - * @see infrared_brute_force.h for the infrared brute force - loading and transmitting multiple signals. + * @see infrared_remote.h for the infrared remote library - loading, storing and manipulating remotes */ #pragma once diff --git a/applications/main/infrared/infrared_app_i.h b/applications/main/infrared/infrared_app_i.h index 75d8502f26..caed2d6019 100644 --- a/applications/main/infrared/infrared_app_i.h +++ b/applications/main/infrared/infrared_app_i.h @@ -31,7 +31,7 @@ #include "infrared_app.h" #include "infrared_remote.h" -#include "infrared_brute_force.h" +#include #include "infrared_custom_event.h" #include "scenes/infrared_scene.h" diff --git a/applications/main/infrared/infrared_cli.c b/applications/main/infrared/infrared_cli.c index eb13bcd796..b953daad66 100644 --- a/applications/main/infrared/infrared_cli.c +++ b/applications/main/infrared/infrared_cli.c @@ -8,8 +8,8 @@ #include #include -#include "infrared_signal.h" -#include "infrared_brute_force.h" +#include +#include #define INFRARED_CLI_BUF_SIZE (10U) #define INFRARED_CLI_FILE_NAME_SIZE (256U) diff --git a/applications/main/infrared/infrared_remote.h b/applications/main/infrared/infrared_remote.h index 14416cd659..65f00100fd 100644 --- a/applications/main/infrared/infrared_remote.h +++ b/applications/main/infrared/infrared_remote.h @@ -11,7 +11,7 @@ */ #pragma once -#include "infrared_signal.h" +#include /** * @brief InfraredRemote opaque type declaration. diff --git a/fbt_options.py b/fbt_options.py index 191c4ef1ac..a801c1c480 100644 --- a/fbt_options.py +++ b/fbt_options.py @@ -76,6 +76,7 @@ FIRMWARE_APPS = { "radio_device_cc1101_ext", "unit_tests", "js_app", + "infrared", "archive", ], } diff --git a/lib/infrared/SConscript b/lib/infrared/SConscript index a32248a645..aa4b52776a 100644 --- a/lib/infrared/SConscript +++ b/lib/infrared/SConscript @@ -4,11 +4,15 @@ env.Append( CPPPATH=[ "#/lib/infrared/encoder_decoder", "#/lib/infrared/worker", + "#/lib/infrared/signal", ], SDK_HEADERS=[ File("encoder_decoder/infrared.h"), File("worker/infrared_worker.h"), File("worker/infrared_transmit.h"), + File("signal/infrared_error_code.h"), + File("signal/infrared_signal.h"), + File("signal/infrared_brute_force.h"), ], LINT_SOURCES=[ Dir("."), diff --git a/applications/main/infrared/infrared_brute_force.c b/lib/infrared/signal/infrared_brute_force.c similarity index 100% rename from applications/main/infrared/infrared_brute_force.c rename to lib/infrared/signal/infrared_brute_force.c diff --git a/applications/main/infrared/infrared_brute_force.h b/lib/infrared/signal/infrared_brute_force.h similarity index 98% rename from applications/main/infrared/infrared_brute_force.h rename to lib/infrared/signal/infrared_brute_force.h index 2c75d37f2d..f6e31af982 100644 --- a/applications/main/infrared/infrared_brute_force.h +++ b/lib/infrared/signal/infrared_brute_force.h @@ -12,6 +12,10 @@ #include #include "infrared_error_code.h" +#ifdef __cplusplus +extern "C" { +#endif + /** * @brief InfraredBruteForce opaque type declaration. */ @@ -107,3 +111,7 @@ void infrared_brute_force_add_record( * @param[in,out] brute_force pointer to the instance to be reset. */ void infrared_brute_force_reset(InfraredBruteForce* brute_force); + +#ifdef __cplusplus +} +#endif diff --git a/applications/main/infrared/infrared_error_code.h b/lib/infrared/signal/infrared_error_code.h similarity index 96% rename from applications/main/infrared/infrared_error_code.h rename to lib/infrared/signal/infrared_error_code.h index 841721b176..7aa619c4a0 100644 --- a/applications/main/infrared/infrared_error_code.h +++ b/lib/infrared/signal/infrared_error_code.h @@ -1,5 +1,9 @@ #pragma once +#ifdef __cplusplus +extern "C" { +#endif + typedef enum { InfraredErrorCodeNone = 0, InfraredErrorCodeFileOperationFailed = 0x800000, @@ -43,3 +47,7 @@ typedef enum { #define INFRARED_ERROR_PRESENT(error) (INFRARED_ERROR_GET_CODE(error) != InfraredErrorCodeNone) #define INFRARED_ERROR_CHECK(error, test_code) (INFRARED_ERROR_GET_CODE(error) == (test_code)) + +#ifdef __cplusplus +} +#endif diff --git a/applications/main/infrared/infrared_signal.c b/lib/infrared/signal/infrared_signal.c similarity index 99% rename from applications/main/infrared/infrared_signal.c rename to lib/infrared/signal/infrared_signal.c index 75643f1d3b..436de4e29c 100644 --- a/applications/main/infrared/infrared_signal.c +++ b/lib/infrared/signal/infrared_signal.c @@ -85,7 +85,7 @@ static bool infrared_signal_is_raw_valid(const InfraredRawSignal* raw) { raw->frequency); return false; - } else if((raw->duty_cycle <= 0) || (raw->duty_cycle > 1)) { + } else if((raw->duty_cycle <= 0) || (raw->duty_cycle > 1.f)) { FURI_LOG_E(TAG, "Duty cycle is out of range (0 - 1): %f", (double)raw->duty_cycle); return false; diff --git a/applications/main/infrared/infrared_signal.h b/lib/infrared/signal/infrared_signal.h similarity index 98% rename from applications/main/infrared/infrared_signal.h rename to lib/infrared/signal/infrared_signal.h index 3fa7768b30..96afd8c2e0 100644 --- a/applications/main/infrared/infrared_signal.h +++ b/lib/infrared/signal/infrared_signal.h @@ -10,7 +10,11 @@ #include "infrared_error_code.h" #include -#include +#include + +#ifdef __cplusplus +extern "C" { +#endif /** * @brief InfraredSignal opaque type declaration. @@ -218,3 +222,7 @@ InfraredErrorCode * @param[in] signal pointer to the instance holding the signal to be transmitted. */ void infrared_signal_transmit(const InfraredSignal* signal); + +#ifdef __cplusplus +} +#endif diff --git a/targets/f18/api_symbols.csv b/targets/f18/api_symbols.csv index 27b65e2022..f66fcb9e48 100644 --- a/targets/f18/api_symbols.csv +++ b/targets/f18/api_symbols.csv @@ -1,5 +1,5 @@ entry,status,name,type,params -Version,+,87.0,, +Version,+,87.1,, Header,+,applications/services/bt/bt_service/bt.h,, Header,+,applications/services/bt/bt_service/bt_keys_storage.h,, Header,+,applications/services/cli/cli.h,, @@ -339,6 +339,7 @@ Function,-,Osal_MemSet,void*,"void*, int, unsigned int" Function,-,SystemCoreClockUpdate,void, Function,-,SystemInit,void, Function,-,_Exit,void,int +Function,+,__aeabi_f2d,double,float Function,+,__aeabi_uldivmod,void*,"uint64_t, uint64_t" Function,-,__assert,void,"const char*, int, const char*" Function,+,__assert_func,void,"const char*, int, const char*, const char*" diff --git a/targets/f7/api_symbols.csv b/targets/f7/api_symbols.csv index 15a3d360b1..9963b35158 100644 --- a/targets/f7/api_symbols.csv +++ b/targets/f7/api_symbols.csv @@ -1,5 +1,5 @@ entry,status,name,type,params -Version,+,87.0,, +Version,+,87.1,, Header,+,applications/drivers/subghz/cc1101_ext/cc1101_ext_interconnect.h,, Header,+,applications/services/bt/bt_service/bt.h,, Header,+,applications/services/bt/bt_service/bt_keys_storage.h,, @@ -63,6 +63,9 @@ Header,+,lib/ibutton/ibutton_protocols.h,, Header,+,lib/ibutton/ibutton_worker.h,, Header,+,lib/ieee754_parse_wrap/wrappers.h,, Header,+,lib/infrared/encoder_decoder/infrared.h,, +Header,+,lib/infrared/signal/infrared_brute_force.h,, +Header,+,lib/infrared/signal/infrared_error_code.h,, +Header,+,lib/infrared/signal/infrared_signal.h,, Header,+,lib/infrared/worker/infrared_transmit.h,, Header,+,lib/infrared/worker/infrared_worker.h,, Header,+,lib/lfrfid/lfrfid_dict_file.h,, @@ -418,6 +421,7 @@ Function,-,Osal_MemSet,void*,"void*, int, unsigned int" Function,-,SystemCoreClockUpdate,void, Function,-,SystemInit,void, Function,-,_Exit,void,int +Function,+,__aeabi_f2d,double,float Function,+,__aeabi_uldivmod,void*,"uint64_t, uint64_t" Function,-,__assert,void,"const char*, int, const char*" Function,+,__assert_func,void,"const char*, int, const char*, const char*" @@ -625,8 +629,8 @@ Function,-,arc4random_uniform,__uint32_t,__uint32_t Function,+,args_char_to_hex,_Bool,"char, char, uint8_t*" Function,+,args_get_first_word_length,size_t,FuriString* Function,+,args_length,size_t,FuriString* -Function,+,args_read_float_and_trim,_Bool,"FuriString*, float*" Function,+,args_read_duration,_Bool,"FuriString*, uint32_t*, const char*" +Function,+,args_read_float_and_trim,_Bool,"FuriString*, float*" Function,+,args_read_hex_bytes,_Bool,"FuriString*, uint8_t*, size_t" Function,+,args_read_int_and_trim,_Bool,"FuriString*, int*" Function,+,args_read_probably_quoted_string_and_trim,_Bool,"FuriString*, FuriString*" @@ -2065,6 +2069,16 @@ Function,-,infinity,double, Function,-,infinityf,float, Function,+,infrared_alloc_decoder,InfraredDecoderHandler*, Function,+,infrared_alloc_encoder,InfraredEncoderHandler*, +Function,-,infrared_brute_force_add_record,void,"InfraredBruteForce*, uint32_t, const char*" +Function,-,infrared_brute_force_alloc,InfraredBruteForce*, +Function,-,infrared_brute_force_calculate_messages,InfraredErrorCode,InfraredBruteForce* +Function,-,infrared_brute_force_free,void,InfraredBruteForce* +Function,-,infrared_brute_force_is_started,_Bool,const InfraredBruteForce* +Function,-,infrared_brute_force_reset,void,InfraredBruteForce* +Function,-,infrared_brute_force_send,_Bool,"InfraredBruteForce*, uint32_t" +Function,-,infrared_brute_force_set_db_filename,void,"InfraredBruteForce*, const char*" +Function,-,infrared_brute_force_start,_Bool,"InfraredBruteForce*, uint32_t, uint32_t*" +Function,-,infrared_brute_force_stop,void,InfraredBruteForce* Function,+,infrared_check_decoder_ready,const InfraredMessage*,InfraredDecoderHandler* Function,+,infrared_decode,const InfraredMessage*,"InfraredDecoderHandler*, _Bool, uint32_t" Function,+,infrared_encode,InfraredStatus,"InfraredEncoderHandler*, uint32_t*, _Bool*" @@ -2083,6 +2097,22 @@ Function,+,infrared_reset_encoder,void,"InfraredEncoderHandler*, const InfraredM Function,+,infrared_send,void,"const InfraredMessage*, int" Function,+,infrared_send_raw,void,"const uint32_t[], uint32_t, _Bool" Function,+,infrared_send_raw_ext,void,"const uint32_t[], uint32_t, _Bool, uint32_t, float" +Function,-,infrared_signal_alloc,InfraredSignal*, +Function,-,infrared_signal_free,void,InfraredSignal* +Function,-,infrared_signal_get_message,const InfraredMessage*,const InfraredSignal* +Function,-,infrared_signal_get_raw_signal,const InfraredRawSignal*,const InfraredSignal* +Function,-,infrared_signal_is_raw,_Bool,const InfraredSignal* +Function,-,infrared_signal_is_valid,_Bool,const InfraredSignal* +Function,-,infrared_signal_read,InfraredErrorCode,"InfraredSignal*, FlipperFormat*, FuriString*" +Function,-,infrared_signal_read_body,InfraredErrorCode,"InfraredSignal*, FlipperFormat*" +Function,-,infrared_signal_read_name,InfraredErrorCode,"FlipperFormat*, FuriString*" +Function,-,infrared_signal_save,InfraredErrorCode,"const InfraredSignal*, FlipperFormat*, const char*" +Function,-,infrared_signal_search_by_index_and_read,InfraredErrorCode,"InfraredSignal*, FlipperFormat*, size_t" +Function,-,infrared_signal_search_by_name_and_read,InfraredErrorCode,"InfraredSignal*, FlipperFormat*, const char*" +Function,-,infrared_signal_set_message,void,"InfraredSignal*, const InfraredMessage*" +Function,-,infrared_signal_set_raw_signal,void,"InfraredSignal*, const uint32_t*, size_t, uint32_t, float" +Function,-,infrared_signal_set_signal,void,"InfraredSignal*, const InfraredSignal*" +Function,-,infrared_signal_transmit,void,const InfraredSignal* Function,+,infrared_worker_alloc,InfraredWorker*, Function,+,infrared_worker_free,void,InfraredWorker* Function,+,infrared_worker_get_decoded_signal,const InfraredMessage*,const InfraredWorkerSignal* diff --git a/targets/f7/platform_specific/intrinsic_export.h b/targets/f7/platform_specific/intrinsic_export.h index d3c7be5e04..989bcafb25 100644 --- a/targets/f7/platform_specific/intrinsic_export.h +++ b/targets/f7/platform_specific/intrinsic_export.h @@ -8,6 +8,7 @@ extern "C" { void __clear_cache(void*, void*); void* __aeabi_uldivmod(uint64_t, uint64_t); +double __aeabi_f2d(float); #ifdef __cplusplus }