Merge branch 'ofwdev' into 420

This commit is contained in:
RogueMaster
2022-09-27 18:02:53 -04:00
5 changed files with 138 additions and 42 deletions

View File

@@ -23,13 +23,17 @@ struct InfraredBruteForce {
FlipperFormat* ff; FlipperFormat* ff;
const char* db_filename; const char* db_filename;
string_t current_record_name; string_t current_record_name;
InfraredSignal* current_signal;
InfraredBruteForceRecordDict_t records; InfraredBruteForceRecordDict_t records;
bool is_started;
}; };
InfraredBruteForce* infrared_brute_force_alloc() { InfraredBruteForce* infrared_brute_force_alloc() {
InfraredBruteForce* brute_force = malloc(sizeof(InfraredBruteForce)); InfraredBruteForce* brute_force = malloc(sizeof(InfraredBruteForce));
brute_force->ff = NULL; brute_force->ff = NULL;
brute_force->db_filename = NULL; brute_force->db_filename = NULL;
brute_force->current_signal = NULL;
brute_force->is_started = false;
string_init(brute_force->current_record_name); string_init(brute_force->current_record_name);
InfraredBruteForceRecordDict_init(brute_force->records); InfraredBruteForceRecordDict_init(brute_force->records);
return brute_force; return brute_force;
@@ -40,17 +44,19 @@ void infrared_brute_force_clear_records(InfraredBruteForce* brute_force) {
} }
void infrared_brute_force_free(InfraredBruteForce* brute_force) { void infrared_brute_force_free(InfraredBruteForce* brute_force) {
furi_assert(!brute_force->ff); furi_assert(!brute_force->is_started);
InfraredBruteForceRecordDict_clear(brute_force->records); InfraredBruteForceRecordDict_clear(brute_force->records);
string_clear(brute_force->current_record_name); string_clear(brute_force->current_record_name);
free(brute_force); free(brute_force);
} }
void infrared_brute_force_set_db_filename(InfraredBruteForce* brute_force, const char* db_filename) { void infrared_brute_force_set_db_filename(InfraredBruteForce* brute_force, const char* db_filename) {
furi_assert(!brute_force->is_started);
brute_force->db_filename = db_filename; brute_force->db_filename = db_filename;
} }
bool infrared_brute_force_calculate_messages(InfraredBruteForce* brute_force) { bool infrared_brute_force_calculate_messages(InfraredBruteForce* brute_force) {
furi_assert(!brute_force->is_started);
furi_assert(brute_force->db_filename); furi_assert(brute_force->db_filename);
bool success = false; bool success = false;
@@ -80,6 +86,7 @@ bool infrared_brute_force_start(
InfraredBruteForce* brute_force, InfraredBruteForce* brute_force,
uint32_t index, uint32_t index,
uint32_t* record_count) { uint32_t* record_count) {
furi_assert(!brute_force->is_started);
bool success = false; bool success = false;
*record_count = 0; *record_count = 0;
@@ -100,50 +107,37 @@ bool infrared_brute_force_start(
if(*record_count) { if(*record_count) {
Storage* storage = furi_record_open(RECORD_STORAGE); Storage* storage = furi_record_open(RECORD_STORAGE);
brute_force->ff = flipper_format_buffered_file_alloc(storage); brute_force->ff = flipper_format_buffered_file_alloc(storage);
brute_force->current_signal = infrared_signal_alloc();
brute_force->is_started = true;
success = success =
flipper_format_buffered_file_open_existing(brute_force->ff, brute_force->db_filename); flipper_format_buffered_file_open_existing(brute_force->ff, brute_force->db_filename);
if(!success) { if(!success) infrared_brute_force_stop(brute_force);
flipper_format_free(brute_force->ff);
brute_force->ff = NULL;
furi_record_close(RECORD_STORAGE);
}
} }
return success; return success;
} }
bool infrared_brute_force_is_started(InfraredBruteForce* brute_force) { bool infrared_brute_force_is_started(InfraredBruteForce* brute_force) {
return brute_force->ff; return brute_force->is_started;
} }
void infrared_brute_force_stop(InfraredBruteForce* brute_force) { void infrared_brute_force_stop(InfraredBruteForce* brute_force) {
furi_assert(string_size(brute_force->current_record_name)); furi_assert(brute_force->is_started);
furi_assert(brute_force->ff);
string_reset(brute_force->current_record_name); string_reset(brute_force->current_record_name);
infrared_signal_free(brute_force->current_signal);
flipper_format_free(brute_force->ff); flipper_format_free(brute_force->ff);
furi_record_close(RECORD_STORAGE); brute_force->current_signal = NULL;
brute_force->ff = NULL; brute_force->ff = NULL;
brute_force->is_started = false;
furi_record_close(RECORD_STORAGE);
} }
bool infrared_brute_force_send_next(InfraredBruteForce* brute_force) { bool infrared_brute_force_send_next(InfraredBruteForce* brute_force) {
furi_assert(string_size(brute_force->current_record_name)); furi_assert(brute_force->is_started);
furi_assert(brute_force->ff); const bool success = infrared_signal_search_and_read(
bool success = false; brute_force->current_signal, brute_force->ff, brute_force->current_record_name);
string_t signal_name;
string_init(signal_name);
InfraredSignal* signal = infrared_signal_alloc();
do {
success = infrared_signal_read(signal, brute_force->ff, signal_name);
} while(success && !string_equal_p(brute_force->current_record_name, signal_name));
if(success) { if(success) {
infrared_signal_transmit(signal); infrared_signal_transmit(brute_force->current_signal);
} }
infrared_signal_free(signal);
string_clear(signal_name);
return success; return success;
} }
@@ -157,3 +151,8 @@ void infrared_brute_force_add_record(
InfraredBruteForceRecordDict_set_at(brute_force->records, key, value); InfraredBruteForceRecordDict_set_at(brute_force->records, key, value);
string_clear(key); string_clear(key);
} }
void infrared_brute_force_reset(InfraredBruteForce* brute_force) {
furi_assert(!brute_force->is_started);
InfraredBruteForceRecordDict_reset(brute_force->records);
}

View File

@@ -146,6 +146,26 @@ static inline bool infrared_signal_read_raw(InfraredSignal* signal, FlipperForma
return success; return success;
} }
static bool infrared_signal_read_body(InfraredSignal* signal, FlipperFormat* ff) {
string_t tmp;
string_init(tmp);
bool success = false;
do {
if(!flipper_format_read_string(ff, "type", tmp)) break;
if(string_equal_p(tmp, "raw")) {
success = infrared_signal_read_raw(signal, ff);
} else if(string_equal_p(tmp, "parsed")) {
success = infrared_signal_read_message(signal, ff);
} else {
FURI_LOG_E(TAG, "Unknown signal type");
}
} while(false);
string_clear(tmp);
return success;
}
InfraredSignal* infrared_signal_alloc() { InfraredSignal* infrared_signal_alloc() {
InfraredSignal* signal = malloc(sizeof(InfraredSignal)); InfraredSignal* signal = malloc(sizeof(InfraredSignal));
@@ -227,24 +247,41 @@ bool infrared_signal_save(InfraredSignal* signal, FlipperFormat* ff, const char*
} }
bool infrared_signal_read(InfraredSignal* signal, FlipperFormat* ff, string_t name) { bool infrared_signal_read(InfraredSignal* signal, FlipperFormat* ff, string_t name) {
string_t buf; string_t tmp;
string_init(buf); string_init(tmp);
bool success = false; bool success = false;
do { do {
if(!flipper_format_read_string(ff, "name", buf)) break; if(!flipper_format_read_string(ff, "name", tmp)) break;
string_set(name, buf); string_set(name, tmp);
if(!flipper_format_read_string(ff, "type", buf)) break; if(!infrared_signal_read_body(signal, ff)) break;
if(!string_cmp_str(buf, "raw")) { success = true;
success = infrared_signal_read_raw(signal, ff);
} else if(!string_cmp_str(buf, "parsed")) {
success = infrared_signal_read_message(signal, ff);
} else {
FURI_LOG_E(TAG, "Unknown type of signal (allowed - raw/parsed) ");
}
} while(0); } while(0);
string_clear(buf); string_clear(tmp);
return success;
}
bool infrared_signal_search_and_read(
InfraredSignal* signal,
FlipperFormat* ff,
const string_t name) {
bool success = false;
string_t tmp;
string_init(tmp);
do {
bool is_name_found = false;
while(flipper_format_read_string(ff, "name", tmp)) {
is_name_found = string_equal_p(name, tmp);
if(is_name_found) break;
}
if(!is_name_found) break;
if(!infrared_signal_read_body(signal, ff)) break;
success = true;
} while(false);
string_clear(tmp);
return success; return success;
} }

View File

@@ -37,5 +37,9 @@ InfraredMessage* infrared_signal_get_message(InfraredSignal* signal);
bool infrared_signal_save(InfraredSignal* signal, FlipperFormat* ff, const char* name); bool infrared_signal_save(InfraredSignal* signal, FlipperFormat* ff, const char* name);
bool infrared_signal_read(InfraredSignal* signal, FlipperFormat* ff, string_t name); bool infrared_signal_read(InfraredSignal* signal, FlipperFormat* ff, string_t name);
bool infrared_signal_search_and_read(
InfraredSignal* signal,
FlipperFormat* ff,
const string_t name);
void infrared_signal_transmit(InfraredSignal* signal); void infrared_signal_transmit(InfraredSignal* signal);

View File

@@ -0,0 +1,40 @@
# Universal Remotes
## Air Conditioners
### Recording signals
Air conditioners differ from most other infrared-controlled devices because their state is tracked by the remote.
The majority of A/C remotes have a small display which shows current mode, temperature and other settings.
When the user presses a button, a whole set of parameters is transmitted to the device, which must be recorded and used as a whole.
In order to add a particular air conditioner to the universal remote, 6 signals must be recorded: `Off`, `Dh`, `Cool_hi`, `Cool_lo`, `Heat_hi`, `Heat_lo`.
Each signal (except `Off`) is recorded using the following algorithm:
1. Get the remote and press the **Power Button** so that the display shows that A/C is ON.
2. Set the A/C to the corresponding mode (see table below), while leaving other parameters such as fan speed or vane on **AUTO** (if applicable).
3. Press the **POWER** button to switch the A/C off.
4. Start learning a new remote on Flipper if it's the first button or press `+` to add a new button otherwise.
5. Point the remote to Flipper's IR receiver as directed and press **POWER** button once again.
6. Save the resulting signal under the specified name.
7. Repeat the steps 2-6 for each signal from the table below.
| Signal | Mode | Temperature | Note |
| :-----: | :--------: | :---------: | ----------------------------------- |
| Dh | Dehumidify | N/A | |
| Cool_hi | Cooling | See note | Lowest temperature in cooling mode |
| Cool_lo | Cooling | 23°C | |
| Heat_hi | Heating | See note | Highest temperature in heating mode |
| Heat_lo | Heating | 23°C | |
Finally, record the `Off` signal:
1. Make sure the display shows that A/C is ON.
2. Start learning a new signal on Flipper and point the remote towards the IR receiver.
3. Press the **POWER** button so that the remote shows the OFF state.
4. Save the resulting signal under the name `Off`.
The resulting remote file should now contain 6 signals. Any of them can be omitted, but that will mean that this functionality will not be used.
Test the file against the actual device. Every signal must do what it's supposed to.
If everything checks out, append these signals **to the end** of the [A/C universal remote file](/assets/resources/infrared/assets/ac.ir).
The order of signals is not important, but they must be preceded by a following comment: `# Model: <Your model name>` in order to keep the library organised.
When done, open a pull request containing the changed file.

View File

@@ -209,8 +209,24 @@ void mf_df_cat_file(MifareDesfireFile* file, string_t out) {
uint8_t* data = file->contents; uint8_t* data = file->contents;
if(data) { if(data) {
for(int rec = 0; rec < num; rec++) { for(int rec = 0; rec < num; rec++) {
for(int ch = 0; ch < size; ch++) { string_cat_printf(out, "record %d\n", rec);
string_cat_printf(out, "%02x", data[rec * size + ch]); for(int ch = 0; ch < size; ch += 4) {
string_cat_printf(out, "%03x|", ch);
for(int i = 0; i < 4; i++) {
if(ch + i < size) {
string_cat_printf(out, "%02x ", data[rec * size + ch + i]);
} else {
string_cat_printf(out, " ");
}
}
for(int i = 0; i < 4 && ch + i < size; i++) {
if(isprint(data[rec * size + ch + i])) {
string_cat_printf(out, "%c", data[rec * size + ch + i]);
} else {
string_cat_printf(out, ".");
}
}
string_cat_printf(out, "\n");
} }
string_cat_printf(out, " \n"); string_cat_printf(out, " \n");
} }