| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537 |
- #include <furi.h>
- #include <flipper_format.h>
- #include <infrared.h>
- #include <common/infrared_common_i.h>
- #include "../minunit.h"
- #define IR_TEST_FILES_DIR EXT_PATH("unit_tests/infrared/")
- #define IR_TEST_FILE_PREFIX "test_"
- #define IR_TEST_FILE_SUFFIX ".irtest"
- typedef struct {
- InfraredDecoderHandler* decoder_handler;
- InfraredEncoderHandler* encoder_handler;
- FuriString* file_path;
- FlipperFormat* ff;
- } InfraredTest;
- static InfraredTest* test;
- static void infrared_test_alloc() {
- Storage* storage = furi_record_open(RECORD_STORAGE);
- test = malloc(sizeof(InfraredTest));
- test->decoder_handler = infrared_alloc_decoder();
- test->encoder_handler = infrared_alloc_encoder();
- test->ff = flipper_format_buffered_file_alloc(storage);
- test->file_path = furi_string_alloc();
- }
- static void infrared_test_free() {
- furi_assert(test);
- infrared_free_decoder(test->decoder_handler);
- infrared_free_encoder(test->encoder_handler);
- flipper_format_free(test->ff);
- furi_string_free(test->file_path);
- furi_record_close(RECORD_STORAGE);
- free(test);
- test = NULL;
- }
- static bool infrared_test_prepare_file(const char* protocol_name) {
- FuriString* file_type;
- file_type = furi_string_alloc();
- bool success = false;
- furi_string_printf(
- test->file_path,
- "%s%s%s%s",
- IR_TEST_FILES_DIR,
- IR_TEST_FILE_PREFIX,
- protocol_name,
- IR_TEST_FILE_SUFFIX);
- do {
- uint32_t format_version;
- if(!flipper_format_buffered_file_open_existing(
- test->ff, furi_string_get_cstr(test->file_path)))
- break;
- if(!flipper_format_read_header(test->ff, file_type, &format_version)) break;
- if(furi_string_cmp_str(file_type, "IR tests file") || format_version != 1) break;
- success = true;
- } while(false);
- furi_string_free(file_type);
- return success;
- }
- static bool infrared_test_load_raw_signal(
- FlipperFormat* ff,
- const char* signal_name,
- uint32_t** timings,
- uint32_t* timings_count) {
- FuriString* buf;
- buf = furi_string_alloc();
- bool success = false;
- do {
- bool is_name_found = false;
- for(; !is_name_found && flipper_format_read_string(ff, "name", buf);
- is_name_found = !furi_string_cmp(buf, signal_name))
- ;
- if(!is_name_found) break;
- if(!flipper_format_read_string(ff, "type", buf) || furi_string_cmp_str(buf, "raw")) break;
- if(!flipper_format_get_value_count(ff, "data", timings_count)) break;
- if(!*timings_count) break;
- *timings = malloc(*timings_count * sizeof(uint32_t*));
- if(!flipper_format_read_uint32(ff, "data", *timings, *timings_count)) {
- free(*timings);
- break;
- }
- success = true;
- } while(false);
- furi_string_free(buf);
- return success;
- }
- static bool infrared_test_read_message(FlipperFormat* ff, InfraredMessage* message) {
- FuriString* buf;
- buf = furi_string_alloc();
- bool success = false;
- do {
- if(!flipper_format_read_string(ff, "protocol", buf)) break;
- message->protocol = infrared_get_protocol_by_name(furi_string_get_cstr(buf));
- if(!infrared_is_protocol_valid(message->protocol)) break;
- if(!flipper_format_read_hex(ff, "address", (uint8_t*)&message->address, sizeof(uint32_t)))
- break;
- if(!flipper_format_read_hex(ff, "command", (uint8_t*)&message->command, sizeof(uint32_t)))
- break;
- if(!flipper_format_read_bool(ff, "repeat", &message->repeat, 1)) break;
- success = true;
- } while(false);
- furi_string_free(buf);
- return success;
- }
- static bool infrared_test_load_messages(
- FlipperFormat* ff,
- const char* signal_name,
- InfraredMessage** messages,
- uint32_t* messages_count) {
- FuriString* buf;
- buf = furi_string_alloc();
- bool success = false;
- do {
- bool is_name_found = false;
- for(; !is_name_found && flipper_format_read_string(ff, "name", buf);
- is_name_found = !furi_string_cmp(buf, signal_name))
- ;
- if(!is_name_found) break;
- if(!flipper_format_read_string(ff, "type", buf) ||
- furi_string_cmp_str(buf, "parsed_array"))
- break;
- if(!flipper_format_read_uint32(ff, "count", messages_count, 1)) break;
- if(!*messages_count) break;
- *messages = malloc(*messages_count * sizeof(InfraredMessage));
- uint32_t i;
- for(i = 0; i < *messages_count; ++i) {
- if(!infrared_test_read_message(ff, (*messages) + i)) {
- break;
- }
- }
- if(*messages_count != i) {
- free(*messages);
- break;
- }
- success = true;
- } while(false);
- furi_string_free(buf);
- return success;
- }
- static void infrared_test_compare_message_results(
- const InfraredMessage* message_decoded,
- const InfraredMessage* message_expected) {
- mu_check(message_decoded->protocol == message_expected->protocol);
- mu_check(message_decoded->command == message_expected->command);
- mu_check(message_decoded->address == message_expected->address);
- if((message_expected->protocol == InfraredProtocolSIRC) ||
- (message_expected->protocol == InfraredProtocolSIRC15) ||
- (message_expected->protocol == InfraredProtocolSIRC20)) {
- mu_check(message_decoded->repeat == false);
- } else {
- mu_check(message_decoded->repeat == message_expected->repeat);
- }
- }
- /* Encodes signal and merges same levels (high+high, low+low) */
- static void infrared_test_run_encoder_fill_array(
- InfraredEncoderHandler* handler,
- uint32_t* timings,
- uint32_t* timings_len,
- bool* start_level) {
- uint32_t duration = 0;
- bool level = false;
- bool level_read;
- InfraredStatus status = InfraredStatusError;
- size_t i = 0;
- bool first = true;
- while(1) {
- status = infrared_encode(handler, &duration, &level_read);
- if(first) {
- if(start_level) *start_level = level_read;
- first = false;
- timings[0] = 0;
- } else if(level_read != level) {
- ++i;
- furi_check(i < *timings_len);
- timings[i] = 0;
- }
- level = level_read;
- timings[i] += duration;
- furi_check((status == InfraredStatusOk) || (status == InfraredStatusDone));
- if(status == InfraredStatusDone) break;
- }
- *timings_len = i + 1;
- }
- // messages in input array for encoder should have one protocol
- static void infrared_test_run_encoder(InfraredProtocol protocol, uint32_t test_index) {
- uint32_t* timings;
- uint32_t timings_count = 200;
- uint32_t* expected_timings;
- uint32_t expected_timings_count;
- InfraredMessage* input_messages;
- uint32_t input_messages_count;
- FuriString* buf;
- buf = furi_string_alloc();
- const char* protocol_name = infrared_get_protocol_name(protocol);
- mu_assert(infrared_test_prepare_file(protocol_name), "Failed to prepare test file");
- furi_string_printf(buf, "encoder_input%ld", test_index);
- mu_assert(
- infrared_test_load_messages(
- test->ff, furi_string_get_cstr(buf), &input_messages, &input_messages_count),
- "Failed to load messages from file");
- furi_string_printf(buf, "encoder_expected%ld", test_index);
- mu_assert(
- infrared_test_load_raw_signal(
- test->ff, furi_string_get_cstr(buf), &expected_timings, &expected_timings_count),
- "Failed to load raw signal from file");
- flipper_format_buffered_file_close(test->ff);
- furi_string_free(buf);
- uint32_t j = 0;
- timings = malloc(sizeof(uint32_t) * timings_count);
- for(uint32_t message_counter = 0; message_counter < input_messages_count; ++message_counter) {
- const InfraredMessage* message = &input_messages[message_counter];
- if(!message->repeat) {
- infrared_reset_encoder(test->encoder_handler, message);
- }
- timings_count = 200;
- infrared_test_run_encoder_fill_array(test->encoder_handler, timings, &timings_count, NULL);
- furi_check(timings_count <= 200);
- for(size_t i = 0; i < timings_count; ++i, ++j) {
- mu_check(MATCH_TIMING(timings[i], expected_timings[j], 120));
- mu_assert(j < expected_timings_count, "encoded more timings than expected");
- }
- }
- free(input_messages);
- free(expected_timings);
- free(timings);
- mu_assert(j == expected_timings_count, "encoded less timings than expected");
- }
- static void infrared_test_run_encoder_decoder(InfraredProtocol protocol, uint32_t test_index) {
- uint32_t* timings = 0;
- uint32_t timings_count = 200;
- InfraredMessage* input_messages;
- uint32_t input_messages_count;
- bool level = false;
- FuriString* buf;
- buf = furi_string_alloc();
- timings = malloc(sizeof(uint32_t) * timings_count);
- const char* protocol_name = infrared_get_protocol_name(protocol);
- mu_assert(infrared_test_prepare_file(protocol_name), "Failed to prepare test file");
- furi_string_printf(buf, "encoder_decoder_input%ld", test_index);
- mu_assert(
- infrared_test_load_messages(
- test->ff, furi_string_get_cstr(buf), &input_messages, &input_messages_count),
- "Failed to load messages from file");
- flipper_format_buffered_file_close(test->ff);
- furi_string_free(buf);
- for(uint32_t message_counter = 0; message_counter < input_messages_count; ++message_counter) {
- const InfraredMessage* message_encoded = &input_messages[message_counter];
- if(!message_encoded->repeat) {
- infrared_reset_encoder(test->encoder_handler, message_encoded);
- }
- timings_count = 200;
- infrared_test_run_encoder_fill_array(
- test->encoder_handler, timings, &timings_count, &level);
- furi_check(timings_count <= 200);
- const InfraredMessage* message_decoded = 0;
- for(size_t i = 0; i < timings_count; ++i) {
- message_decoded = infrared_decode(test->decoder_handler, level, timings[i]);
- if((i == timings_count - 2) && level && message_decoded) {
- /* In case we end with space timing - message can be decoded at last mark */
- break;
- } else if(i < timings_count - 1) {
- mu_check(!message_decoded);
- } else {
- if(!message_decoded) {
- message_decoded = infrared_check_decoder_ready(test->decoder_handler);
- }
- mu_check(message_decoded);
- }
- level = !level;
- }
- if(message_decoded) {
- infrared_test_compare_message_results(message_decoded, message_encoded);
- } else {
- mu_check(0);
- }
- }
- free(input_messages);
- free(timings);
- }
- static void infrared_test_run_decoder(InfraredProtocol protocol, uint32_t test_index) {
- uint32_t* timings;
- uint32_t timings_count;
- InfraredMessage* messages;
- uint32_t messages_count;
- FuriString* buf;
- buf = furi_string_alloc();
- mu_assert(
- infrared_test_prepare_file(infrared_get_protocol_name(protocol)),
- "Failed to prepare test file");
- furi_string_printf(buf, "decoder_input%ld", test_index);
- mu_assert(
- infrared_test_load_raw_signal(
- test->ff, furi_string_get_cstr(buf), &timings, &timings_count),
- "Failed to load raw signal from file");
- furi_string_printf(buf, "decoder_expected%ld", test_index);
- mu_assert(
- infrared_test_load_messages(
- test->ff, furi_string_get_cstr(buf), &messages, &messages_count),
- "Failed to load messages from file");
- flipper_format_buffered_file_close(test->ff);
- furi_string_free(buf);
- InfraredMessage message_decoded_check_local;
- bool level = 0;
- uint32_t message_counter = 0;
- const InfraredMessage* message_decoded = 0;
- for(uint32_t i = 0; i < timings_count; ++i) {
- const InfraredMessage* message_decoded_check = 0;
- if(timings[i] > INFRARED_RAW_RX_TIMING_DELAY_US) {
- message_decoded_check = infrared_check_decoder_ready(test->decoder_handler);
- if(message_decoded_check) {
- /* infrared_decode() can reset message, but we have to call infrared_decode() to perform real
- * simulation: infrared_check() by timeout, then infrared_decode() when meet edge */
- message_decoded_check_local = *message_decoded_check;
- message_decoded_check = &message_decoded_check_local;
- }
- }
- message_decoded = infrared_decode(test->decoder_handler, level, timings[i]);
- if(message_decoded_check || message_decoded) {
- mu_assert(
- !(message_decoded_check && message_decoded),
- "both messages decoded: check_ready() and infrared_decode()");
- if(message_decoded_check) {
- message_decoded = message_decoded_check;
- }
- mu_assert(message_counter < messages_count, "decoded more than expected");
- infrared_test_compare_message_results(message_decoded, &messages[message_counter]);
- ++message_counter;
- }
- level = !level;
- }
- message_decoded = infrared_check_decoder_ready(test->decoder_handler);
- if(message_decoded) {
- infrared_test_compare_message_results(message_decoded, &messages[message_counter]);
- ++message_counter;
- }
- free(timings);
- free(messages);
- mu_assert(message_counter == messages_count, "decoded less than expected");
- }
- MU_TEST(infrared_test_decoder_samsung32) {
- infrared_test_run_decoder(InfraredProtocolSamsung32, 1);
- }
- MU_TEST(infrared_test_decoder_mixed) {
- infrared_test_run_decoder(InfraredProtocolRC5, 2);
- infrared_test_run_decoder(InfraredProtocolSIRC, 1);
- infrared_test_run_decoder(InfraredProtocolNECext, 1);
- infrared_test_run_decoder(InfraredProtocolRC6, 2);
- infrared_test_run_decoder(InfraredProtocolSamsung32, 1);
- infrared_test_run_decoder(InfraredProtocolRC6, 1);
- infrared_test_run_decoder(InfraredProtocolSamsung32, 1);
- infrared_test_run_decoder(InfraredProtocolRC5, 1);
- infrared_test_run_decoder(InfraredProtocolSIRC, 2);
- infrared_test_run_decoder(InfraredProtocolNECext, 1);
- infrared_test_run_decoder(InfraredProtocolSIRC, 4);
- infrared_test_run_decoder(InfraredProtocolNEC, 2);
- infrared_test_run_decoder(InfraredProtocolRC6, 1);
- infrared_test_run_decoder(InfraredProtocolNECext, 1);
- infrared_test_run_decoder(InfraredProtocolSIRC, 5);
- infrared_test_run_decoder(InfraredProtocolNEC, 3);
- infrared_test_run_decoder(InfraredProtocolRC5, 5);
- infrared_test_run_decoder(InfraredProtocolSamsung32, 1);
- infrared_test_run_decoder(InfraredProtocolSIRC, 3);
- infrared_test_run_decoder(InfraredProtocolKaseikyo, 1);
- }
- MU_TEST(infrared_test_decoder_nec) {
- infrared_test_run_decoder(InfraredProtocolNEC, 1);
- infrared_test_run_decoder(InfraredProtocolNEC, 2);
- infrared_test_run_decoder(InfraredProtocolNEC, 3);
- }
- MU_TEST(infrared_test_decoder_unexpected_end_in_sequence) {
- infrared_test_run_decoder(InfraredProtocolNEC, 1);
- infrared_test_run_decoder(InfraredProtocolNEC, 1);
- infrared_test_run_decoder(InfraredProtocolNEC, 2);
- infrared_test_run_decoder(InfraredProtocolNEC, 2);
- }
- MU_TEST(infrared_test_decoder_necext1) {
- infrared_test_run_decoder(InfraredProtocolNECext, 1);
- infrared_test_run_decoder(InfraredProtocolNECext, 1);
- }
- MU_TEST(infrared_test_decoder_long_packets_with_nec_start) {
- infrared_test_run_decoder(InfraredProtocolNEC42ext, 1);
- infrared_test_run_decoder(InfraredProtocolNEC42ext, 2);
- }
- MU_TEST(infrared_test_encoder_sirc) {
- infrared_test_run_encoder(InfraredProtocolSIRC, 1);
- infrared_test_run_encoder(InfraredProtocolSIRC, 2);
- }
- MU_TEST(infrared_test_decoder_sirc) {
- infrared_test_run_decoder(InfraredProtocolSIRC, 3);
- infrared_test_run_decoder(InfraredProtocolSIRC, 1);
- infrared_test_run_decoder(InfraredProtocolSIRC, 2);
- infrared_test_run_decoder(InfraredProtocolSIRC, 4);
- infrared_test_run_decoder(InfraredProtocolSIRC, 5);
- }
- MU_TEST(infrared_test_decoder_rc5) {
- infrared_test_run_decoder(InfraredProtocolRC5X, 1);
- infrared_test_run_decoder(InfraredProtocolRC5, 1);
- infrared_test_run_decoder(InfraredProtocolRC5, 2);
- infrared_test_run_decoder(InfraredProtocolRC5, 3);
- infrared_test_run_decoder(InfraredProtocolRC5, 4);
- infrared_test_run_decoder(InfraredProtocolRC5, 5);
- infrared_test_run_decoder(InfraredProtocolRC5, 6);
- infrared_test_run_decoder(InfraredProtocolRC5, 7);
- }
- MU_TEST(infrared_test_encoder_rc5x) {
- infrared_test_run_encoder(InfraredProtocolRC5X, 1);
- }
- MU_TEST(infrared_test_encoder_rc5) {
- infrared_test_run_encoder(InfraredProtocolRC5, 1);
- }
- MU_TEST(infrared_test_decoder_rc6) {
- infrared_test_run_decoder(InfraredProtocolRC6, 1);
- }
- MU_TEST(infrared_test_encoder_rc6) {
- infrared_test_run_encoder(InfraredProtocolRC6, 1);
- }
- MU_TEST(infrared_test_decoder_kaseikyo) {
- infrared_test_run_decoder(InfraredProtocolKaseikyo, 1);
- infrared_test_run_decoder(InfraredProtocolKaseikyo, 2);
- infrared_test_run_decoder(InfraredProtocolKaseikyo, 3);
- infrared_test_run_decoder(InfraredProtocolKaseikyo, 4);
- infrared_test_run_decoder(InfraredProtocolKaseikyo, 5);
- infrared_test_run_decoder(InfraredProtocolKaseikyo, 6);
- }
- MU_TEST(infrared_test_encoder_decoder_all) {
- infrared_test_run_encoder_decoder(InfraredProtocolNEC, 1);
- infrared_test_run_encoder_decoder(InfraredProtocolNECext, 1);
- infrared_test_run_encoder_decoder(InfraredProtocolNEC42, 1);
- infrared_test_run_encoder_decoder(InfraredProtocolNEC42ext, 1);
- infrared_test_run_encoder_decoder(InfraredProtocolSamsung32, 1);
- infrared_test_run_encoder_decoder(InfraredProtocolRC6, 1);
- infrared_test_run_encoder_decoder(InfraredProtocolRC5, 1);
- infrared_test_run_encoder_decoder(InfraredProtocolSIRC, 1);
- infrared_test_run_encoder_decoder(InfraredProtocolKaseikyo, 1);
- }
- MU_TEST_SUITE(infrared_test) {
- MU_SUITE_CONFIGURE(&infrared_test_alloc, &infrared_test_free);
- MU_RUN_TEST(infrared_test_encoder_sirc);
- MU_RUN_TEST(infrared_test_decoder_sirc);
- MU_RUN_TEST(infrared_test_encoder_rc5x);
- MU_RUN_TEST(infrared_test_encoder_rc5);
- MU_RUN_TEST(infrared_test_decoder_rc5);
- MU_RUN_TEST(infrared_test_decoder_rc6);
- MU_RUN_TEST(infrared_test_encoder_rc6);
- MU_RUN_TEST(infrared_test_decoder_unexpected_end_in_sequence);
- MU_RUN_TEST(infrared_test_decoder_long_packets_with_nec_start);
- MU_RUN_TEST(infrared_test_decoder_nec);
- MU_RUN_TEST(infrared_test_decoder_samsung32);
- MU_RUN_TEST(infrared_test_decoder_necext1);
- MU_RUN_TEST(infrared_test_decoder_kaseikyo);
- MU_RUN_TEST(infrared_test_decoder_mixed);
- MU_RUN_TEST(infrared_test_encoder_decoder_all);
- }
- int run_minunit_test_infrared() {
- MU_RUN_SUITE(infrared_test);
- return MU_EXIT_CODE;
- }
|