[FL-1505] Add RAW format (#576)
* Add RAW format * F5 stubs for build to pass * Fix saving decoded signal error * Irda: set ISR before starting timer, remove explicit NVIC configuration Co-authored-by: あく <alleteam@gmail.com>
This commit is contained in:
parent
a2dfa33a9f
commit
13c5a8cb20
@ -1,24 +1,48 @@
|
|||||||
#include "app-template.h"
|
#include <api-hal-delay.h>
|
||||||
#include "cli/cli.h"
|
#include <irda.h>
|
||||||
#include "cmsis_os2.h"
|
#include <app-template.h>
|
||||||
|
#include <cli/cli.h>
|
||||||
|
#include <cmsis_os2.h>
|
||||||
|
#include <irda_worker.h>
|
||||||
#include <furi.h>
|
#include <furi.h>
|
||||||
#include <api-hal-irda.h>
|
#include <api-hal-irda.h>
|
||||||
#include "irda.h"
|
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <m-string.h>
|
#include <m-string.h>
|
||||||
|
#include <irda_transmit.h>
|
||||||
|
|
||||||
typedef struct IrdaCli {
|
static void signal_received_callback(void* context, IrdaWorkerSignal* received_signal) {
|
||||||
IrdaDecoderHandler* handler;
|
furi_assert(received_signal);
|
||||||
osMessageQueueId_t message_queue;
|
char buf[100];
|
||||||
} IrdaCli;
|
size_t buf_cnt;
|
||||||
|
Cli* cli = (Cli*)context;
|
||||||
|
|
||||||
static void irda_rx_callback(void* ctx, bool level, uint32_t duration) {
|
if(irda_worker_signal_is_decoded(received_signal)) {
|
||||||
IrdaCli* irda_cli = (IrdaCli*)ctx;
|
const IrdaMessage* message = irda_worker_get_decoded_message(received_signal);
|
||||||
const IrdaMessage* message;
|
buf_cnt = sniprintf(
|
||||||
message = irda_decode(irda_cli->handler, level, duration);
|
buf,
|
||||||
if(message) {
|
sizeof(buf),
|
||||||
osMessageQueuePut(irda_cli->message_queue, message, 0, 0);
|
"%s, A:0x%0*lX, C:0x%0*lX%s\r\n",
|
||||||
|
irda_get_protocol_name(message->protocol),
|
||||||
|
irda_get_protocol_address_length(message->protocol),
|
||||||
|
message->address,
|
||||||
|
irda_get_protocol_command_length(message->protocol),
|
||||||
|
message->command,
|
||||||
|
message->repeat ? " R" : "");
|
||||||
|
cli_write(cli, (uint8_t*)buf, buf_cnt);
|
||||||
|
} else {
|
||||||
|
const uint32_t* timings;
|
||||||
|
size_t timings_cnt;
|
||||||
|
irda_worker_get_raw_signal(received_signal, &timings, &timings_cnt);
|
||||||
|
|
||||||
|
buf_cnt = sniprintf(buf, sizeof(buf), "RAW, %d samples:\r\n", timings_cnt);
|
||||||
|
cli_write(cli, (uint8_t*)buf, buf_cnt);
|
||||||
|
for(size_t i = 0; i < timings_cnt; ++i) {
|
||||||
|
buf_cnt = sniprintf(buf, sizeof(buf), "%lu ", timings[i]);
|
||||||
|
cli_write(cli, (uint8_t*)buf, buf_cnt);
|
||||||
|
}
|
||||||
|
buf_cnt = sniprintf(buf, sizeof(buf), "\r\n");
|
||||||
|
cli_write(cli, (uint8_t*)buf, buf_cnt);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -27,30 +51,19 @@ static void irda_cli_start_ir_rx(Cli* cli, string_t args, void* context) {
|
|||||||
printf("IRDA is busy. Exit.");
|
printf("IRDA is busy. Exit.");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
IrdaCli irda_cli;
|
|
||||||
irda_cli.handler = irda_alloc_decoder();
|
IrdaWorker* worker = irda_worker_alloc();
|
||||||
irda_cli.message_queue = osMessageQueueNew(2, sizeof(IrdaMessage), NULL);
|
irda_worker_set_context(worker, cli);
|
||||||
api_hal_irda_rx_irq_init();
|
irda_worker_start(worker);
|
||||||
api_hal_irda_rx_irq_set_callback(irda_rx_callback, &irda_cli);
|
irda_worker_set_received_signal_callback(worker, signal_received_callback);
|
||||||
|
|
||||||
printf("Receiving IRDA...\r\nPress Ctrl+C to abort\r\n");
|
printf("Receiving IRDA...\r\nPress Ctrl+C to abort\r\n");
|
||||||
while(!cli_cmd_interrupt_received(cli)) {
|
while(!cli_cmd_interrupt_received(cli)) {
|
||||||
IrdaMessage message;
|
delay(50);
|
||||||
if(osOK == osMessageQueueGet(irda_cli.message_queue, &message, NULL, 50)) {
|
|
||||||
printf(
|
|
||||||
"%s, A:0x%0*lX, C:0x%0*lX%s\r\n",
|
|
||||||
irda_get_protocol_name(message.protocol),
|
|
||||||
irda_get_protocol_address_length(message.protocol),
|
|
||||||
message.address,
|
|
||||||
irda_get_protocol_command_length(message.protocol),
|
|
||||||
message.command,
|
|
||||||
message.repeat ? " R" : "");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
api_hal_irda_rx_irq_deinit();
|
irda_worker_stop(worker);
|
||||||
irda_free_decoder(irda_cli.handler);
|
irda_worker_free(worker);
|
||||||
osMessageQueueDelete(irda_cli.message_queue);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void irda_cli_print_usage(void) {
|
static void irda_cli_print_usage(void) {
|
||||||
@ -63,38 +76,93 @@ static void irda_cli_print_usage(void) {
|
|||||||
printf("\r\n");
|
printf("\r\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool parse_message(const char* str, IrdaMessage* message) {
|
||||||
|
uint32_t command = 0;
|
||||||
|
uint32_t address = 0;
|
||||||
|
char protocol_name[32];
|
||||||
|
int parsed = sscanf(str, "%31s %lX %lX", protocol_name, &address, &command);
|
||||||
|
|
||||||
|
if(parsed != 3) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
IrdaProtocol protocol = irda_get_protocol_by_name(protocol_name);
|
||||||
|
|
||||||
|
if(!irda_is_protocol_valid(protocol)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
message->protocol = protocol;
|
||||||
|
message->address = address;
|
||||||
|
message->command = command;
|
||||||
|
message->repeat = false;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool parse_signal_raw(
|
||||||
|
const char* str,
|
||||||
|
uint32_t* timings,
|
||||||
|
uint32_t* timings_cnt,
|
||||||
|
float* duty_cycle,
|
||||||
|
float* frequency) {
|
||||||
|
char frequency_str[10];
|
||||||
|
char duty_cycle_str[10];
|
||||||
|
int parsed = sscanf(str, "RAW F:%9s DC:%9s", frequency_str, duty_cycle_str);
|
||||||
|
if(parsed != 2) return false;
|
||||||
|
|
||||||
|
*frequency = atoi(frequency_str);
|
||||||
|
*duty_cycle = (float)atoi(duty_cycle_str) / 100;
|
||||||
|
str += strlen(frequency_str) + strlen(duty_cycle_str) + 10;
|
||||||
|
|
||||||
|
uint32_t timings_cnt_max = *timings_cnt;
|
||||||
|
*timings_cnt = 0;
|
||||||
|
|
||||||
|
while(1) {
|
||||||
|
char timing_str[10];
|
||||||
|
for(; *str == ' '; ++str)
|
||||||
|
;
|
||||||
|
if(1 != sscanf(str, "%9s", timing_str)) break;
|
||||||
|
str += strlen(timing_str);
|
||||||
|
uint32_t timing = atoi(timing_str);
|
||||||
|
if(timing <= 0) break;
|
||||||
|
if(*timings_cnt >= timings_cnt_max) break;
|
||||||
|
timings[*timings_cnt] = timing;
|
||||||
|
++*timings_cnt;
|
||||||
|
}
|
||||||
|
|
||||||
|
printf("\r\nTransmit:");
|
||||||
|
for(size_t i = 0; i < *timings_cnt; ++i) {
|
||||||
|
printf(" %ld", timings[i]);
|
||||||
|
}
|
||||||
|
printf("\r\n");
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
static void irda_cli_start_ir_tx(Cli* cli, string_t args, void* context) {
|
static void irda_cli_start_ir_tx(Cli* cli, string_t args, void* context) {
|
||||||
if(api_hal_irda_rx_irq_is_busy()) {
|
if(api_hal_irda_rx_irq_is_busy()) {
|
||||||
printf("IRDA is busy. Exit.");
|
printf("IRDA is busy. Exit.");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t command = 0;
|
IrdaMessage message;
|
||||||
uint32_t address = 0;
|
const char* str = string_get_cstr(args);
|
||||||
char protocol_name[32];
|
float frequency;
|
||||||
int parsed = sscanf(string_get_cstr(args), "%31s %lX %lX", protocol_name, &address, &command);
|
float duty_cycle;
|
||||||
|
uint32_t* timings = (uint32_t*)furi_alloc(sizeof(uint32_t) * 1000);
|
||||||
|
uint32_t timings_cnt = 1000;
|
||||||
|
|
||||||
if(parsed != 3) {
|
if(parse_message(str, &message)) {
|
||||||
|
irda_send(&message, 1);
|
||||||
|
} else if(parse_signal_raw(str, timings, &timings_cnt, &duty_cycle, &frequency)) {
|
||||||
|
irda_send_raw_ext(timings, timings_cnt, true, duty_cycle, frequency);
|
||||||
|
} else {
|
||||||
printf("Wrong arguments.\r\n");
|
printf("Wrong arguments.\r\n");
|
||||||
irda_cli_print_usage();
|
irda_cli_print_usage();
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
IrdaProtocol protocol = irda_get_protocol_by_name(protocol_name);
|
free(timings);
|
||||||
|
|
||||||
if(!irda_is_protocol_valid(protocol)) {
|
|
||||||
printf("Unknown protocol.\r\n");
|
|
||||||
irda_cli_print_usage();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
IrdaMessage message = {
|
|
||||||
.protocol = protocol,
|
|
||||||
.address = address,
|
|
||||||
.command = command,
|
|
||||||
.repeat = false,
|
|
||||||
};
|
|
||||||
irda_send(&message, 1);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
extern "C" void irda_cli_init() {
|
extern "C" void irda_cli_init() {
|
||||||
|
@ -16,7 +16,7 @@ bool IrdaAppBruteForce::calculate_messages() {
|
|||||||
|
|
||||||
file_parser.reset();
|
file_parser.reset();
|
||||||
while(1) {
|
while(1) {
|
||||||
auto message = file_parser.read_message(&file);
|
auto message = file_parser.read_signal(&file);
|
||||||
if(!message) break;
|
if(!message) break;
|
||||||
auto element = records.find(message->name);
|
auto element = records.find(message->name);
|
||||||
if(element != records.cend()) {
|
if(element != records.cend()) {
|
||||||
@ -37,19 +37,19 @@ void IrdaAppBruteForce::stop_bruteforce() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// TODO: [FL-1418] replace with timer-chained consequence of messages.
|
// TODO: [FL-1418] replace with timer-chained consequence of messages.
|
||||||
bool IrdaAppBruteForce::send_next_bruteforce(const IrdaAppSignalTransceiver& transceiver) {
|
bool IrdaAppBruteForce::send_next_bruteforce(void) {
|
||||||
furi_assert(current_record.size());
|
furi_assert(current_record.size());
|
||||||
|
|
||||||
std::unique_ptr<IrdaAppFileParser::IrdaFileMessage> message;
|
std::unique_ptr<IrdaAppFileParser::IrdaFileSignal> file_signal;
|
||||||
|
|
||||||
do {
|
do {
|
||||||
message = file_parser.read_message(&file);
|
file_signal = file_parser.read_signal(&file);
|
||||||
} while(message && current_record.compare(message->name));
|
} while(file_signal && current_record.compare(file_signal->name));
|
||||||
|
|
||||||
if(message) {
|
if(file_signal) {
|
||||||
transceiver.send_message(&message->message);
|
file_signal->signal.transmit();
|
||||||
}
|
}
|
||||||
return !!message;
|
return !!file_signal;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool IrdaAppBruteForce::start_bruteforce(int index, int& record_amount) {
|
bool IrdaAppBruteForce::start_bruteforce(int index, int& record_amount) {
|
||||||
|
@ -2,7 +2,6 @@
|
|||||||
#include "furi/check.h"
|
#include "furi/check.h"
|
||||||
#include <unordered_map>
|
#include <unordered_map>
|
||||||
#include "irda-app-file-parser.hpp"
|
#include "irda-app-file-parser.hpp"
|
||||||
#include "irda-app-transceiver.hpp"
|
|
||||||
|
|
||||||
|
|
||||||
class IrdaAppBruteForce {
|
class IrdaAppBruteForce {
|
||||||
@ -26,7 +25,7 @@ class IrdaAppBruteForce {
|
|||||||
public:
|
public:
|
||||||
bool calculate_messages();
|
bool calculate_messages();
|
||||||
void stop_bruteforce();
|
void stop_bruteforce();
|
||||||
bool send_next_bruteforce(const IrdaAppSignalTransceiver& receiver);
|
bool send_next_bruteforce();
|
||||||
bool start_bruteforce(int index, int& record_amount);
|
bool start_bruteforce(int index, int& record_amount);
|
||||||
void add_record(int index, const char* name);
|
void add_record(int index, const char* name);
|
||||||
|
|
||||||
|
@ -1,26 +1,83 @@
|
|||||||
#include "irda-app-file-parser.hpp"
|
#include "irda-app-file-parser.hpp"
|
||||||
|
#include "irda-app-remote-manager.hpp"
|
||||||
|
#include "irda-app-signal.h"
|
||||||
|
#include <irda.h>
|
||||||
|
#include <cstdio>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <string_view>
|
||||||
|
#include <furi.h>
|
||||||
|
|
||||||
std::unique_ptr<IrdaAppFileParser::IrdaFileMessage> IrdaAppFileParser::read_message(File* file) {
|
uint32_t const IrdaAppFileParser::max_line_length = ((9 + 1) * 512 + 100);
|
||||||
|
|
||||||
|
std::unique_ptr<IrdaAppFileParser::IrdaFileSignal> IrdaAppFileParser::read_signal(File* file) {
|
||||||
while(1) {
|
while(1) {
|
||||||
auto str = getline(file);
|
auto str = getline(file);
|
||||||
if(str.empty()) return nullptr;
|
if(str.empty()) return nullptr;
|
||||||
|
|
||||||
auto message = parse_message(str);
|
auto message = parse_signal(str);
|
||||||
|
if(!message.get()) {
|
||||||
|
message = parse_signal_raw(str);
|
||||||
|
}
|
||||||
if(message) return message;
|
if(message) return message;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
std::unique_ptr<IrdaAppFileParser::IrdaFileMessage>
|
bool IrdaAppFileParser::store_signal(File* file, const IrdaAppSignal& signal, const char* name) {
|
||||||
IrdaAppFileParser::parse_message(const std::string& str) const {
|
char* content = new char[max_line_length];
|
||||||
|
size_t written = 0;
|
||||||
|
|
||||||
|
if(!signal.is_raw()) {
|
||||||
|
auto message = signal.get_message();
|
||||||
|
auto protocol = message.protocol;
|
||||||
|
|
||||||
|
sniprintf(
|
||||||
|
content,
|
||||||
|
max_line_length,
|
||||||
|
"%.31s %.31s A:%0*lX C:%0*lX\n",
|
||||||
|
name,
|
||||||
|
irda_get_protocol_name(protocol),
|
||||||
|
irda_get_protocol_address_length(protocol),
|
||||||
|
message.address,
|
||||||
|
irda_get_protocol_command_length(protocol),
|
||||||
|
message.command);
|
||||||
|
written = strlen(content);
|
||||||
|
} else {
|
||||||
|
int duty_cycle = 100 * IRDA_COMMON_DUTY_CYCLE;
|
||||||
|
written += sniprintf(
|
||||||
|
&content[written],
|
||||||
|
max_line_length - written,
|
||||||
|
"%.31s RAW F:%d DC:%d",
|
||||||
|
name,
|
||||||
|
IRDA_COMMON_CARRIER_FREQUENCY,
|
||||||
|
duty_cycle);
|
||||||
|
|
||||||
|
auto& raw_signal = signal.get_raw_signal();
|
||||||
|
for(size_t i = 0; i < raw_signal.timings_cnt; ++i) {
|
||||||
|
written += sniprintf(
|
||||||
|
&content[written], max_line_length - written, " %ld", raw_signal.timings[i]);
|
||||||
|
furi_assert(written <= max_line_length);
|
||||||
|
}
|
||||||
|
written += snprintf(&content[written], max_line_length - written, "\n");
|
||||||
|
}
|
||||||
|
furi_assert(written < max_line_length);
|
||||||
|
|
||||||
|
size_t write_count = 0;
|
||||||
|
write_count = get_fs_api().file.write(file, content, written);
|
||||||
|
delete[] content;
|
||||||
|
return (file->error_id == FSE_OK) && (write_count == written);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::unique_ptr<IrdaAppFileParser::IrdaFileSignal>
|
||||||
|
IrdaAppFileParser::parse_signal(const std::string& str) const {
|
||||||
char protocol_name[32];
|
char protocol_name[32];
|
||||||
uint32_t address;
|
uint32_t address;
|
||||||
uint32_t command;
|
uint32_t command;
|
||||||
auto irda_file_message = std::make_unique<IrdaFileMessage>();
|
auto irda_file_signal = std::make_unique<IrdaFileSignal>();
|
||||||
|
|
||||||
int parsed = std::sscanf(
|
int parsed = std::sscanf(
|
||||||
str.c_str(),
|
str.c_str(),
|
||||||
"%31s %31s A:%lX C:%lX",
|
"%31s %31s A:%lX C:%lX",
|
||||||
irda_file_message->name,
|
irda_file_signal->name,
|
||||||
protocol_name,
|
protocol_name,
|
||||||
&address,
|
&address,
|
||||||
&command);
|
&command);
|
||||||
@ -47,12 +104,97 @@ std::unique_ptr<IrdaAppFileParser::IrdaFileMessage>
|
|||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
irda_file_message->message = {
|
IrdaMessage message = {
|
||||||
.protocol = protocol,
|
.protocol = protocol,
|
||||||
.address = address,
|
.address = address,
|
||||||
.command = command,
|
.command = command,
|
||||||
.repeat = false,
|
.repeat = false,
|
||||||
};
|
};
|
||||||
|
|
||||||
return irda_file_message;
|
irda_file_signal->signal.set_message(&message);
|
||||||
|
|
||||||
|
return irda_file_signal;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char* find_first_not_of(const char* str, char symbol) {
|
||||||
|
const char* str_start = nullptr;
|
||||||
|
while(str != str_start) {
|
||||||
|
str_start = str;
|
||||||
|
str = strchr(str, symbol);
|
||||||
|
}
|
||||||
|
|
||||||
|
return str;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::unique_ptr<IrdaAppFileParser::IrdaFileSignal>
|
||||||
|
IrdaAppFileParser::parse_signal_raw(const std::string& string) const {
|
||||||
|
char protocol_name[32];
|
||||||
|
uint32_t frequency;
|
||||||
|
uint32_t duty_cycle;
|
||||||
|
int str_len = string.size();
|
||||||
|
std::string_view str(string.c_str());
|
||||||
|
auto irda_file_signal = std::make_unique<IrdaFileSignal>();
|
||||||
|
|
||||||
|
int parsed = std::sscanf(
|
||||||
|
str.data(),
|
||||||
|
"%31s %31s F:%ld DC:%ld",
|
||||||
|
irda_file_signal->name,
|
||||||
|
protocol_name,
|
||||||
|
&frequency,
|
||||||
|
&duty_cycle);
|
||||||
|
|
||||||
|
if(parsed != 4) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
char dummy[100] = {0};
|
||||||
|
int header_len = 0;
|
||||||
|
header_len = sniprintf(
|
||||||
|
dummy,
|
||||||
|
sizeof(dummy),
|
||||||
|
"%.31s %.31s F:%ld DC:%ld",
|
||||||
|
irda_file_signal->name,
|
||||||
|
protocol_name,
|
||||||
|
frequency,
|
||||||
|
duty_cycle);
|
||||||
|
|
||||||
|
furi_assert(header_len < str_len);
|
||||||
|
str.remove_prefix(header_len);
|
||||||
|
|
||||||
|
/* move allocated timings into raw signal object */
|
||||||
|
IrdaAppSignal::RawSignal raw_signal = {.timings_cnt = 0, .timings = new uint32_t[500]};
|
||||||
|
bool result = false;
|
||||||
|
|
||||||
|
while(!str.empty()) {
|
||||||
|
char buf[10];
|
||||||
|
size_t index = str.find_first_not_of(' ', 1);
|
||||||
|
if(index == std::string_view::npos) {
|
||||||
|
result = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
str.remove_prefix(index);
|
||||||
|
parsed = std::sscanf(str.data(), "%9s", buf);
|
||||||
|
if(parsed != 1) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
str.remove_prefix(strlen(buf));
|
||||||
|
|
||||||
|
int value = atoi(buf);
|
||||||
|
if(value <= 0) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
raw_signal.timings[raw_signal.timings_cnt] = value;
|
||||||
|
++raw_signal.timings_cnt;
|
||||||
|
if(raw_signal.timings_cnt >= 500) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(result) {
|
||||||
|
irda_file_signal->signal.set_raw_signal(raw_signal.timings, raw_signal.timings_cnt);
|
||||||
|
} else {
|
||||||
|
(void)irda_file_signal.release();
|
||||||
|
delete[] raw_signal.timings;
|
||||||
|
}
|
||||||
|
return irda_file_signal;
|
||||||
}
|
}
|
||||||
|
@ -1,17 +1,26 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
#include "file_reader/file_reader.hpp"
|
#include <file_reader/file_reader.h>
|
||||||
#include "irda.h"
|
#include <irda.h>
|
||||||
|
#include "irda-app-remote-manager.hpp"
|
||||||
|
|
||||||
class IrdaAppFileParser : public FileReader {
|
class IrdaAppFileParser : public FileReader {
|
||||||
public:
|
public:
|
||||||
typedef struct {
|
typedef struct {
|
||||||
char name[32];
|
char name[32];
|
||||||
IrdaMessage message;
|
IrdaAppSignal signal;
|
||||||
} IrdaFileMessage;
|
} IrdaFileSignal;
|
||||||
|
|
||||||
std::unique_ptr<IrdaAppFileParser::IrdaFileMessage> read_message(File* file);
|
IrdaAppFileParser() {
|
||||||
|
/* Assume we can save max 512 samples */
|
||||||
|
set_max_line_length(max_line_length);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::unique_ptr<IrdaAppFileParser::IrdaFileSignal> read_signal(File* file);
|
||||||
|
bool store_signal(File* file, const IrdaAppSignal& signal, const char* name);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::unique_ptr<IrdaFileMessage> parse_message(const std::string& str) const;
|
static const uint32_t max_line_length;
|
||||||
|
std::unique_ptr<IrdaFileSignal> parse_signal(const std::string& str) const;
|
||||||
|
std::unique_ptr<IrdaFileSignal> parse_signal_raw(const std::string& str) const;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -33,16 +33,15 @@ static std::string
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool IrdaAppRemoteManager::add_button(const char* button_name, const IrdaMessage* message) {
|
bool IrdaAppRemoteManager::add_button(const char* button_name, const IrdaAppSignal& signal) {
|
||||||
remote->buttons.emplace_back(button_name, message);
|
remote->buttons.emplace_back(button_name, signal);
|
||||||
return store();
|
return store();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool IrdaAppRemoteManager::add_remote_with_button(
|
bool IrdaAppRemoteManager::add_remote_with_button(
|
||||||
const char* button_name,
|
const char* button_name,
|
||||||
const IrdaMessage* message) {
|
const IrdaAppSignal& signal) {
|
||||||
furi_check(button_name != nullptr);
|
furi_check(button_name != nullptr);
|
||||||
furi_check(message != nullptr);
|
|
||||||
|
|
||||||
std::vector<std::string> remote_list;
|
std::vector<std::string> remote_list;
|
||||||
bool result = get_remote_list(remote_list);
|
bool result = get_remote_list(remote_list);
|
||||||
@ -51,7 +50,7 @@ bool IrdaAppRemoteManager::add_remote_with_button(
|
|||||||
auto new_name = find_vacant_name(remote_list, default_remote_name);
|
auto new_name = find_vacant_name(remote_list, default_remote_name);
|
||||||
|
|
||||||
remote = std::make_unique<IrdaAppRemote>(new_name);
|
remote = std::make_unique<IrdaAppRemote>(new_name);
|
||||||
return add_button(button_name, message);
|
return add_button(button_name, signal);
|
||||||
}
|
}
|
||||||
|
|
||||||
IrdaAppRemote::IrdaAppRemote(const std::string& name)
|
IrdaAppRemote::IrdaAppRemote(const std::string& name)
|
||||||
@ -70,12 +69,12 @@ std::vector<std::string> IrdaAppRemoteManager::get_button_list(void) const {
|
|||||||
return name_vector;
|
return name_vector;
|
||||||
}
|
}
|
||||||
|
|
||||||
const IrdaMessage* IrdaAppRemoteManager::get_button_data(size_t index) const {
|
const IrdaAppSignal& IrdaAppRemoteManager::get_button_data(size_t index) const {
|
||||||
furi_check(remote.get() != nullptr);
|
furi_check(remote.get() != nullptr);
|
||||||
auto& buttons = remote->buttons;
|
auto& buttons = remote->buttons;
|
||||||
furi_check(index < buttons.size());
|
furi_check(index < buttons.size());
|
||||||
|
|
||||||
return &buttons.at(index).message;
|
return buttons.at(index).signal;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string IrdaAppRemoteManager::make_filename(const std::string& name) const {
|
std::string IrdaAppRemoteManager::make_filename(const std::string& name) const {
|
||||||
@ -166,7 +165,6 @@ size_t IrdaAppRemoteManager::get_number_of_buttons() {
|
|||||||
|
|
||||||
bool IrdaAppRemoteManager::store(void) {
|
bool IrdaAppRemoteManager::store(void) {
|
||||||
File file;
|
File file;
|
||||||
uint16_t write_count;
|
|
||||||
std::string dirname(std::string("/") + irda_directory);
|
std::string dirname(std::string("/") + irda_directory);
|
||||||
|
|
||||||
IrdaAppFileParser file_parser;
|
IrdaAppFileParser file_parser;
|
||||||
@ -186,25 +184,9 @@ bool IrdaAppRemoteManager::store(void) {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
char content[128];
|
|
||||||
|
|
||||||
for(const auto& button : remote->buttons) {
|
for(const auto& button : remote->buttons) {
|
||||||
auto protocol = button.message.protocol;
|
bool result = file_parser.store_signal(&file, button.signal, button.name.c_str());
|
||||||
|
if(!result) {
|
||||||
sniprintf(
|
|
||||||
content,
|
|
||||||
sizeof(content),
|
|
||||||
"%.31s %.31s A:%0*lX C:%0*lX\n",
|
|
||||||
button.name.c_str(),
|
|
||||||
irda_get_protocol_name(protocol),
|
|
||||||
irda_get_protocol_address_length(protocol),
|
|
||||||
button.message.address,
|
|
||||||
irda_get_protocol_command_length(protocol),
|
|
||||||
button.message.command);
|
|
||||||
|
|
||||||
auto content_len = strlen(content);
|
|
||||||
write_count = file_parser.get_fs_api().file.write(&file, content, content_len);
|
|
||||||
if(file.error_id != FSE_OK || write_count != content_len) {
|
|
||||||
file_parser.get_sd_api().show_error(
|
file_parser.get_sd_api().show_error(
|
||||||
file_parser.get_sd_api().context, "Cannot write\nto key file");
|
file_parser.get_sd_api().context, "Cannot write\nto key file");
|
||||||
file_parser.get_fs_api().file.close(&file);
|
file_parser.get_fs_api().file.close(&file);
|
||||||
@ -267,9 +249,9 @@ bool IrdaAppRemoteManager::load(const std::string& name) {
|
|||||||
remote = std::make_unique<IrdaAppRemote>(name);
|
remote = std::make_unique<IrdaAppRemote>(name);
|
||||||
|
|
||||||
while(1) {
|
while(1) {
|
||||||
auto message = file_parser.read_message(&file);
|
auto file_signal = file_parser.read_signal(&file);
|
||||||
if(!message) break;
|
if(!file_signal.get()) break;
|
||||||
remote->buttons.emplace_back(message->name, &message->message);
|
remote->buttons.emplace_back(file_signal->name, file_signal->signal);
|
||||||
}
|
}
|
||||||
file_parser.get_fs_api().file.close(&file);
|
file_parser.get_fs_api().file.close(&file);
|
||||||
|
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
#include <irda_worker.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
@ -6,14 +7,16 @@
|
|||||||
#include <irda.h>
|
#include <irda.h>
|
||||||
#include <sd-card-api.h>
|
#include <sd-card-api.h>
|
||||||
#include <filesystem-api.h>
|
#include <filesystem-api.h>
|
||||||
|
#include "irda-app-signal.h"
|
||||||
|
|
||||||
|
|
||||||
class IrdaAppRemoteButton {
|
class IrdaAppRemoteButton {
|
||||||
friend class IrdaAppRemoteManager;
|
friend class IrdaAppRemoteManager;
|
||||||
std::string name;
|
std::string name;
|
||||||
IrdaMessage message;
|
IrdaAppSignal signal;
|
||||||
public:
|
public:
|
||||||
IrdaAppRemoteButton(const char* name, const IrdaMessage* message)
|
IrdaAppRemoteButton(const char* name, const IrdaAppSignal& signal)
|
||||||
: name(name), message (*message) {}
|
: name(name), signal (signal) {}
|
||||||
~IrdaAppRemoteButton() {}
|
~IrdaAppRemoteButton() {}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -38,8 +41,8 @@ class IrdaAppRemoteManager {
|
|||||||
std::string make_filename(const std::string& name) const;
|
std::string make_filename(const std::string& name) const;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
bool add_remote_with_button(const char* button_name, const IrdaMessage* message);
|
bool add_remote_with_button(const char* button_name, const IrdaAppSignal& signal);
|
||||||
bool add_button(const char* button_name, const IrdaMessage* message);
|
bool add_button(const char* button_name, const IrdaAppSignal& signal);
|
||||||
|
|
||||||
int find_remote_name(const std::vector<std::string>& strings);
|
int find_remote_name(const std::vector<std::string>& strings);
|
||||||
bool rename_button(uint32_t index, const char* str);
|
bool rename_button(uint32_t index, const char* str);
|
||||||
@ -50,7 +53,7 @@ public:
|
|||||||
std::string get_button_name(uint32_t index);
|
std::string get_button_name(uint32_t index);
|
||||||
std::string get_remote_name();
|
std::string get_remote_name();
|
||||||
size_t get_number_of_buttons();
|
size_t get_number_of_buttons();
|
||||||
const IrdaMessage* get_button_data(size_t button_index) const;
|
const IrdaAppSignal& get_button_data(size_t index) const;
|
||||||
bool delete_button(uint32_t index);
|
bool delete_button(uint32_t index);
|
||||||
bool delete_remote();
|
bool delete_remote();
|
||||||
|
|
||||||
|
95
applications/irda/irda-app-signal.cpp
Normal file
95
applications/irda/irda-app-signal.cpp
Normal file
@ -0,0 +1,95 @@
|
|||||||
|
#include "irda-app-signal.h"
|
||||||
|
#include <irda_transmit.h>
|
||||||
|
|
||||||
|
void IrdaAppSignal::copy_timings(const uint32_t* timings, size_t size) {
|
||||||
|
furi_assert(size);
|
||||||
|
furi_assert(timings);
|
||||||
|
|
||||||
|
if(size) {
|
||||||
|
payload.raw.timings = new uint32_t[size];
|
||||||
|
payload.raw.timings_cnt = size;
|
||||||
|
memcpy(payload.raw.timings, timings, size * sizeof(uint32_t));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void IrdaAppSignal::clear_timings() {
|
||||||
|
if(!decoded) {
|
||||||
|
delete[] payload.raw.timings;
|
||||||
|
payload.raw.timings_cnt = 0;
|
||||||
|
payload.raw.timings = nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
IrdaAppSignal::IrdaAppSignal(const uint32_t* timings, size_t timings_cnt) {
|
||||||
|
decoded = false;
|
||||||
|
copy_timings(timings, timings_cnt);
|
||||||
|
}
|
||||||
|
|
||||||
|
IrdaAppSignal::IrdaAppSignal(const IrdaMessage* irda_message) {
|
||||||
|
decoded = true;
|
||||||
|
payload.message = *irda_message;
|
||||||
|
}
|
||||||
|
|
||||||
|
IrdaAppSignal& IrdaAppSignal::operator=(const IrdaAppSignal& other) {
|
||||||
|
clear_timings();
|
||||||
|
decoded = other.decoded;
|
||||||
|
if(decoded) {
|
||||||
|
payload.message = other.payload.message;
|
||||||
|
} else {
|
||||||
|
copy_timings(other.payload.raw.timings, other.payload.raw.timings_cnt);
|
||||||
|
}
|
||||||
|
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
IrdaAppSignal::IrdaAppSignal(const IrdaAppSignal& other) {
|
||||||
|
decoded = other.decoded;
|
||||||
|
if(decoded) {
|
||||||
|
payload.message = other.payload.message;
|
||||||
|
} else {
|
||||||
|
copy_timings(other.payload.raw.timings, other.payload.raw.timings_cnt);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
IrdaAppSignal::IrdaAppSignal(IrdaAppSignal&& other) {
|
||||||
|
clear_timings();
|
||||||
|
|
||||||
|
decoded = other.decoded;
|
||||||
|
if(decoded) {
|
||||||
|
payload.message = other.payload.message;
|
||||||
|
} else {
|
||||||
|
furi_assert(other.payload.raw.timings_cnt > 0);
|
||||||
|
|
||||||
|
payload.raw.timings = other.payload.raw.timings;
|
||||||
|
payload.raw.timings_cnt = other.payload.raw.timings_cnt;
|
||||||
|
other.payload.raw.timings = nullptr;
|
||||||
|
other.payload.raw.timings_cnt = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void IrdaAppSignal::set_message(const IrdaMessage* irda_message) {
|
||||||
|
clear_timings();
|
||||||
|
decoded = true;
|
||||||
|
payload.message = *irda_message;
|
||||||
|
}
|
||||||
|
|
||||||
|
void IrdaAppSignal::set_raw_signal(uint32_t* timings, size_t timings_cnt) {
|
||||||
|
clear_timings();
|
||||||
|
decoded = false;
|
||||||
|
payload.raw.timings = timings;
|
||||||
|
payload.raw.timings_cnt = timings_cnt;
|
||||||
|
}
|
||||||
|
|
||||||
|
void IrdaAppSignal::copy_raw_signal(uint32_t* timings, size_t timings_cnt) {
|
||||||
|
clear_timings();
|
||||||
|
decoded = false;
|
||||||
|
copy_timings(timings, timings_cnt);
|
||||||
|
}
|
||||||
|
|
||||||
|
void IrdaAppSignal::transmit() const {
|
||||||
|
if(decoded) {
|
||||||
|
irda_send(&payload.message, 1);
|
||||||
|
} else {
|
||||||
|
irda_send_raw(payload.raw.timings, payload.raw.timings_cnt, true);
|
||||||
|
}
|
||||||
|
}
|
61
applications/irda/irda-app-signal.h
Normal file
61
applications/irda/irda-app-signal.h
Normal file
@ -0,0 +1,61 @@
|
|||||||
|
#pragma once
|
||||||
|
#include <irda_worker.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <string>
|
||||||
|
#include <irda.h>
|
||||||
|
|
||||||
|
class IrdaAppSignal {
|
||||||
|
public:
|
||||||
|
typedef struct {
|
||||||
|
size_t timings_cnt;
|
||||||
|
uint32_t* timings;
|
||||||
|
} RawSignal;
|
||||||
|
|
||||||
|
private:
|
||||||
|
bool decoded;
|
||||||
|
union {
|
||||||
|
IrdaMessage message;
|
||||||
|
RawSignal raw;
|
||||||
|
} payload;
|
||||||
|
|
||||||
|
void copy_timings(const uint32_t* timings, size_t size);
|
||||||
|
void clear_timings();
|
||||||
|
|
||||||
|
public:
|
||||||
|
IrdaAppSignal() {
|
||||||
|
decoded = true;
|
||||||
|
payload.message.protocol = IrdaProtocolUnknown;
|
||||||
|
}
|
||||||
|
|
||||||
|
~IrdaAppSignal() {
|
||||||
|
clear_timings();
|
||||||
|
}
|
||||||
|
|
||||||
|
IrdaAppSignal(const uint32_t* timings, size_t timings_cnt);
|
||||||
|
IrdaAppSignal(const IrdaMessage* irda_message);
|
||||||
|
|
||||||
|
IrdaAppSignal(const IrdaAppSignal& other);
|
||||||
|
IrdaAppSignal(IrdaAppSignal&& other);
|
||||||
|
|
||||||
|
IrdaAppSignal& operator=(const IrdaAppSignal& signal);
|
||||||
|
|
||||||
|
void set_message(const IrdaMessage* irda_message);
|
||||||
|
void set_raw_signal(uint32_t* timings, size_t timings_cnt);
|
||||||
|
void copy_raw_signal(uint32_t* timings, size_t timings_cnt);
|
||||||
|
|
||||||
|
void transmit() const;
|
||||||
|
|
||||||
|
bool is_raw(void) const {
|
||||||
|
return !decoded;
|
||||||
|
}
|
||||||
|
|
||||||
|
const IrdaMessage& get_message(void) const {
|
||||||
|
furi_assert(decoded);
|
||||||
|
return payload.message;
|
||||||
|
}
|
||||||
|
|
||||||
|
const RawSignal& get_raw_signal(void) const {
|
||||||
|
furi_assert(!decoded);
|
||||||
|
return payload.raw;
|
||||||
|
}
|
||||||
|
};
|
@ -1,56 +0,0 @@
|
|||||||
#include "irda-app.hpp"
|
|
||||||
#include "irda.h"
|
|
||||||
#include <api-hal-irda.h>
|
|
||||||
|
|
||||||
void IrdaAppSignalTransceiver::irda_rx_callback(void* ctx, bool level, uint32_t duration) {
|
|
||||||
IrdaAppEvent event;
|
|
||||||
const IrdaMessage* irda_message;
|
|
||||||
IrdaAppSignalTransceiver* this_ = static_cast<IrdaAppSignalTransceiver*>(ctx);
|
|
||||||
|
|
||||||
irda_message = irda_decode(this_->decoder, level, duration);
|
|
||||||
if(irda_message) {
|
|
||||||
this_->message = *irda_message;
|
|
||||||
event.type = IrdaAppEvent::Type::IrdaMessageReceived;
|
|
||||||
osStatus_t result = osMessageQueuePut(this_->event_queue, &event, 0, 0);
|
|
||||||
furi_check(result == osOK);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
IrdaAppSignalTransceiver::IrdaAppSignalTransceiver(void)
|
|
||||||
: capture_started(false)
|
|
||||||
, decoder(irda_alloc_decoder()) {
|
|
||||||
}
|
|
||||||
|
|
||||||
IrdaAppSignalTransceiver::~IrdaAppSignalTransceiver() {
|
|
||||||
capture_stop();
|
|
||||||
irda_free_decoder(decoder);
|
|
||||||
}
|
|
||||||
|
|
||||||
void IrdaAppSignalTransceiver::capture_once_start(osMessageQueueId_t queue) {
|
|
||||||
event_queue = queue;
|
|
||||||
irda_reset_decoder(decoder);
|
|
||||||
if(!capture_started) {
|
|
||||||
capture_started = true;
|
|
||||||
api_hal_irda_rx_irq_set_callback(IrdaAppSignalTransceiver::irda_rx_callback, this);
|
|
||||||
api_hal_irda_rx_irq_init();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void IrdaAppSignalTransceiver::capture_stop(void) {
|
|
||||||
IrdaAppEvent event;
|
|
||||||
|
|
||||||
if(capture_started) {
|
|
||||||
capture_started = false;
|
|
||||||
api_hal_irda_rx_irq_deinit();
|
|
||||||
while(osMessageQueueGet(this->event_queue, &event, 0, 0) == osOK)
|
|
||||||
;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
IrdaMessage* IrdaAppSignalTransceiver::get_last_message(void) {
|
|
||||||
return &message;
|
|
||||||
}
|
|
||||||
|
|
||||||
void IrdaAppSignalTransceiver::send_message(const IrdaMessage* message) const {
|
|
||||||
irda_send(message, 1);
|
|
||||||
}
|
|
@ -1,21 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
#include <furi.h>
|
|
||||||
#include <irda.h>
|
|
||||||
|
|
||||||
class IrdaAppSignalTransceiver {
|
|
||||||
public:
|
|
||||||
IrdaAppSignalTransceiver(void);
|
|
||||||
~IrdaAppSignalTransceiver(void);
|
|
||||||
void capture_once_start(osMessageQueueId_t event_queue);
|
|
||||||
void capture_stop(void);
|
|
||||||
IrdaMessage* get_last_message(void);
|
|
||||||
void send_message(const IrdaMessage* message) const;
|
|
||||||
|
|
||||||
private:
|
|
||||||
bool capture_started;
|
|
||||||
osMessageQueueId_t event_queue;
|
|
||||||
static void irda_rx_callback(void* ctx, bool level, uint32_t duration);
|
|
||||||
IrdaDecoderHandler* decoder;
|
|
||||||
IrdaMessage message;
|
|
||||||
};
|
|
||||||
|
|
@ -1,4 +1,5 @@
|
|||||||
#include "irda-app.hpp"
|
#include "irda-app.hpp"
|
||||||
|
#include <irda_worker.h>
|
||||||
#include <furi.h>
|
#include <furi.h>
|
||||||
#include <gui/gui.h>
|
#include <gui/gui.h>
|
||||||
#include <input/input.h>
|
#include <input/input.h>
|
||||||
@ -99,10 +100,6 @@ IrdaAppRemoteManager* IrdaApp::get_remote_manager() {
|
|||||||
return &remote_manager;
|
return &remote_manager;
|
||||||
}
|
}
|
||||||
|
|
||||||
IrdaAppSignalTransceiver* IrdaApp::get_transceiver() {
|
|
||||||
return &transceiver;
|
|
||||||
}
|
|
||||||
|
|
||||||
void IrdaApp::set_text_store(uint8_t index, const char* text...) {
|
void IrdaApp::set_text_store(uint8_t index, const char* text...) {
|
||||||
furi_check(index < text_store_max);
|
furi_check(index < text_store_max);
|
||||||
|
|
||||||
@ -220,3 +217,15 @@ void IrdaApp::notify_green_on() {
|
|||||||
void IrdaApp::notify_green_off() {
|
void IrdaApp::notify_green_off() {
|
||||||
notification_message(notification, &sequence_reset_green);
|
notification_message(notification, &sequence_reset_green);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
IrdaWorker* IrdaApp::get_irda_worker() {
|
||||||
|
return irda_worker;
|
||||||
|
}
|
||||||
|
|
||||||
|
const IrdaAppSignal& IrdaApp::get_received_signal() const {
|
||||||
|
return received_signal;
|
||||||
|
}
|
||||||
|
|
||||||
|
void IrdaApp::set_received_signal(const IrdaAppSignal& signal) {
|
||||||
|
received_signal = signal;
|
||||||
|
}
|
||||||
|
@ -7,10 +7,10 @@
|
|||||||
#include "scene/irda-app-scene.hpp"
|
#include "scene/irda-app-scene.hpp"
|
||||||
#include "irda-app-view-manager.hpp"
|
#include "irda-app-view-manager.hpp"
|
||||||
#include "irda-app-remote-manager.hpp"
|
#include "irda-app-remote-manager.hpp"
|
||||||
#include "irda-app-transceiver.hpp"
|
|
||||||
#include <forward_list>
|
#include <forward_list>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <notification/notification-messages.h>
|
#include <notification/notification-messages.h>
|
||||||
|
#include <irda_worker.h>
|
||||||
|
|
||||||
|
|
||||||
class IrdaApp {
|
class IrdaApp {
|
||||||
@ -51,11 +51,15 @@ public:
|
|||||||
bool switch_to_previous_scene(uint8_t count = 1);
|
bool switch_to_previous_scene(uint8_t count = 1);
|
||||||
Scene get_previous_scene();
|
Scene get_previous_scene();
|
||||||
IrdaAppViewManager* get_view_manager();
|
IrdaAppViewManager* get_view_manager();
|
||||||
IrdaAppSignalTransceiver* get_transceiver();
|
|
||||||
void set_text_store(uint8_t index, const char* text...);
|
void set_text_store(uint8_t index, const char* text...);
|
||||||
char* get_text_store(uint8_t index);
|
char* get_text_store(uint8_t index);
|
||||||
uint8_t get_text_store_size();
|
uint8_t get_text_store_size();
|
||||||
IrdaAppRemoteManager* get_remote_manager();
|
IrdaAppRemoteManager* get_remote_manager();
|
||||||
|
|
||||||
|
IrdaWorker* get_irda_worker();
|
||||||
|
const IrdaAppSignal& get_received_signal() const;
|
||||||
|
void set_received_signal(const IrdaAppSignal& signal);
|
||||||
|
|
||||||
void search_and_switch_to_previous_scene(const std::initializer_list<Scene>& scenes_list);
|
void search_and_switch_to_previous_scene(const std::initializer_list<Scene>& scenes_list);
|
||||||
|
|
||||||
void set_edit_element(EditElement value);
|
void set_edit_element(EditElement value);
|
||||||
@ -87,8 +91,10 @@ public:
|
|||||||
|
|
||||||
IrdaApp() {
|
IrdaApp() {
|
||||||
notification = static_cast<NotificationApp*>(furi_record_open("notification"));
|
notification = static_cast<NotificationApp*>(furi_record_open("notification"));
|
||||||
|
irda_worker = irda_worker_alloc();
|
||||||
}
|
}
|
||||||
~IrdaApp() {
|
~IrdaApp() {
|
||||||
|
irda_worker_free(irda_worker);
|
||||||
furi_record_close("notification");
|
furi_record_close("notification");
|
||||||
for (auto &it : scenes)
|
for (auto &it : scenes)
|
||||||
delete it.second;
|
delete it.second;
|
||||||
@ -103,9 +109,10 @@ private:
|
|||||||
uint32_t current_button;
|
uint32_t current_button;
|
||||||
|
|
||||||
NotificationApp* notification;
|
NotificationApp* notification;
|
||||||
IrdaAppSignalTransceiver transceiver;
|
|
||||||
IrdaAppViewManager view_manager;
|
IrdaAppViewManager view_manager;
|
||||||
IrdaAppRemoteManager remote_manager;
|
IrdaAppRemoteManager remote_manager;
|
||||||
|
IrdaWorker* irda_worker;
|
||||||
|
IrdaAppSignal received_signal;
|
||||||
|
|
||||||
std::forward_list<Scene> previous_scenes_list;
|
std::forward_list<Scene> previous_scenes_list;
|
||||||
Scene current_scene = Scene::Start;
|
Scene current_scene = Scene::Start;
|
||||||
|
@ -1,434 +0,0 @@
|
|||||||
#include <furi.h>
|
|
||||||
#include <api-hal.h>
|
|
||||||
#include <gui/gui.h>
|
|
||||||
#include <input/input.h>
|
|
||||||
#include <cli/cli.h>
|
|
||||||
#include <notification/notification-messages.h>
|
|
||||||
|
|
||||||
#include <api-hal-irda.h>
|
|
||||||
#include "irda.h"
|
|
||||||
|
|
||||||
typedef enum {
|
|
||||||
EventTypeTick,
|
|
||||||
EventTypeKey,
|
|
||||||
EventTypeRX,
|
|
||||||
} EventType;
|
|
||||||
|
|
||||||
typedef IrdaMessage IrDAPacket;
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
union {
|
|
||||||
InputEvent input;
|
|
||||||
IrDAPacket rx;
|
|
||||||
} value;
|
|
||||||
EventType type;
|
|
||||||
} AppEvent;
|
|
||||||
|
|
||||||
//typedef struct {
|
|
||||||
// IrdaProtocol protocol;
|
|
||||||
// uint32_t address;
|
|
||||||
// uint32_t command;
|
|
||||||
//} IrDAPacket;
|
|
||||||
|
|
||||||
#define IRDA_PACKET_COUNT 8
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
osMessageQueueId_t cli_ir_rx_queue;
|
|
||||||
Cli* cli;
|
|
||||||
bool cli_cmd_is_active;
|
|
||||||
} IrDAApp;
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
uint8_t mode_id;
|
|
||||||
uint16_t carrier_freq;
|
|
||||||
uint8_t carrier_duty_cycle_id;
|
|
||||||
|
|
||||||
uint8_t packet_id;
|
|
||||||
IrDAPacket packets[IRDA_PACKET_COUNT];
|
|
||||||
} State;
|
|
||||||
|
|
||||||
typedef void (*ModeInput)(AppEvent*, State*);
|
|
||||||
typedef void (*ModeRender)(Canvas*, State*);
|
|
||||||
|
|
||||||
void input_carrier(AppEvent* event, State* state);
|
|
||||||
void render_carrier(Canvas* canvas, State* state);
|
|
||||||
void input_packet(AppEvent* event, State* state);
|
|
||||||
void render_packet(Canvas* canvas, State* state);
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
ModeRender render;
|
|
||||||
ModeInput input;
|
|
||||||
} Mode;
|
|
||||||
|
|
||||||
const Mode modes[] = {
|
|
||||||
{.render = render_carrier, .input = input_carrier},
|
|
||||||
{.render = render_packet, .input = input_packet},
|
|
||||||
};
|
|
||||||
|
|
||||||
const float duty_cycles[] = {0.1, 0.25, 0.333, 0.5, 1.0};
|
|
||||||
|
|
||||||
void render_carrier(Canvas* canvas, State* state) {
|
|
||||||
canvas_set_font(canvas, FontSecondary);
|
|
||||||
canvas_draw_str(canvas, 2, 25, "carrier mode >");
|
|
||||||
canvas_draw_str(canvas, 2, 37, "? /\\ freq | \\/ duty cycle");
|
|
||||||
{
|
|
||||||
char buf[24];
|
|
||||||
sprintf(buf, "frequency: %u Hz", state->carrier_freq);
|
|
||||||
canvas_draw_str(canvas, 2, 50, buf);
|
|
||||||
sprintf(
|
|
||||||
buf, "duty cycle: %d/1000", (int)(duty_cycles[state->carrier_duty_cycle_id] * 1000));
|
|
||||||
canvas_draw_str(canvas, 2, 62, buf);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void input_carrier(AppEvent* event, State* state) {
|
|
||||||
if(event->value.input.key == InputKeyOk) {
|
|
||||||
if(event->value.input.type == InputTypePress) {
|
|
||||||
api_hal_irda_pwm_set(duty_cycles[state->carrier_duty_cycle_id], state->carrier_freq);
|
|
||||||
} else if(event->value.input.type == InputTypeRelease) {
|
|
||||||
api_hal_irda_pwm_stop();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if(event->value.input.type == InputTypeShort && event->value.input.key == InputKeyUp) {
|
|
||||||
if(state->carrier_freq < 45000) {
|
|
||||||
state->carrier_freq += 1000;
|
|
||||||
} else {
|
|
||||||
state->carrier_freq = 33000;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if(event->value.input.type == InputTypeShort && event->value.input.key == InputKeyDown) {
|
|
||||||
uint8_t duty_cycles_count = sizeof(duty_cycles) / sizeof(duty_cycles[0]);
|
|
||||||
if(state->carrier_duty_cycle_id < (duty_cycles_count - 1)) {
|
|
||||||
state->carrier_duty_cycle_id++;
|
|
||||||
} else {
|
|
||||||
state->carrier_duty_cycle_id = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void render_packet(Canvas* canvas, State* state) {
|
|
||||||
canvas_set_font(canvas, FontSecondary);
|
|
||||||
canvas_draw_str(canvas, 2, 25, "< packet mode");
|
|
||||||
canvas_draw_str(canvas, 2, 37, "? /\\ \\/ packet");
|
|
||||||
{
|
|
||||||
char buf[30];
|
|
||||||
sprintf(
|
|
||||||
buf,
|
|
||||||
"P[%d]: %s 0x%lX 0x%lX",
|
|
||||||
state->packet_id,
|
|
||||||
irda_get_protocol_name(state->packets[state->packet_id].protocol),
|
|
||||||
state->packets[state->packet_id].address,
|
|
||||||
state->packets[state->packet_id].command);
|
|
||||||
canvas_draw_str(canvas, 2, 50, buf);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void input_packet(AppEvent* event, State* state) {
|
|
||||||
if(event->value.input.key == InputKeyOk) {
|
|
||||||
if(event->value.input.type == InputTypeShort) {
|
|
||||||
IrdaMessage message = {
|
|
||||||
.protocol = state->packets[state->packet_id].protocol,
|
|
||||||
.address = state->packets[state->packet_id].address,
|
|
||||||
.command = state->packets[state->packet_id].command,
|
|
||||||
};
|
|
||||||
irda_send(&message, 1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if(event->value.input.type == InputTypeShort && event->value.input.key == InputKeyDown) {
|
|
||||||
if(state->packet_id < (IRDA_PACKET_COUNT - 1)) {
|
|
||||||
state->packet_id++;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
if(event->value.input.type == InputTypeShort && event->value.input.key == InputKeyUp) {
|
|
||||||
if(state->packet_id > 0) {
|
|
||||||
state->packet_id--;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void render_callback(Canvas* canvas, void* ctx) {
|
|
||||||
State* state = (State*)acquire_mutex((ValueMutex*)ctx, 25);
|
|
||||||
|
|
||||||
if(state != NULL) {
|
|
||||||
canvas_clear(canvas);
|
|
||||||
canvas_set_color(canvas, ColorBlack);
|
|
||||||
canvas_set_font(canvas, FontPrimary);
|
|
||||||
canvas_draw_str(canvas, 2, 12, "irda test");
|
|
||||||
|
|
||||||
modes[state->mode_id].render(canvas, state);
|
|
||||||
|
|
||||||
release_mutex((ValueMutex*)ctx, state);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void input_callback(InputEvent* input_event, void* ctx) {
|
|
||||||
osMessageQueueId_t event_queue = ctx;
|
|
||||||
|
|
||||||
AppEvent event;
|
|
||||||
event.type = EventTypeKey;
|
|
||||||
event.value.input = *input_event;
|
|
||||||
osMessageQueuePut(event_queue, &event, 0, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
void init_packet(
|
|
||||||
State* state,
|
|
||||||
uint8_t index,
|
|
||||||
IrdaProtocol protocol,
|
|
||||||
uint32_t address,
|
|
||||||
uint32_t command) {
|
|
||||||
if(index >= IRDA_PACKET_COUNT) return;
|
|
||||||
state->packets[index].protocol = protocol;
|
|
||||||
state->packets[index].address = address;
|
|
||||||
state->packets[index].command = command;
|
|
||||||
}
|
|
||||||
|
|
||||||
void irda_cli_cmd_rx(Cli* cli, string_t args, void* context) {
|
|
||||||
furi_assert(context);
|
|
||||||
IrDAPacket packet;
|
|
||||||
IrDAApp* app = context;
|
|
||||||
app->cli_cmd_is_active = true;
|
|
||||||
bool exit = false;
|
|
||||||
|
|
||||||
printf("Reading income packets...\r\nPress Ctrl+C to abort\r\n");
|
|
||||||
while(!exit) {
|
|
||||||
exit = cli_cmd_interrupt_received(app->cli);
|
|
||||||
osStatus status = osMessageQueueGet(app->cli_ir_rx_queue, &packet, 0, 5);
|
|
||||||
if(status == osOK) {
|
|
||||||
printf(
|
|
||||||
"%s "
|
|
||||||
"Address:0x%02X Command: 0x%02X %s\r\n",
|
|
||||||
irda_get_protocol_name(packet.protocol),
|
|
||||||
(uint8_t)packet.address,
|
|
||||||
(uint8_t)packet.command,
|
|
||||||
packet.repeat ? "R" : "");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
printf("Interrupt command received");
|
|
||||||
app->cli_cmd_is_active = false;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
void irda_cli_cmd_tx(Cli* cli, string_t args, void* context) {
|
|
||||||
furi_assert(context);
|
|
||||||
ValueMutex* state_mutex = context;
|
|
||||||
// Read protocol name
|
|
||||||
IrdaProtocol protocol;
|
|
||||||
string_t protocol_str;
|
|
||||||
string_init(protocol_str);
|
|
||||||
size_t ws = string_search_char(args, ' ');
|
|
||||||
if(ws == STRING_FAILURE) {
|
|
||||||
printf("Invalid input. Use ir_tx PROTOCOL ADDRESS COMMAND");
|
|
||||||
string_clear(protocol_str);
|
|
||||||
return;
|
|
||||||
} else {
|
|
||||||
string_set_n(protocol_str, args, 0, ws);
|
|
||||||
string_right(args, ws);
|
|
||||||
string_strim(args);
|
|
||||||
}
|
|
||||||
if(!string_cmp_str(protocol_str, "NEC")) {
|
|
||||||
protocol = IrdaProtocolNEC;
|
|
||||||
} else if(!string_cmp_str(protocol_str, "SAMSUNG")) {
|
|
||||||
protocol = IrdaProtocolSamsung32;
|
|
||||||
} else {
|
|
||||||
printf("Incorrect protocol. Valid protocols: `NEC`, `SAMSUNG`");
|
|
||||||
string_clear(protocol_str);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
string_clear(protocol_str);
|
|
||||||
// Read address
|
|
||||||
uint16_t address = strtoul(string_get_cstr(args), NULL, 16);
|
|
||||||
ws = string_search_char(args, ' ');
|
|
||||||
if(!(ws == 4 || ws == 6)) {
|
|
||||||
printf("Invalid address format. Use 4 [0-F] hex digits in 0xXXXX or XXXX formats");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
string_right(args, ws);
|
|
||||||
string_strim(args);
|
|
||||||
// Read command
|
|
||||||
uint16_t command = strtoul(string_get_cstr(args), NULL, 16);
|
|
||||||
ws = string_search_char(args, '\0');
|
|
||||||
if(!(ws == 4 || ws == 6)) {
|
|
||||||
printf("Invalid command format. Use 4 [0-F] hex digits in 0xXXXX or XXXX formats");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
State* state = (State*)acquire_mutex(state_mutex, 25);
|
|
||||||
if(state == NULL) {
|
|
||||||
printf("IRDA resources busy\r\n");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
IrdaMessage message = {
|
|
||||||
.protocol = protocol,
|
|
||||||
.address = address,
|
|
||||||
.command = command,
|
|
||||||
};
|
|
||||||
irda_send(&message, 1);
|
|
||||||
release_mutex(state_mutex, state);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
osMessageQueueId_t event_queue;
|
|
||||||
IrdaDecoderHandler* handler;
|
|
||||||
} IsrContext;
|
|
||||||
|
|
||||||
void irda_rx_callback(void* ctx, bool level, uint32_t duration) {
|
|
||||||
IsrContext* isr_context = ctx;
|
|
||||||
const IrdaMessage* message = irda_decode(isr_context->handler, level, duration);
|
|
||||||
AppEvent event;
|
|
||||||
event.type = EventTypeRX;
|
|
||||||
|
|
||||||
if(message) {
|
|
||||||
event.value.rx = *message;
|
|
||||||
furi_check(osMessageQueuePut(isr_context->event_queue, &event, 0, 0) == osOK);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
int32_t irda2(void* p) {
|
|
||||||
osMessageQueueId_t event_queue = osMessageQueueNew(32, sizeof(AppEvent), NULL);
|
|
||||||
|
|
||||||
State _state;
|
|
||||||
uint8_t mode_count = sizeof(modes) / sizeof(modes[0]);
|
|
||||||
uint8_t duty_cycles_count = sizeof(duty_cycles) / sizeof(duty_cycles[0]);
|
|
||||||
|
|
||||||
_state.carrier_duty_cycle_id = duty_cycles_count - 2;
|
|
||||||
_state.carrier_freq = 36000;
|
|
||||||
_state.mode_id = 0;
|
|
||||||
_state.packet_id = 0;
|
|
||||||
|
|
||||||
IrDAApp irda_app;
|
|
||||||
irda_app.cli = furi_record_open("cli");
|
|
||||||
irda_app.cli_ir_rx_queue = osMessageQueueNew(1, sizeof(IrDAPacket), NULL);
|
|
||||||
irda_app.cli_cmd_is_active = false;
|
|
||||||
|
|
||||||
NotificationApp* notification = furi_record_open("notification");
|
|
||||||
|
|
||||||
for(uint8_t i = 0; i < IRDA_PACKET_COUNT; i++) {
|
|
||||||
init_packet(&_state, i, 0, 0, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
init_packet(&_state, 0, IrdaProtocolNEC, 0x00, 0x11);
|
|
||||||
init_packet(&_state, 1, IrdaProtocolNEC, 0x08, 0x59);
|
|
||||||
init_packet(&_state, 2, IrdaProtocolNEC, 0x00, 0x10);
|
|
||||||
init_packet(&_state, 3, IrdaProtocolNEC, 0x00, 0x15);
|
|
||||||
init_packet(&_state, 4, IrdaProtocolNEC, 0x00, 0x25);
|
|
||||||
init_packet(&_state, 5, IrdaProtocolSamsung32, 0x0E, 0x0C);
|
|
||||||
init_packet(&_state, 6, IrdaProtocolSamsung32, 0x0E, 0x0D);
|
|
||||||
init_packet(&_state, 7, IrdaProtocolSamsung32, 0x0E, 0x0E);
|
|
||||||
|
|
||||||
ValueMutex state_mutex;
|
|
||||||
if(!init_mutex(&state_mutex, &_state, sizeof(State))) {
|
|
||||||
printf("cannot create mutex\r\n");
|
|
||||||
return 255;
|
|
||||||
}
|
|
||||||
|
|
||||||
ViewPort* view_port = view_port_alloc();
|
|
||||||
|
|
||||||
view_port_draw_callback_set(view_port, render_callback, &state_mutex);
|
|
||||||
view_port_input_callback_set(view_port, input_callback, event_queue);
|
|
||||||
|
|
||||||
cli_add_command(irda_app.cli, "ir_rx", irda_cli_cmd_rx, &irda_app);
|
|
||||||
cli_add_command(irda_app.cli, "ir_tx", irda_cli_cmd_tx, &state_mutex);
|
|
||||||
|
|
||||||
// Open GUI and register view_port
|
|
||||||
Gui* gui = furi_record_open("gui");
|
|
||||||
gui_add_view_port(gui, view_port, GuiLayerFullscreen);
|
|
||||||
|
|
||||||
IsrContext isr_context = {
|
|
||||||
.handler = irda_alloc_decoder(),
|
|
||||||
.event_queue = event_queue,
|
|
||||||
};
|
|
||||||
api_hal_irda_rx_irq_init();
|
|
||||||
api_hal_irda_rx_irq_set_callback(irda_rx_callback, &isr_context);
|
|
||||||
|
|
||||||
AppEvent event;
|
|
||||||
while(1) {
|
|
||||||
osStatus_t event_status = osMessageQueueGet(event_queue, &event, NULL, 500);
|
|
||||||
|
|
||||||
if(event_status == osOK) {
|
|
||||||
if(event.type == EventTypeKey) {
|
|
||||||
State* state = (State*)acquire_mutex_block(&state_mutex);
|
|
||||||
|
|
||||||
// press events
|
|
||||||
if(event.value.input.type == InputTypeShort &&
|
|
||||||
event.value.input.key == InputKeyBack) {
|
|
||||||
release_mutex(&state_mutex, state);
|
|
||||||
|
|
||||||
// remove all view_ports create by app
|
|
||||||
gui_remove_view_port(gui, view_port);
|
|
||||||
view_port_free(view_port);
|
|
||||||
|
|
||||||
// free decoder
|
|
||||||
delete_mutex(&state_mutex);
|
|
||||||
osMessageQueueDelete(event_queue);
|
|
||||||
osMessageQueueDelete(irda_app.cli_ir_rx_queue);
|
|
||||||
cli_delete_command(irda_app.cli, "ir_rx");
|
|
||||||
cli_delete_command(irda_app.cli, "ir_tx");
|
|
||||||
furi_record_close("cli");
|
|
||||||
furi_record_close("notification");
|
|
||||||
api_hal_irda_rx_irq_deinit();
|
|
||||||
irda_free_decoder(isr_context.handler);
|
|
||||||
|
|
||||||
// exit
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(event.value.input.type == InputTypeShort &&
|
|
||||||
event.value.input.key == InputKeyLeft) {
|
|
||||||
if(state->mode_id > 0) {
|
|
||||||
state->mode_id--;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if(event.value.input.type == InputTypeShort &&
|
|
||||||
event.value.input.key == InputKeyRight) {
|
|
||||||
if(state->mode_id < (mode_count - 1)) {
|
|
||||||
state->mode_id++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
modes[state->mode_id].input(&event, state);
|
|
||||||
|
|
||||||
release_mutex(&state_mutex, state);
|
|
||||||
view_port_update(view_port);
|
|
||||||
|
|
||||||
} else if(event.type == EventTypeRX) {
|
|
||||||
notification_message(notification, &sequence_blink_red_10);
|
|
||||||
|
|
||||||
// save only if we in packet mode
|
|
||||||
State* state = (State*)acquire_mutex_block(&state_mutex);
|
|
||||||
IrDAPacket packet = event.value.rx;
|
|
||||||
|
|
||||||
if(state->mode_id == 1) {
|
|
||||||
printf("P=%s ", irda_get_protocol_name(packet.protocol));
|
|
||||||
printf("A=0x%02lX ", packet.address);
|
|
||||||
printf("C=0x%02lX ", packet.command);
|
|
||||||
if(packet.repeat) {
|
|
||||||
printf("R");
|
|
||||||
}
|
|
||||||
printf("\r\n");
|
|
||||||
// Save packet to state
|
|
||||||
memcpy(&(state->packets[state->packet_id]), &packet, sizeof(IrDAPacket));
|
|
||||||
}
|
|
||||||
if(irda_app.cli_cmd_is_active) {
|
|
||||||
// Send decoded packet to cli
|
|
||||||
osMessageQueuePut(irda_app.cli_ir_rx_queue, &packet, 0, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
release_mutex(&state_mutex, state);
|
|
||||||
view_port_update(view_port);
|
|
||||||
|
|
||||||
// blink anyway
|
|
||||||
notification_message(notification, &sequence_blink_green_10);
|
|
||||||
}
|
|
||||||
|
|
||||||
} else {
|
|
||||||
// event timeout
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -20,8 +20,10 @@ void IrdaAppSceneEditDelete::on_enter(IrdaApp* app) {
|
|||||||
auto remote_manager = app->get_remote_manager();
|
auto remote_manager = app->get_remote_manager();
|
||||||
|
|
||||||
if(app->get_edit_element() == IrdaApp::EditElement::Button) {
|
if(app->get_edit_element() == IrdaApp::EditElement::Button) {
|
||||||
auto message = remote_manager->get_button_data(app->get_current_button());
|
auto signal = remote_manager->get_button_data(app->get_current_button());
|
||||||
dialog_ex_set_header(dialog_ex, "Delete button?", 64, 6, AlignCenter, AlignCenter);
|
dialog_ex_set_header(dialog_ex, "Delete button?", 64, 6, AlignCenter, AlignCenter);
|
||||||
|
if(!signal.is_raw()) {
|
||||||
|
auto message = &signal.get_message();
|
||||||
app->set_text_store(
|
app->set_text_store(
|
||||||
0,
|
0,
|
||||||
"%s\n%s\nA=0x%0*lX C=0x%0*lX",
|
"%s\n%s\nA=0x%0*lX C=0x%0*lX",
|
||||||
@ -31,6 +33,13 @@ void IrdaAppSceneEditDelete::on_enter(IrdaApp* app) {
|
|||||||
message->address,
|
message->address,
|
||||||
irda_get_protocol_command_length(message->protocol),
|
irda_get_protocol_command_length(message->protocol),
|
||||||
message->command);
|
message->command);
|
||||||
|
} else {
|
||||||
|
app->set_text_store(
|
||||||
|
0,
|
||||||
|
"%s\nRAW\n%ld samples",
|
||||||
|
remote_manager->get_button_name(app->get_current_button()).c_str(),
|
||||||
|
signal.get_raw_signal().timings_cnt);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
dialog_ex_set_header(dialog_ex, "Delete remote?", 64, 6, AlignCenter, AlignCenter);
|
dialog_ex_set_header(dialog_ex, "Delete remote?", 64, 6, AlignCenter, AlignCenter);
|
||||||
app->set_text_store(
|
app->set_text_store(
|
||||||
|
@ -5,15 +5,20 @@ void IrdaAppSceneLearnEnterName::on_enter(IrdaApp* app) {
|
|||||||
IrdaAppViewManager* view_manager = app->get_view_manager();
|
IrdaAppViewManager* view_manager = app->get_view_manager();
|
||||||
TextInput* text_input = view_manager->get_text_input();
|
TextInput* text_input = view_manager->get_text_input();
|
||||||
|
|
||||||
auto transceiver = app->get_transceiver();
|
auto signal = app->get_received_signal();
|
||||||
auto message = transceiver->get_last_message();
|
|
||||||
|
|
||||||
|
if(!signal.is_raw()) {
|
||||||
|
auto message = &signal.get_message();
|
||||||
app->set_text_store(
|
app->set_text_store(
|
||||||
0,
|
0,
|
||||||
"%.4s_%0*lX",
|
"%.4s_%0*lX",
|
||||||
irda_get_protocol_name(message->protocol),
|
irda_get_protocol_name(message->protocol),
|
||||||
irda_get_protocol_command_length(message->protocol),
|
irda_get_protocol_command_length(message->protocol),
|
||||||
message->command);
|
message->command);
|
||||||
|
} else {
|
||||||
|
auto raw_signal = signal.get_raw_signal();
|
||||||
|
app->set_text_store(0, "RAW_%d", raw_signal.timings_cnt);
|
||||||
|
}
|
||||||
|
|
||||||
text_input_set_header_text(text_input, "Name the key");
|
text_input_set_header_text(text_input, "Name the key");
|
||||||
text_input_set_result_callback(
|
text_input_set_result_callback(
|
||||||
@ -31,14 +36,13 @@ bool IrdaAppSceneLearnEnterName::on_event(IrdaApp* app, IrdaAppEvent* event) {
|
|||||||
|
|
||||||
if(event->type == IrdaAppEvent::Type::TextEditDone) {
|
if(event->type == IrdaAppEvent::Type::TextEditDone) {
|
||||||
auto remote_manager = app->get_remote_manager();
|
auto remote_manager = app->get_remote_manager();
|
||||||
auto transceiver = app->get_transceiver();
|
|
||||||
bool result = false;
|
bool result = false;
|
||||||
if(app->get_learn_new_remote()) {
|
if(app->get_learn_new_remote()) {
|
||||||
result = remote_manager->add_remote_with_button(
|
result = remote_manager->add_remote_with_button(
|
||||||
app->get_text_store(0), transceiver->get_last_message());
|
app->get_text_store(0), app->get_received_signal());
|
||||||
} else {
|
} else {
|
||||||
result = remote_manager->add_button(
|
result =
|
||||||
app->get_text_store(0), transceiver->get_last_message());
|
remote_manager->add_button(app->get_text_store(0), app->get_received_signal());
|
||||||
}
|
}
|
||||||
|
|
||||||
if(!result) {
|
if(!result) {
|
||||||
|
@ -17,9 +17,10 @@ void IrdaAppSceneLearnSuccess::on_enter(IrdaApp* app) {
|
|||||||
|
|
||||||
app->notify_green_on();
|
app->notify_green_on();
|
||||||
|
|
||||||
auto transceiver = app->get_transceiver();
|
auto signal = app->get_received_signal();
|
||||||
auto message = transceiver->get_last_message();
|
|
||||||
|
|
||||||
|
if(!signal.is_raw()) {
|
||||||
|
auto message = &signal.get_message();
|
||||||
app->set_text_store(0, "%s", irda_get_protocol_name(message->protocol));
|
app->set_text_store(0, "%s", irda_get_protocol_name(message->protocol));
|
||||||
app->set_text_store(
|
app->set_text_store(
|
||||||
1,
|
1,
|
||||||
@ -30,6 +31,12 @@ void IrdaAppSceneLearnSuccess::on_enter(IrdaApp* app) {
|
|||||||
message->command);
|
message->command);
|
||||||
dialog_ex_set_header(dialog_ex, app->get_text_store(0), 95, 10, AlignCenter, AlignCenter);
|
dialog_ex_set_header(dialog_ex, app->get_text_store(0), 95, 10, AlignCenter, AlignCenter);
|
||||||
dialog_ex_set_text(dialog_ex, app->get_text_store(1), 75, 23, AlignLeft, AlignTop);
|
dialog_ex_set_text(dialog_ex, app->get_text_store(1), 75, 23, AlignLeft, AlignTop);
|
||||||
|
} else {
|
||||||
|
dialog_ex_set_header(dialog_ex, "Unknown", 95, 10, AlignCenter, AlignCenter);
|
||||||
|
app->set_text_store(0, "%d samples", signal.get_raw_signal().timings_cnt);
|
||||||
|
dialog_ex_set_text(dialog_ex, app->get_text_store(0), 75, 23, AlignLeft, AlignTop);
|
||||||
|
}
|
||||||
|
|
||||||
dialog_ex_set_left_button_text(dialog_ex, "Retry");
|
dialog_ex_set_left_button_text(dialog_ex, "Retry");
|
||||||
dialog_ex_set_right_button_text(dialog_ex, "Save");
|
dialog_ex_set_right_button_text(dialog_ex, "Save");
|
||||||
dialog_ex_set_center_button_text(dialog_ex, "Send");
|
dialog_ex_set_center_button_text(dialog_ex, "Send");
|
||||||
@ -50,9 +57,8 @@ bool IrdaAppSceneLearnSuccess::on_event(IrdaApp* app, IrdaAppEvent* event) {
|
|||||||
break;
|
break;
|
||||||
case DialogExResultCenter: {
|
case DialogExResultCenter: {
|
||||||
app->notify_space_blink();
|
app->notify_space_blink();
|
||||||
auto transceiver = app->get_transceiver();
|
auto signal = app->get_received_signal();
|
||||||
auto message = transceiver->get_last_message();
|
signal.transmit();
|
||||||
irda_send(message, 1);
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case DialogExResultRight:
|
case DialogExResultRight:
|
||||||
|
@ -1,14 +1,40 @@
|
|||||||
#include "../irda-app.hpp"
|
#include "../irda-app.hpp"
|
||||||
|
#include "../irda-app-event.hpp"
|
||||||
|
#include <irda_worker.h>
|
||||||
|
|
||||||
|
static void signal_received_callback(void* context, IrdaWorkerSignal* received_signal) {
|
||||||
|
furi_assert(context);
|
||||||
|
furi_assert(received_signal);
|
||||||
|
|
||||||
|
IrdaApp* app = static_cast<IrdaApp*>(context);
|
||||||
|
|
||||||
|
if(irda_worker_signal_is_decoded(received_signal)) {
|
||||||
|
IrdaAppSignal signal(irda_worker_get_decoded_message(received_signal));
|
||||||
|
app->set_received_signal(signal);
|
||||||
|
} else {
|
||||||
|
const uint32_t* timings;
|
||||||
|
size_t timings_cnt;
|
||||||
|
irda_worker_get_raw_signal(received_signal, &timings, &timings_cnt);
|
||||||
|
IrdaAppSignal signal(timings, timings_cnt);
|
||||||
|
app->set_received_signal(signal);
|
||||||
|
}
|
||||||
|
|
||||||
|
irda_worker_set_received_signal_callback(app->get_irda_worker(), NULL);
|
||||||
|
IrdaAppEvent event;
|
||||||
|
event.type = IrdaAppEvent::Type::IrdaMessageReceived;
|
||||||
|
auto view_manager = app->get_view_manager();
|
||||||
|
view_manager->send_event(&event);
|
||||||
|
}
|
||||||
|
|
||||||
void IrdaAppSceneLearn::on_enter(IrdaApp* app) {
|
void IrdaAppSceneLearn::on_enter(IrdaApp* app) {
|
||||||
auto view_manager = app->get_view_manager();
|
auto view_manager = app->get_view_manager();
|
||||||
auto transceiver = app->get_transceiver();
|
|
||||||
auto event_queue = view_manager->get_event_queue();
|
|
||||||
|
|
||||||
transceiver->capture_once_start(event_queue);
|
|
||||||
|
|
||||||
auto popup = view_manager->get_popup();
|
auto popup = view_manager->get_popup();
|
||||||
|
|
||||||
|
auto worker = app->get_irda_worker();
|
||||||
|
irda_worker_set_context(worker, app);
|
||||||
|
irda_worker_set_received_signal_callback(worker, signal_received_callback);
|
||||||
|
irda_worker_start(worker);
|
||||||
|
|
||||||
popup_set_icon(popup, 0, 32, &I_IrdaLearnShort_128x31);
|
popup_set_icon(popup, 0, 32, &I_IrdaLearnShort_128x31);
|
||||||
popup_set_text(
|
popup_set_text(
|
||||||
popup, "Point the remote at IR port\nand push the button", 5, 10, AlignLeft, AlignCenter);
|
popup, "Point the remote at IR port\nand push the button", 5, 10, AlignLeft, AlignCenter);
|
||||||
@ -24,19 +50,27 @@ void IrdaAppSceneLearn::on_enter(IrdaApp* app) {
|
|||||||
bool IrdaAppSceneLearn::on_event(IrdaApp* app, IrdaAppEvent* event) {
|
bool IrdaAppSceneLearn::on_event(IrdaApp* app, IrdaAppEvent* event) {
|
||||||
bool consumed = false;
|
bool consumed = false;
|
||||||
|
|
||||||
if(event->type == IrdaAppEvent::Type::Tick) {
|
switch(event->type) {
|
||||||
|
case IrdaAppEvent::Type::Tick:
|
||||||
consumed = true;
|
consumed = true;
|
||||||
app->notify_red_blink();
|
app->notify_red_blink();
|
||||||
}
|
break;
|
||||||
if(event->type == IrdaAppEvent::Type::IrdaMessageReceived) {
|
case IrdaAppEvent::Type::IrdaMessageReceived:
|
||||||
app->notify_success();
|
app->notify_success();
|
||||||
app->switch_to_next_scene_without_saving(IrdaApp::Scene::LearnSuccess);
|
app->switch_to_next_scene_without_saving(IrdaApp::Scene::LearnSuccess);
|
||||||
|
irda_worker_stop(app->get_irda_worker());
|
||||||
|
break;
|
||||||
|
case IrdaAppEvent::Type::Back:
|
||||||
|
consumed = true;
|
||||||
|
irda_worker_stop(app->get_irda_worker());
|
||||||
|
app->switch_to_previous_scene();
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
furi_assert(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
return consumed;
|
return consumed;
|
||||||
}
|
}
|
||||||
|
|
||||||
void IrdaAppSceneLearn::on_exit(IrdaApp* app) {
|
void IrdaAppSceneLearn::on_exit(IrdaApp* app) {
|
||||||
auto transceiver = app->get_transceiver();
|
|
||||||
transceiver->capture_stop();
|
|
||||||
}
|
}
|
||||||
|
@ -64,8 +64,8 @@ bool IrdaAppSceneRemote::on_event(IrdaApp* app, IrdaAppEvent* event) {
|
|||||||
default:
|
default:
|
||||||
app->notify_click_and_blink();
|
app->notify_click_and_blink();
|
||||||
auto remote_manager = app->get_remote_manager();
|
auto remote_manager = app->get_remote_manager();
|
||||||
auto message = remote_manager->get_button_data(event->payload.menu_index);
|
auto signal = remote_manager->get_button_data(event->payload.menu_index);
|
||||||
app->get_transceiver()->send_message(message);
|
signal.transmit();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
} else if(event->type == IrdaAppEvent::Type::Back) {
|
} else if(event->type == IrdaAppEvent::Type::Back) {
|
||||||
|
@ -63,7 +63,7 @@ bool IrdaAppSceneUniversalCommon::on_event(IrdaApp* app, IrdaAppEvent* event) {
|
|||||||
auto view_manager = app->get_view_manager();
|
auto view_manager = app->get_view_manager();
|
||||||
IrdaAppEvent tick_event = {.type = IrdaAppEvent::Type::Tick};
|
IrdaAppEvent tick_event = {.type = IrdaAppEvent::Type::Tick};
|
||||||
view_manager->send_event(&tick_event);
|
view_manager->send_event(&tick_event);
|
||||||
if(brute_force.send_next_bruteforce(*app->get_transceiver())) {
|
if(brute_force.send_next_bruteforce()) {
|
||||||
progress_popup(app);
|
progress_popup(app);
|
||||||
} else {
|
} else {
|
||||||
brute_force.stop_bruteforce();
|
brute_force.stop_bruteforce();
|
||||||
|
@ -1,10 +1,11 @@
|
|||||||
#include "gui/canvas.h"
|
#include <gui/canvas.h>
|
||||||
#include "irda.h"
|
#include <input/input.h>
|
||||||
|
#include <irda.h>
|
||||||
|
#include <irda_worker.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <furi.h>
|
#include <furi.h>
|
||||||
#include <api-hal-irda.h>
|
#include <api-hal-irda.h>
|
||||||
#include <api-hal.h>
|
#include <api-hal.h>
|
||||||
#include <notification/notification-messages.h>
|
|
||||||
#include <gui/view_port.h>
|
#include <gui/view_port.h>
|
||||||
#include <gui/gui.h>
|
#include <gui/gui.h>
|
||||||
#include <gui/elements.h>
|
#include <gui/elements.h>
|
||||||
@ -20,25 +21,13 @@ typedef struct {
|
|||||||
} IrdaDelaysArray;
|
} IrdaDelaysArray;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
IrdaDecoderHandler* handler;
|
|
||||||
char display_text[64];
|
char display_text[64];
|
||||||
osMessageQueueId_t event_queue;
|
osMessageQueueId_t event_queue;
|
||||||
IrdaDelaysArray delays;
|
IrdaDelaysArray delays;
|
||||||
|
IrdaWorker* worker;
|
||||||
|
ViewPort* view_port;
|
||||||
} IrdaMonitor;
|
} IrdaMonitor;
|
||||||
|
|
||||||
static void irda_rx_callback(void* ctx, bool level, uint32_t duration) {
|
|
||||||
IrdaMonitor* irda_monitor = (IrdaMonitor*)ctx;
|
|
||||||
IrdaDelaysArray* delays = &irda_monitor->delays;
|
|
||||||
|
|
||||||
if(delays->timing_cnt > 1) furi_assert(level != delays->timing[delays->timing_cnt - 1].level);
|
|
||||||
delays->timing[delays->timing_cnt].level = level;
|
|
||||||
delays->timing[delays->timing_cnt].duration = duration;
|
|
||||||
delays->timing_cnt++; // Read-Modify-Write in ISR only: no need to add synchronization
|
|
||||||
if(delays->timing_cnt >= IRDA_TIMINGS_SIZE) {
|
|
||||||
delays->timing_cnt = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void irda_monitor_input_callback(InputEvent* input_event, void* ctx) {
|
void irda_monitor_input_callback(InputEvent* input_event, void* ctx) {
|
||||||
furi_assert(ctx);
|
furi_assert(ctx);
|
||||||
IrdaMonitor* irda_monitor = (IrdaMonitor*)ctx;
|
IrdaMonitor* irda_monitor = (IrdaMonitor*)ctx;
|
||||||
@ -63,50 +52,13 @@ static void irda_monitor_draw_callback(Canvas* canvas, void* ctx) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int32_t irda_monitor_app(void* p) {
|
static void signal_received_callback(void* context, IrdaWorkerSignal* received_signal) {
|
||||||
(void)p;
|
furi_assert(context);
|
||||||
uint32_t counter = 0;
|
furi_assert(received_signal);
|
||||||
uint32_t print_counter = 0;
|
IrdaMonitor* irda_monitor = context;
|
||||||
|
|
||||||
IrdaMonitor* irda_monitor = furi_alloc(sizeof(IrdaMonitor));
|
if(irda_worker_signal_is_decoded(received_signal)) {
|
||||||
irda_monitor->display_text[0] = 0;
|
const IrdaMessage* message = irda_worker_get_decoded_message(received_signal);
|
||||||
irda_monitor->event_queue = osMessageQueueNew(1, sizeof(InputEvent), NULL);
|
|
||||||
ViewPort* view_port = view_port_alloc();
|
|
||||||
IrdaDelaysArray* delays = &irda_monitor->delays;
|
|
||||||
NotificationApp* notification = furi_record_open("notification");
|
|
||||||
Gui* gui = furi_record_open("gui");
|
|
||||||
|
|
||||||
view_port_draw_callback_set(view_port, irda_monitor_draw_callback, irda_monitor);
|
|
||||||
view_port_input_callback_set(view_port, irda_monitor_input_callback, irda_monitor);
|
|
||||||
|
|
||||||
gui_add_view_port(gui, view_port, GuiLayerFullscreen);
|
|
||||||
|
|
||||||
api_hal_irda_rx_irq_init();
|
|
||||||
api_hal_irda_rx_irq_set_callback(irda_rx_callback, irda_monitor);
|
|
||||||
irda_monitor->handler = irda_alloc_decoder();
|
|
||||||
|
|
||||||
while(1) {
|
|
||||||
InputEvent event;
|
|
||||||
if(osOK == osMessageQueueGet(irda_monitor->event_queue, &event, NULL, 50)) {
|
|
||||||
if((event.type == InputTypeShort) && (event.key == InputKeyBack)) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if(counter != delays->timing_cnt) {
|
|
||||||
notification_message(notification, &sequence_blink_blue_10);
|
|
||||||
}
|
|
||||||
|
|
||||||
for(; counter != delays->timing_cnt;) {
|
|
||||||
const IrdaMessage* message = irda_decode(
|
|
||||||
irda_monitor->handler,
|
|
||||||
delays->timing[counter].level,
|
|
||||||
delays->timing[counter].duration);
|
|
||||||
|
|
||||||
++counter;
|
|
||||||
if(counter >= IRDA_TIMINGS_SIZE) counter = 0;
|
|
||||||
|
|
||||||
if(message) {
|
|
||||||
snprintf(
|
snprintf(
|
||||||
irda_monitor->display_text,
|
irda_monitor->display_text,
|
||||||
sizeof(irda_monitor->display_text),
|
sizeof(irda_monitor->display_text),
|
||||||
@ -117,14 +69,7 @@ int32_t irda_monitor_app(void* p) {
|
|||||||
irda_get_protocol_command_length(message->protocol),
|
irda_get_protocol_command_length(message->protocol),
|
||||||
message->command,
|
message->command,
|
||||||
message->repeat ? " R" : "");
|
message->repeat ? " R" : "");
|
||||||
view_port_update(view_port);
|
view_port_update(irda_monitor->view_port);
|
||||||
}
|
|
||||||
|
|
||||||
size_t distance = (counter > print_counter) ?
|
|
||||||
counter - print_counter :
|
|
||||||
(counter + IRDA_TIMINGS_SIZE) - print_counter;
|
|
||||||
if(message || (distance > (IRDA_TIMINGS_SIZE / 2))) {
|
|
||||||
if(message) {
|
|
||||||
printf(
|
printf(
|
||||||
"== %s, A:0x%0*lX, C:0x%0*lX%s ==\r\n",
|
"== %s, A:0x%0*lX, C:0x%0*lX%s ==\r\n",
|
||||||
irda_get_protocol_name(message->protocol),
|
irda_get_protocol_name(message->protocol),
|
||||||
@ -134,33 +79,59 @@ int32_t irda_monitor_app(void* p) {
|
|||||||
message->command,
|
message->command,
|
||||||
message->repeat ? " R" : "");
|
message->repeat ? " R" : "");
|
||||||
} else {
|
} else {
|
||||||
printf("== unknown data ==\r\n");
|
const uint32_t* timings;
|
||||||
|
size_t timings_cnt;
|
||||||
|
irda_worker_get_raw_signal(received_signal, &timings, &timings_cnt);
|
||||||
snprintf(
|
snprintf(
|
||||||
irda_monitor->display_text,
|
irda_monitor->display_text,
|
||||||
sizeof(irda_monitor->display_text),
|
sizeof(irda_monitor->display_text),
|
||||||
"unknown data");
|
"RAW\n%d samples\n",
|
||||||
view_port_update(view_port);
|
timings_cnt);
|
||||||
|
view_port_update(irda_monitor->view_port);
|
||||||
|
printf("RAW, %d samples:\r\n", timings_cnt);
|
||||||
|
for(size_t i = 0; i < timings_cnt; ++i) {
|
||||||
|
printf("%lu ", timings[i]);
|
||||||
}
|
}
|
||||||
printf("{");
|
printf("\r\n");
|
||||||
while(print_counter != counter) {
|
|
||||||
printf("%lu, ", delays->timing[print_counter].duration);
|
|
||||||
++print_counter;
|
|
||||||
if(print_counter >= IRDA_TIMINGS_SIZE) {
|
|
||||||
print_counter = 0;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
printf("\r\n};\r\n");
|
|
||||||
|
int32_t irda_monitor_app(void* p) {
|
||||||
|
(void)p;
|
||||||
|
|
||||||
|
IrdaMonitor* irda_monitor = furi_alloc(sizeof(IrdaMonitor));
|
||||||
|
irda_monitor->display_text[0] = 0;
|
||||||
|
irda_monitor->event_queue = osMessageQueueNew(1, sizeof(InputEvent), NULL);
|
||||||
|
irda_monitor->view_port = view_port_alloc();
|
||||||
|
Gui* gui = furi_record_open("gui");
|
||||||
|
|
||||||
|
view_port_draw_callback_set(irda_monitor->view_port, irda_monitor_draw_callback, irda_monitor);
|
||||||
|
view_port_input_callback_set(
|
||||||
|
irda_monitor->view_port, irda_monitor_input_callback, irda_monitor);
|
||||||
|
|
||||||
|
gui_add_view_port(gui, irda_monitor->view_port, GuiLayerFullscreen);
|
||||||
|
|
||||||
|
irda_monitor->worker = irda_worker_alloc();
|
||||||
|
irda_worker_set_context(irda_monitor->worker, irda_monitor);
|
||||||
|
irda_worker_start(irda_monitor->worker);
|
||||||
|
irda_worker_set_received_signal_callback(irda_monitor->worker, signal_received_callback);
|
||||||
|
irda_worker_enable_blink_on_receiving(irda_monitor->worker, true);
|
||||||
|
|
||||||
|
while(1) {
|
||||||
|
InputEvent event;
|
||||||
|
if(osOK == osMessageQueueGet(irda_monitor->event_queue, &event, NULL, 50)) {
|
||||||
|
if((event.type == InputTypeShort) && (event.key == InputKeyBack)) {
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
api_hal_irda_rx_irq_deinit();
|
irda_worker_stop(irda_monitor->worker);
|
||||||
irda_free_decoder(irda_monitor->handler);
|
irda_worker_free(irda_monitor->worker);
|
||||||
osMessageQueueDelete(irda_monitor->event_queue);
|
osMessageQueueDelete(irda_monitor->event_queue);
|
||||||
view_port_enabled_set(view_port, false);
|
view_port_enabled_set(irda_monitor->view_port, false);
|
||||||
gui_remove_view_port(gui, view_port);
|
gui_remove_view_port(gui, irda_monitor->view_port);
|
||||||
view_port_free(view_port);
|
view_port_free(irda_monitor->view_port);
|
||||||
furi_record_close("notification");
|
|
||||||
furi_record_close("gui");
|
furi_record_close("gui");
|
||||||
free(irda_monitor);
|
free(irda_monitor);
|
||||||
|
|
||||||
|
@ -9,11 +9,18 @@ extern "C" {
|
|||||||
/**
|
/**
|
||||||
* Signature of callback function for receiving continuous IRDA rx signal.
|
* Signature of callback function for receiving continuous IRDA rx signal.
|
||||||
*
|
*
|
||||||
* @param level - level of input IRDA rx signal
|
* @param ctx[in] - context to pass to callback
|
||||||
* @param duration - duration of continuous rx signal level in us
|
* @param level[in] - level of input IRDA rx signal
|
||||||
|
* @param duration[in] - duration of continuous rx signal level in us
|
||||||
*/
|
*/
|
||||||
typedef void (*TimerISRCallback)(void* ctx, bool level, uint32_t duration);
|
typedef void (*ApiHalIrdaCaptureCallback)(void* ctx, bool level, uint32_t duration);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Signature of callback function for reaching silence timeout on IRDA port.
|
||||||
|
*
|
||||||
|
* @param ctx[in] - context to pass to callback
|
||||||
|
*/
|
||||||
|
typedef void (*ApiHalIrdaTimeoutCallback)(void* ctx);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Initialize IRDA RX timer to receive interrupts.
|
* Initialize IRDA RX timer to receive interrupts.
|
||||||
@ -27,20 +34,37 @@ void api_hal_irda_rx_irq_init(void);
|
|||||||
*/
|
*/
|
||||||
void api_hal_irda_rx_irq_deinit(void);
|
void api_hal_irda_rx_irq_deinit(void);
|
||||||
|
|
||||||
|
/** Setup api hal for receiving silence timeout.
|
||||||
|
* Should be used with 'api_hal_irda_timeout_irq_set_callback()'.
|
||||||
|
*
|
||||||
|
* @param[in] timeout_ms - time to wait for silence on IRDA port
|
||||||
|
* before generating IRQ.
|
||||||
|
*/
|
||||||
|
void api_hal_irda_rx_timeout_irq_init(uint32_t timeout_ms);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Setup callback for previously initialized IRDA RX interrupt.
|
* Setup callback for previously initialized IRDA RX interrupt.
|
||||||
*
|
*
|
||||||
* @param callback - callback to call when RX signal edge changing occurs
|
* @param[in] callback - callback to call when RX signal edge changing occurs
|
||||||
* @param ctx - context for callback
|
* @param[in] ctx - context for callback
|
||||||
*/
|
*/
|
||||||
void api_hal_irda_rx_irq_set_callback(TimerISRCallback callback, void *ctx);
|
void api_hal_irda_rx_irq_set_callback(ApiHalIrdaCaptureCallback callback, void *ctx);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Setup callback for reaching silence timeout on IRDA port.
|
||||||
|
* Should setup api hal with 'api_hal_irda_setup_rx_timeout_irq()' first.
|
||||||
|
*
|
||||||
|
* @param[in] callback - callback for silence timeout
|
||||||
|
* @param[in] ctx - context to pass to callback
|
||||||
|
*/
|
||||||
|
void api_hal_irda_rx_timeout_irq_set_callback(ApiHalIrdaTimeoutCallback callback, void *ctx);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Start generating IRDA TX PWM. Provides PWM initialization on
|
* Start generating IRDA TX PWM. Provides PWM initialization on
|
||||||
* defined frequency.
|
* defined frequency.
|
||||||
*
|
*
|
||||||
* @param duty_cycle - duty cycle
|
* @param[in] duty_cycle - duty cycle
|
||||||
* @param freq - PWM frequency to generate
|
* @param[in] freq - PWM frequency to generate
|
||||||
*/
|
*/
|
||||||
void api_hal_irda_pwm_set(float duty_cycle, float freq);
|
void api_hal_irda_pwm_set(float duty_cycle, float freq);
|
||||||
|
|
||||||
|
@ -1,82 +1,58 @@
|
|||||||
#include "cmsis_os.h"
|
|
||||||
#include "api-hal-tim_i.h"
|
|
||||||
#include "api-hal-irda.h"
|
#include "api-hal-irda.h"
|
||||||
|
#include <cmsis_os2.h>
|
||||||
|
#include <api-hal-resources.h>
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
#include <stm32wbxx_ll_tim.h>
|
#include <stm32wbxx_ll_tim.h>
|
||||||
#include <stm32wbxx_ll_gpio.h>
|
#include <stm32wbxx_ll_gpio.h>
|
||||||
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <furi.h>
|
#include <furi.h>
|
||||||
#include "main.h"
|
#include <main.h>
|
||||||
#include "api-hal-pwm.h"
|
#include <api-hal-pwm.h>
|
||||||
|
|
||||||
|
|
||||||
static struct{
|
static struct{
|
||||||
TimerISRCallback callback;
|
ApiHalIrdaCaptureCallback capture_callback;
|
||||||
void *ctx;
|
void *capture_context;
|
||||||
|
ApiHalIrdaTimeoutCallback timeout_callback;
|
||||||
|
void *timeout_context;
|
||||||
} timer_irda;
|
} timer_irda;
|
||||||
|
|
||||||
|
typedef enum{
|
||||||
|
TimerIRQSourceCCI1,
|
||||||
|
TimerIRQSourceCCI2,
|
||||||
|
} TimerIRQSource;
|
||||||
|
|
||||||
void api_hal_irda_tim_isr(TimerIRQSource source)
|
void api_hal_irda_rx_irq_init(void) {
|
||||||
{
|
|
||||||
uint32_t duration = 0;
|
|
||||||
bool level = 0;
|
|
||||||
|
|
||||||
switch (source) {
|
|
||||||
case TimerIRQSourceCCI1:
|
|
||||||
duration = LL_TIM_OC_GetCompareCH1(TIM2);
|
|
||||||
LL_TIM_SetCounter(TIM2, 0);
|
|
||||||
level = 1;
|
|
||||||
break;
|
|
||||||
case TimerIRQSourceCCI2:
|
|
||||||
duration = LL_TIM_OC_GetCompareCH2(TIM2);
|
|
||||||
LL_TIM_SetCounter(TIM2, 0);
|
|
||||||
level = 0;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
furi_check(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (timer_irda.callback)
|
|
||||||
timer_irda.callback(timer_irda.ctx, level, duration);
|
|
||||||
}
|
|
||||||
|
|
||||||
void api_hal_irda_rx_irq_init(void)
|
|
||||||
{
|
|
||||||
LL_TIM_InitTypeDef TIM_InitStruct = {0};
|
|
||||||
|
|
||||||
LL_GPIO_InitTypeDef GPIO_InitStruct = {0};
|
|
||||||
|
|
||||||
/* Peripheral clock enable */
|
|
||||||
LL_APB1_GRP1_EnableClock(LL_APB1_GRP1_PERIPH_TIM2);
|
LL_APB1_GRP1_EnableClock(LL_APB1_GRP1_PERIPH_TIM2);
|
||||||
|
|
||||||
LL_AHB2_GRP1_EnableClock(LL_AHB2_GRP1_PERIPH_GPIOA);
|
LL_AHB2_GRP1_EnableClock(LL_AHB2_GRP1_PERIPH_GPIOA);
|
||||||
/**TIM2 GPIO Configuration
|
|
||||||
PA0 ------> TIM2_CH1
|
|
||||||
*/
|
|
||||||
GPIO_InitStruct.Pin = LL_GPIO_PIN_0;
|
|
||||||
GPIO_InitStruct.Mode = LL_GPIO_MODE_ALTERNATE;
|
|
||||||
GPIO_InitStruct.Speed = LL_GPIO_SPEED_FREQ_LOW;
|
|
||||||
GPIO_InitStruct.OutputType = LL_GPIO_OUTPUT_PUSHPULL;
|
|
||||||
GPIO_InitStruct.Pull = LL_GPIO_PULL_NO;
|
|
||||||
GPIO_InitStruct.Alternate = LL_GPIO_AF_1;
|
|
||||||
LL_GPIO_Init(GPIOA, &GPIO_InitStruct);
|
|
||||||
|
|
||||||
|
hal_gpio_init_ex(&gpio_irda_rx, GpioModeAltFunctionPushPull, GpioPullNo, GpioSpeedLow, GpioAltFn1TIM2);
|
||||||
|
|
||||||
|
LL_TIM_InitTypeDef TIM_InitStruct = {0};
|
||||||
TIM_InitStruct.Prescaler = 64 - 1;
|
TIM_InitStruct.Prescaler = 64 - 1;
|
||||||
TIM_InitStruct.CounterMode = LL_TIM_COUNTERMODE_UP;
|
TIM_InitStruct.CounterMode = LL_TIM_COUNTERMODE_UP;
|
||||||
TIM_InitStruct.Autoreload = 0xFFFFFFFF;
|
TIM_InitStruct.Autoreload = 0x7FFFFFFE;
|
||||||
TIM_InitStruct.ClockDivision = LL_TIM_CLOCKDIVISION_DIV1;
|
TIM_InitStruct.ClockDivision = LL_TIM_CLOCKDIVISION_DIV1;
|
||||||
LL_TIM_Init(TIM2, &TIM_InitStruct);
|
LL_TIM_Init(TIM2, &TIM_InitStruct);
|
||||||
|
|
||||||
LL_TIM_SetClockSource(TIM2, LL_TIM_CLOCKSOURCE_INTERNAL);
|
LL_TIM_SetClockSource(TIM2, LL_TIM_CLOCKSOURCE_INTERNAL);
|
||||||
LL_TIM_EnableARRPreload(TIM2);
|
LL_TIM_DisableARRPreload(TIM2);
|
||||||
|
LL_TIM_SetTriggerInput(TIM2, LL_TIM_TS_TI1FP1);
|
||||||
|
LL_TIM_SetSlaveMode(TIM2, LL_TIM_SLAVEMODE_RESET);
|
||||||
|
LL_TIM_CC_DisableChannel(TIM2, LL_TIM_CHANNEL_CH2);
|
||||||
|
LL_TIM_IC_SetFilter(TIM2, LL_TIM_CHANNEL_CH2, LL_TIM_IC_FILTER_FDIV1);
|
||||||
|
LL_TIM_IC_SetPolarity(TIM2, LL_TIM_CHANNEL_CH2, LL_TIM_IC_POLARITY_FALLING);
|
||||||
|
LL_TIM_DisableIT_TRIG(TIM2);
|
||||||
|
LL_TIM_DisableDMAReq_TRIG(TIM2);
|
||||||
LL_TIM_SetTriggerOutput(TIM2, LL_TIM_TRGO_RESET);
|
LL_TIM_SetTriggerOutput(TIM2, LL_TIM_TRGO_RESET);
|
||||||
LL_TIM_DisableMasterSlaveMode(TIM2);
|
LL_TIM_EnableMasterSlaveMode(TIM2);
|
||||||
LL_TIM_IC_SetActiveInput(TIM2, LL_TIM_CHANNEL_CH1, LL_TIM_ACTIVEINPUT_DIRECTTI);
|
LL_TIM_IC_SetActiveInput(TIM2, LL_TIM_CHANNEL_CH1, LL_TIM_ACTIVEINPUT_DIRECTTI);
|
||||||
LL_TIM_IC_SetPrescaler(TIM2, LL_TIM_CHANNEL_CH1, LL_TIM_ICPSC_DIV1);
|
LL_TIM_IC_SetPrescaler(TIM2, LL_TIM_CHANNEL_CH1, LL_TIM_ICPSC_DIV1);
|
||||||
LL_TIM_IC_SetFilter(TIM2, LL_TIM_CHANNEL_CH1, LL_TIM_IC_FILTER_FDIV1);
|
LL_TIM_IC_SetFilter(TIM2, LL_TIM_CHANNEL_CH1, LL_TIM_IC_FILTER_FDIV1);
|
||||||
LL_TIM_IC_SetPolarity(TIM2, LL_TIM_CHANNEL_CH1, LL_TIM_IC_POLARITY_FALLING);
|
LL_TIM_IC_SetPolarity(TIM2, LL_TIM_CHANNEL_CH1, LL_TIM_IC_POLARITY_RISING);
|
||||||
LL_TIM_IC_SetActiveInput(TIM2, LL_TIM_CHANNEL_CH2, LL_TIM_ACTIVEINPUT_INDIRECTTI);
|
LL_TIM_IC_SetActiveInput(TIM2, LL_TIM_CHANNEL_CH2, LL_TIM_ACTIVEINPUT_INDIRECTTI);
|
||||||
LL_TIM_IC_SetPrescaler(TIM2, LL_TIM_CHANNEL_CH2, LL_TIM_ICPSC_DIV1);
|
LL_TIM_IC_SetPrescaler(TIM2, LL_TIM_CHANNEL_CH2, LL_TIM_ICPSC_DIV1);
|
||||||
LL_TIM_IC_SetFilter(TIM2, LL_TIM_CHANNEL_CH2, LL_TIM_IC_FILTER_FDIV1);
|
|
||||||
LL_TIM_IC_SetPolarity(TIM2, LL_TIM_CHANNEL_CH2, LL_TIM_IC_POLARITY_RISING);
|
|
||||||
|
|
||||||
LL_TIM_EnableIT_CC1(TIM2);
|
LL_TIM_EnableIT_CC1(TIM2);
|
||||||
LL_TIM_EnableIT_CC2(TIM2);
|
LL_TIM_EnableIT_CC2(TIM2);
|
||||||
@ -90,22 +66,30 @@ void api_hal_irda_rx_irq_init(void)
|
|||||||
NVIC_EnableIRQ(TIM2_IRQn);
|
NVIC_EnableIRQ(TIM2_IRQn);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Doesn't work. F5 deprecated. */
|
||||||
void api_hal_irda_rx_irq_deinit(void) {
|
void api_hal_irda_rx_irq_deinit(void) {
|
||||||
LL_TIM_DisableIT_CC1(TIM2);
|
LL_TIM_DeInit(TIM2);
|
||||||
LL_TIM_DisableIT_CC2(TIM2);
|
}
|
||||||
LL_TIM_CC_DisableChannel(TIM2, LL_TIM_CHANNEL_CH1);
|
|
||||||
LL_TIM_CC_DisableChannel(TIM2, LL_TIM_CHANNEL_CH2);
|
void api_hal_irda_rx_timeout_irq_init(uint32_t timeout_ms) {
|
||||||
|
LL_TIM_OC_SetCompareCH3(TIM2, timeout_ms * 1000);
|
||||||
|
LL_TIM_OC_SetMode(TIM2, LL_TIM_CHANNEL_CH3, LL_TIM_OCMODE_ACTIVE);
|
||||||
|
LL_TIM_CC_EnableChannel(TIM2, LL_TIM_CHANNEL_CH3);
|
||||||
|
LL_TIM_EnableIT_CC3(TIM2);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool api_hal_irda_rx_irq_is_busy(void) {
|
bool api_hal_irda_rx_irq_is_busy(void) {
|
||||||
return (LL_TIM_IsEnabledIT_CC1(TIM2) || LL_TIM_IsEnabledIT_CC2(TIM2));
|
return (LL_TIM_IsEnabledIT_CC1(TIM2) || LL_TIM_IsEnabledIT_CC2(TIM2));
|
||||||
}
|
}
|
||||||
|
|
||||||
void api_hal_irda_rx_irq_set_callback(TimerISRCallback callback, void *ctx) {
|
void api_hal_irda_rx_irq_set_callback(ApiHalIrdaCaptureCallback callback, void *ctx) {
|
||||||
furi_check(callback);
|
timer_irda.capture_callback = callback;
|
||||||
|
timer_irda.capture_context = ctx;
|
||||||
|
}
|
||||||
|
|
||||||
timer_irda.callback = callback;
|
void api_hal_irda_rx_timeout_irq_set_callback(ApiHalIrdaTimeoutCallback callback, void *ctx) {
|
||||||
timer_irda.ctx = ctx;
|
timer_irda.timeout_callback = callback;
|
||||||
|
timer_irda.timeout_context = ctx;
|
||||||
}
|
}
|
||||||
|
|
||||||
void api_hal_irda_pwm_set(float value, float freq) {
|
void api_hal_irda_pwm_set(float value, float freq) {
|
||||||
@ -115,4 +99,3 @@ void api_hal_irda_pwm_set(float value, float freq) {
|
|||||||
void api_hal_irda_pwm_stop() {
|
void api_hal_irda_pwm_stop() {
|
||||||
hal_pwmn_stop(&IRDA_TX_TIM, IRDA_TX_CH);
|
hal_pwmn_stop(&IRDA_TX_TIM, IRDA_TX_CH);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -49,3 +49,7 @@ const GpioPin gpio_ext_pa7 = {.port = GPIOA, .pin = GPIO_PIN_7};
|
|||||||
const GpioPin gpio_rfid_pull = {.port = RFID_PULL_GPIO_Port, .pin = RFID_PULL_Pin};
|
const GpioPin gpio_rfid_pull = {.port = RFID_PULL_GPIO_Port, .pin = RFID_PULL_Pin};
|
||||||
const GpioPin gpio_rfid_carrier_out = {.port = RFID_OUT_GPIO_Port, .pin = RFID_OUT_Pin};
|
const GpioPin gpio_rfid_carrier_out = {.port = RFID_OUT_GPIO_Port, .pin = RFID_OUT_Pin};
|
||||||
const GpioPin gpio_rfid_data_in = {.port = RFID_RF_IN_GPIO_Port, .pin = RFID_RF_IN_Pin};
|
const GpioPin gpio_rfid_data_in = {.port = RFID_RF_IN_GPIO_Port, .pin = RFID_RF_IN_Pin};
|
||||||
|
|
||||||
|
const GpioPin gpio_irda_rx = {.port = IR_RX_GPIO_Port, .pin = IR_RX_Pin};
|
||||||
|
const GpioPin gpio_irda_tx = {.port = IR_TX_GPIO_Port, .pin = IR_TX_Pin};
|
||||||
|
|
||||||
|
@ -87,6 +87,9 @@ extern const GpioPin gpio_rfid_pull;
|
|||||||
extern const GpioPin gpio_rfid_carrier_out;
|
extern const GpioPin gpio_rfid_carrier_out;
|
||||||
extern const GpioPin gpio_rfid_data_in;
|
extern const GpioPin gpio_rfid_data_in;
|
||||||
|
|
||||||
|
extern const GpioPin gpio_irda_rx;
|
||||||
|
extern const GpioPin gpio_irda_tx;
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
@ -14,7 +14,6 @@ void TIM2_IRQHandler(void)
|
|||||||
|
|
||||||
if (READ_BIT(TIM2->CCMR1, TIM_CCMR1_CC1S)) {
|
if (READ_BIT(TIM2->CCMR1, TIM_CCMR1_CC1S)) {
|
||||||
// input capture
|
// input capture
|
||||||
api_hal_irda_tim_isr(TimerIRQSourceCCI1);
|
|
||||||
consumed = true;
|
consumed = true;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
@ -30,7 +29,6 @@ void TIM2_IRQHandler(void)
|
|||||||
|
|
||||||
if (READ_BIT(TIM2->CCMR1, TIM_CCMR1_CC2S)) {
|
if (READ_BIT(TIM2->CCMR1, TIM_CCMR1_CC2S)) {
|
||||||
// input capture
|
// input capture
|
||||||
api_hal_irda_tim_isr(TimerIRQSourceCCI2);
|
|
||||||
consumed = true;
|
consumed = true;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
@ -1,17 +1,22 @@
|
|||||||
#include "api-hal-interrupt.h"
|
|
||||||
#include "api-hal-irda.h"
|
#include "api-hal-irda.h"
|
||||||
|
#include <cmsis_os2.h>
|
||||||
|
#include <api-hal-interrupt.h>
|
||||||
|
#include <api-hal-resources.h>
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
#include <stm32wbxx_ll_tim.h>
|
#include <stm32wbxx_ll_tim.h>
|
||||||
#include <stm32wbxx_ll_gpio.h>
|
#include <stm32wbxx_ll_gpio.h>
|
||||||
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <furi.h>
|
#include <furi.h>
|
||||||
#include "main.h"
|
#include <main.h>
|
||||||
#include "api-hal-pwm.h"
|
#include <api-hal-pwm.h>
|
||||||
|
|
||||||
static struct{
|
static struct{
|
||||||
TimerISRCallback callback;
|
ApiHalIrdaCaptureCallback capture_callback;
|
||||||
void *ctx;
|
void *capture_context;
|
||||||
|
ApiHalIrdaTimeoutCallback timeout_callback;
|
||||||
|
void *timeout_context;
|
||||||
} timer_irda;
|
} timer_irda;
|
||||||
|
|
||||||
typedef enum{
|
typedef enum{
|
||||||
@ -19,107 +24,105 @@ typedef enum{
|
|||||||
TimerIRQSourceCCI2,
|
TimerIRQSourceCCI2,
|
||||||
} TimerIRQSource;
|
} TimerIRQSource;
|
||||||
|
|
||||||
static void api_hal_irda_handle_capture(TimerIRQSource source)
|
static void api_hal_irda_handle_timeout(void) {
|
||||||
{
|
/* Timers CNT register starts to counting from 0 to ARR, but it is
|
||||||
|
* reseted when Channel 1 catches interrupt. It is not reseted by
|
||||||
|
* channel 2, though, so we have to distract it's values (see TimerIRQSourceCCI1 ISR).
|
||||||
|
* This can cause false timeout: when time is over, but we started
|
||||||
|
* receiving new signal few microseconds ago, because CNT register
|
||||||
|
* is reseted once per period, not per sample. */
|
||||||
|
if (LL_GPIO_IsInputPinSet(gpio_irda_rx.port, gpio_irda_rx.pin) == 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (timer_irda.timeout_callback)
|
||||||
|
timer_irda.timeout_callback(timer_irda.timeout_context);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* High pin level is a Space state of IRDA signal. Invert level for further processing. */
|
||||||
|
static void api_hal_irda_handle_capture(TimerIRQSource source) {
|
||||||
uint32_t duration = 0;
|
uint32_t duration = 0;
|
||||||
bool level = 0;
|
bool level = 0;
|
||||||
|
|
||||||
switch (source) {
|
switch (source) {
|
||||||
case TimerIRQSourceCCI1:
|
case TimerIRQSourceCCI1:
|
||||||
duration = LL_TIM_OC_GetCompareCH1(TIM2);
|
duration = LL_TIM_IC_GetCaptureCH1(TIM2) - LL_TIM_IC_GetCaptureCH2(TIM2);
|
||||||
LL_TIM_SetCounter(TIM2, 0);
|
level = 1;
|
||||||
level = 0;
|
|
||||||
break;
|
break;
|
||||||
case TimerIRQSourceCCI2:
|
case TimerIRQSourceCCI2:
|
||||||
duration = LL_TIM_OC_GetCompareCH2(TIM2);
|
duration = LL_TIM_IC_GetCaptureCH2(TIM2);
|
||||||
LL_TIM_SetCounter(TIM2, 0);
|
level = 0;
|
||||||
level = 1;
|
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
furi_check(0);
|
furi_check(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (timer_irda.callback)
|
if (timer_irda.capture_callback)
|
||||||
timer_irda.callback(timer_irda.ctx, level, duration);
|
timer_irda.capture_callback(timer_irda.capture_context, level, duration);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void api_hal_irda_isr() {
|
static void api_hal_irda_isr() {
|
||||||
if(LL_TIM_IsActiveFlag_CC1(TIM2) == 1) {
|
if(LL_TIM_IsActiveFlag_CC3(TIM2)) {
|
||||||
|
LL_TIM_ClearFlag_CC3(TIM2);
|
||||||
|
api_hal_irda_handle_timeout();
|
||||||
|
}
|
||||||
|
if(LL_TIM_IsActiveFlag_CC1(TIM2)) {
|
||||||
LL_TIM_ClearFlag_CC1(TIM2);
|
LL_TIM_ClearFlag_CC1(TIM2);
|
||||||
|
|
||||||
if(READ_BIT(TIM2->CCMR1, TIM_CCMR1_CC1S)) {
|
if(READ_BIT(TIM2->CCMR1, TIM_CCMR1_CC1S)) {
|
||||||
// input capture
|
// input capture
|
||||||
api_hal_irda_handle_capture(TimerIRQSourceCCI1);
|
api_hal_irda_handle_capture(TimerIRQSourceCCI1);
|
||||||
} else {
|
|
||||||
// output compare
|
|
||||||
// HAL_TIM_OC_DelayElapsedCallback(htim);
|
|
||||||
// HAL_TIM_PWM_PulseFinishedCallback(htim);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if(LL_TIM_IsActiveFlag_CC2(TIM2) == 1) {
|
if(LL_TIM_IsActiveFlag_CC2(TIM2)) {
|
||||||
LL_TIM_ClearFlag_CC2(TIM2);
|
LL_TIM_ClearFlag_CC2(TIM2);
|
||||||
|
|
||||||
if(READ_BIT(TIM2->CCMR1, TIM_CCMR1_CC2S)) {
|
if(READ_BIT(TIM2->CCMR1, TIM_CCMR1_CC2S)) {
|
||||||
// input capture
|
// input capture
|
||||||
api_hal_irda_handle_capture(TimerIRQSourceCCI2);
|
api_hal_irda_handle_capture(TimerIRQSourceCCI2);
|
||||||
} else {
|
|
||||||
// output compare
|
|
||||||
// HAL_TIM_OC_DelayElapsedCallback(htim);
|
|
||||||
// HAL_TIM_PWM_PulseFinishedCallback(htim);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void api_hal_irda_rx_irq_init(void)
|
void api_hal_irda_rx_irq_init(void) {
|
||||||
{
|
|
||||||
LL_TIM_InitTypeDef TIM_InitStruct = {0};
|
|
||||||
|
|
||||||
LL_GPIO_InitTypeDef GPIO_InitStruct = {0};
|
|
||||||
|
|
||||||
/* Peripheral clock enable */
|
|
||||||
LL_APB1_GRP1_EnableClock(LL_APB1_GRP1_PERIPH_TIM2);
|
LL_APB1_GRP1_EnableClock(LL_APB1_GRP1_PERIPH_TIM2);
|
||||||
|
|
||||||
LL_AHB2_GRP1_EnableClock(LL_AHB2_GRP1_PERIPH_GPIOA);
|
LL_AHB2_GRP1_EnableClock(LL_AHB2_GRP1_PERIPH_GPIOA);
|
||||||
/**TIM2 GPIO Configuration
|
|
||||||
PA0 ------> TIM2_CH1
|
|
||||||
*/
|
|
||||||
GPIO_InitStruct.Pin = LL_GPIO_PIN_0;
|
|
||||||
GPIO_InitStruct.Mode = LL_GPIO_MODE_ALTERNATE;
|
|
||||||
GPIO_InitStruct.Speed = LL_GPIO_SPEED_FREQ_LOW;
|
|
||||||
GPIO_InitStruct.OutputType = LL_GPIO_OUTPUT_PUSHPULL;
|
|
||||||
GPIO_InitStruct.Pull = LL_GPIO_PULL_NO;
|
|
||||||
GPIO_InitStruct.Alternate = LL_GPIO_AF_1;
|
|
||||||
LL_GPIO_Init(GPIOA, &GPIO_InitStruct);
|
|
||||||
|
|
||||||
|
hal_gpio_init_ex(&gpio_irda_rx, GpioModeAltFunctionPushPull, GpioPullNo, GpioSpeedLow, GpioAltFn1TIM2);
|
||||||
|
|
||||||
|
LL_TIM_InitTypeDef TIM_InitStruct = {0};
|
||||||
TIM_InitStruct.Prescaler = 64 - 1;
|
TIM_InitStruct.Prescaler = 64 - 1;
|
||||||
TIM_InitStruct.CounterMode = LL_TIM_COUNTERMODE_UP;
|
TIM_InitStruct.CounterMode = LL_TIM_COUNTERMODE_UP;
|
||||||
TIM_InitStruct.Autoreload = 0xFFFFFFFF;
|
TIM_InitStruct.Autoreload = 0x7FFFFFFE;
|
||||||
TIM_InitStruct.ClockDivision = LL_TIM_CLOCKDIVISION_DIV1;
|
TIM_InitStruct.ClockDivision = LL_TIM_CLOCKDIVISION_DIV1;
|
||||||
LL_TIM_Init(TIM2, &TIM_InitStruct);
|
LL_TIM_Init(TIM2, &TIM_InitStruct);
|
||||||
|
|
||||||
LL_TIM_SetClockSource(TIM2, LL_TIM_CLOCKSOURCE_INTERNAL);
|
LL_TIM_SetClockSource(TIM2, LL_TIM_CLOCKSOURCE_INTERNAL);
|
||||||
LL_TIM_EnableARRPreload(TIM2);
|
LL_TIM_DisableARRPreload(TIM2);
|
||||||
|
LL_TIM_SetTriggerInput(TIM2, LL_TIM_TS_TI1FP1);
|
||||||
|
LL_TIM_SetSlaveMode(TIM2, LL_TIM_SLAVEMODE_RESET);
|
||||||
|
LL_TIM_CC_DisableChannel(TIM2, LL_TIM_CHANNEL_CH2);
|
||||||
|
LL_TIM_IC_SetFilter(TIM2, LL_TIM_CHANNEL_CH2, LL_TIM_IC_FILTER_FDIV1);
|
||||||
|
LL_TIM_IC_SetPolarity(TIM2, LL_TIM_CHANNEL_CH2, LL_TIM_IC_POLARITY_FALLING);
|
||||||
|
LL_TIM_DisableIT_TRIG(TIM2);
|
||||||
|
LL_TIM_DisableDMAReq_TRIG(TIM2);
|
||||||
LL_TIM_SetTriggerOutput(TIM2, LL_TIM_TRGO_RESET);
|
LL_TIM_SetTriggerOutput(TIM2, LL_TIM_TRGO_RESET);
|
||||||
LL_TIM_DisableMasterSlaveMode(TIM2);
|
LL_TIM_EnableMasterSlaveMode(TIM2);
|
||||||
LL_TIM_IC_SetActiveInput(TIM2, LL_TIM_CHANNEL_CH1, LL_TIM_ACTIVEINPUT_DIRECTTI);
|
LL_TIM_IC_SetActiveInput(TIM2, LL_TIM_CHANNEL_CH1, LL_TIM_ACTIVEINPUT_DIRECTTI);
|
||||||
LL_TIM_IC_SetPrescaler(TIM2, LL_TIM_CHANNEL_CH1, LL_TIM_ICPSC_DIV1);
|
LL_TIM_IC_SetPrescaler(TIM2, LL_TIM_CHANNEL_CH1, LL_TIM_ICPSC_DIV1);
|
||||||
LL_TIM_IC_SetFilter(TIM2, LL_TIM_CHANNEL_CH1, LL_TIM_IC_FILTER_FDIV1);
|
LL_TIM_IC_SetFilter(TIM2, LL_TIM_CHANNEL_CH1, LL_TIM_IC_FILTER_FDIV1);
|
||||||
LL_TIM_IC_SetPolarity(TIM2, LL_TIM_CHANNEL_CH1, LL_TIM_IC_POLARITY_FALLING);
|
LL_TIM_IC_SetPolarity(TIM2, LL_TIM_CHANNEL_CH1, LL_TIM_IC_POLARITY_RISING);
|
||||||
LL_TIM_IC_SetActiveInput(TIM2, LL_TIM_CHANNEL_CH2, LL_TIM_ACTIVEINPUT_INDIRECTTI);
|
LL_TIM_IC_SetActiveInput(TIM2, LL_TIM_CHANNEL_CH2, LL_TIM_ACTIVEINPUT_INDIRECTTI);
|
||||||
LL_TIM_IC_SetPrescaler(TIM2, LL_TIM_CHANNEL_CH2, LL_TIM_ICPSC_DIV1);
|
LL_TIM_IC_SetPrescaler(TIM2, LL_TIM_CHANNEL_CH2, LL_TIM_ICPSC_DIV1);
|
||||||
LL_TIM_IC_SetFilter(TIM2, LL_TIM_CHANNEL_CH2, LL_TIM_IC_FILTER_FDIV1);
|
|
||||||
LL_TIM_IC_SetPolarity(TIM2, LL_TIM_CHANNEL_CH2, LL_TIM_IC_POLARITY_RISING);
|
|
||||||
|
|
||||||
LL_TIM_EnableIT_CC1(TIM2);
|
LL_TIM_EnableIT_CC1(TIM2);
|
||||||
LL_TIM_EnableIT_CC2(TIM2);
|
LL_TIM_EnableIT_CC2(TIM2);
|
||||||
LL_TIM_CC_EnableChannel(TIM2, LL_TIM_CHANNEL_CH1);
|
LL_TIM_CC_EnableChannel(TIM2, LL_TIM_CHANNEL_CH1);
|
||||||
LL_TIM_CC_EnableChannel(TIM2, LL_TIM_CHANNEL_CH2);
|
LL_TIM_CC_EnableChannel(TIM2, LL_TIM_CHANNEL_CH2);
|
||||||
|
|
||||||
|
api_hal_interrupt_set_timer_isr(TIM2, api_hal_irda_isr);
|
||||||
|
|
||||||
LL_TIM_SetCounter(TIM2, 0);
|
LL_TIM_SetCounter(TIM2, 0);
|
||||||
LL_TIM_EnableCounter(TIM2);
|
LL_TIM_EnableCounter(TIM2);
|
||||||
|
|
||||||
api_hal_interrupt_set_timer_isr(TIM2, api_hal_irda_isr);
|
|
||||||
NVIC_SetPriority(TIM2_IRQn, NVIC_EncodePriority(NVIC_GetPriorityGrouping(),5, 0));
|
|
||||||
NVIC_EnableIRQ(TIM2_IRQn);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void api_hal_irda_rx_irq_deinit(void) {
|
void api_hal_irda_rx_irq_deinit(void) {
|
||||||
@ -127,15 +130,25 @@ void api_hal_irda_rx_irq_deinit(void) {
|
|||||||
api_hal_interrupt_set_timer_isr(TIM2, NULL);
|
api_hal_interrupt_set_timer_isr(TIM2, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void api_hal_irda_rx_timeout_irq_init(uint32_t timeout_ms) {
|
||||||
|
LL_TIM_OC_SetCompareCH3(TIM2, timeout_ms * 1000);
|
||||||
|
LL_TIM_OC_SetMode(TIM2, LL_TIM_CHANNEL_CH3, LL_TIM_OCMODE_ACTIVE);
|
||||||
|
LL_TIM_CC_EnableChannel(TIM2, LL_TIM_CHANNEL_CH3);
|
||||||
|
LL_TIM_EnableIT_CC3(TIM2);
|
||||||
|
}
|
||||||
|
|
||||||
bool api_hal_irda_rx_irq_is_busy(void) {
|
bool api_hal_irda_rx_irq_is_busy(void) {
|
||||||
return (LL_TIM_IsEnabledIT_CC1(TIM2) || LL_TIM_IsEnabledIT_CC2(TIM2));
|
return (LL_TIM_IsEnabledIT_CC1(TIM2) || LL_TIM_IsEnabledIT_CC2(TIM2));
|
||||||
}
|
}
|
||||||
|
|
||||||
void api_hal_irda_rx_irq_set_callback(TimerISRCallback callback, void *ctx) {
|
void api_hal_irda_rx_irq_set_callback(ApiHalIrdaCaptureCallback callback, void *ctx) {
|
||||||
furi_check(callback);
|
timer_irda.capture_callback = callback;
|
||||||
|
timer_irda.capture_context = ctx;
|
||||||
|
}
|
||||||
|
|
||||||
timer_irda.callback = callback;
|
void api_hal_irda_rx_timeout_irq_set_callback(ApiHalIrdaTimeoutCallback callback, void *ctx) {
|
||||||
timer_irda.ctx = ctx;
|
timer_irda.timeout_callback = callback;
|
||||||
|
timer_irda.timeout_context = ctx;
|
||||||
}
|
}
|
||||||
|
|
||||||
void api_hal_irda_pwm_set(float value, float freq) {
|
void api_hal_irda_pwm_set(float value, float freq) {
|
||||||
|
@ -48,3 +48,7 @@ const GpioPin gpio_ext_pa7 = {.port = GPIOA, .pin = GPIO_PIN_7};
|
|||||||
const GpioPin gpio_rfid_pull = {.port = RFID_PULL_GPIO_Port, .pin = RFID_PULL_Pin};
|
const GpioPin gpio_rfid_pull = {.port = RFID_PULL_GPIO_Port, .pin = RFID_PULL_Pin};
|
||||||
const GpioPin gpio_rfid_carrier_out = {.port = RFID_OUT_GPIO_Port, .pin = RFID_OUT_Pin};
|
const GpioPin gpio_rfid_carrier_out = {.port = RFID_OUT_GPIO_Port, .pin = RFID_OUT_Pin};
|
||||||
const GpioPin gpio_rfid_data_in = {.port = RFID_RF_IN_GPIO_Port, .pin = RFID_RF_IN_Pin};
|
const GpioPin gpio_rfid_data_in = {.port = RFID_RF_IN_GPIO_Port, .pin = RFID_RF_IN_Pin};
|
||||||
|
|
||||||
|
const GpioPin gpio_irda_rx = {.port = IR_RX_GPIO_Port, .pin = IR_RX_Pin};
|
||||||
|
const GpioPin gpio_irda_tx = {.port = IR_TX_GPIO_Port, .pin = IR_TX_Pin};
|
||||||
|
|
||||||
|
@ -86,6 +86,9 @@ extern const GpioPin gpio_rfid_pull;
|
|||||||
extern const GpioPin gpio_rfid_carrier_out;
|
extern const GpioPin gpio_rfid_carrier_out;
|
||||||
extern const GpioPin gpio_rfid_data_in;
|
extern const GpioPin gpio_rfid_data_in;
|
||||||
|
|
||||||
|
extern const GpioPin gpio_irda_rx;
|
||||||
|
extern const GpioPin gpio_irda_tx;
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
@ -1,9 +1,10 @@
|
|||||||
#include "file_reader/file_reader.hpp"
|
#include <file_reader.h>
|
||||||
|
|
||||||
std::string FileReader::getline(File* file) {
|
std::string FileReader::getline(File* file) {
|
||||||
std::string str;
|
std::string str;
|
||||||
size_t newline_index = 0;
|
size_t newline_index = 0;
|
||||||
bool found_eol = false;
|
bool found_eol = false;
|
||||||
|
bool max_length_exceeded = false;
|
||||||
|
|
||||||
while(1) {
|
while(1) {
|
||||||
if(file_buf_cnt > 0) {
|
if(file_buf_cnt > 0) {
|
||||||
@ -20,7 +21,12 @@ std::string FileReader::getline(File* file) {
|
|||||||
furi_assert(0);
|
furi_assert(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (max_line_length && (str.size() + end_index > max_line_length))
|
||||||
|
max_length_exceeded = true;
|
||||||
|
|
||||||
|
if (!max_length_exceeded)
|
||||||
str.append(file_buf, end_index);
|
str.append(file_buf, end_index);
|
||||||
|
|
||||||
memmove(file_buf, &file_buf[end_index], file_buf_cnt - end_index);
|
memmove(file_buf, &file_buf[end_index], file_buf_cnt - end_index);
|
||||||
file_buf_cnt = file_buf_cnt - end_index;
|
file_buf_cnt = file_buf_cnt - end_index;
|
||||||
if(found_eol) break;
|
if(found_eol) break;
|
||||||
@ -33,6 +39,9 @@ std::string FileReader::getline(File* file) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (max_length_exceeded)
|
||||||
|
str.clear();
|
||||||
|
|
||||||
return str;
|
return str;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -8,6 +8,7 @@ class FileReader {
|
|||||||
private:
|
private:
|
||||||
char file_buf[48];
|
char file_buf[48];
|
||||||
size_t file_buf_cnt = 0;
|
size_t file_buf_cnt = 0;
|
||||||
|
size_t max_line_length = 0;
|
||||||
SdCard_Api* sd_ex_api;
|
SdCard_Api* sd_ex_api;
|
||||||
FS_Api* fs_api;
|
FS_Api* fs_api;
|
||||||
|
|
||||||
@ -35,5 +36,9 @@ public:
|
|||||||
FS_Api& get_fs_api() {
|
FS_Api& get_fs_api() {
|
||||||
return *fs_api;
|
return *fs_api;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void set_max_line_length(size_t value) {
|
||||||
|
max_line_length = value;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
@ -69,14 +69,6 @@ void irda_free_decoder(IrdaDecoderHandler* handler);
|
|||||||
*/
|
*/
|
||||||
void irda_reset_decoder(IrdaDecoderHandler* handler);
|
void irda_reset_decoder(IrdaDecoderHandler* handler);
|
||||||
|
|
||||||
/**
|
|
||||||
* Send message over IRDA.
|
|
||||||
*
|
|
||||||
* \param[in] message - message to send.
|
|
||||||
* \param[in] times - number of times message should be sent.
|
|
||||||
*/
|
|
||||||
void irda_send(const IrdaMessage* message, int times);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get protocol name by protocol enum.
|
* Get protocol name by protocol enum.
|
||||||
*
|
*
|
||||||
@ -117,19 +109,6 @@ uint8_t irda_get_protocol_command_length(IrdaProtocol protocol);
|
|||||||
*/
|
*/
|
||||||
bool irda_is_protocol_valid(IrdaProtocol protocol);
|
bool irda_is_protocol_valid(IrdaProtocol protocol);
|
||||||
|
|
||||||
/**
|
|
||||||
* Send raw data through infrared port.
|
|
||||||
*
|
|
||||||
* \param[in] protocol - use IRDA settings (duty cycle, frequency) from
|
|
||||||
* this protocol. If provided IrdaProtocolUnknown - use
|
|
||||||
* default settings.
|
|
||||||
* \param[in] timings - array of timings to send.
|
|
||||||
* \param[in] timings_cnt - timings array size.
|
|
||||||
* \param[in] start_from_mark - true if timings starts from mark,
|
|
||||||
* otherwise from space
|
|
||||||
*/
|
|
||||||
void irda_send_raw(const uint32_t timings[], uint32_t timings_cnt, bool start_from_mark);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Allocate IRDA encoder.
|
* Allocate IRDA encoder.
|
||||||
*
|
*
|
@ -6,9 +6,11 @@
|
|||||||
#include <api-hal-irda.h>
|
#include <api-hal-irda.h>
|
||||||
#include <api-hal-delay.h>
|
#include <api-hal-delay.h>
|
||||||
|
|
||||||
static void irda_set_tx(uint32_t duration, bool level) {
|
#define IRDA_SET_TX_COMMON(d, l) irda_set_tx((d), (l), IRDA_COMMON_DUTY_CYCLE, IRDA_COMMON_CARRIER_FREQUENCY)
|
||||||
|
|
||||||
|
static void irda_set_tx(uint32_t duration, bool level, float duty_cycle, float frequency) {
|
||||||
if (level) {
|
if (level) {
|
||||||
api_hal_irda_pwm_set(IRDA_COMMON_DUTY_CYCLE, IRDA_COMMON_CARRIER_FREQUENCY);
|
api_hal_irda_pwm_set(duty_cycle, frequency);
|
||||||
delay_us(duration);
|
delay_us(duration);
|
||||||
} else {
|
} else {
|
||||||
api_hal_irda_pwm_stop();
|
api_hal_irda_pwm_stop();
|
||||||
@ -16,12 +18,21 @@ static void irda_set_tx(uint32_t duration, bool level) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void irda_send_raw_ext(const uint32_t timings[], uint32_t timings_cnt, bool start_from_mark, float duty_cycle, float frequency) {
|
||||||
|
__disable_irq();
|
||||||
|
for (uint32_t i = 0; i < timings_cnt; ++i) {
|
||||||
|
irda_set_tx(timings[i], (i % 2) ^ start_from_mark, duty_cycle, frequency);
|
||||||
|
}
|
||||||
|
IRDA_SET_TX_COMMON(0, false);
|
||||||
|
__enable_irq();
|
||||||
|
}
|
||||||
|
|
||||||
void irda_send_raw(const uint32_t timings[], uint32_t timings_cnt, bool start_from_mark) {
|
void irda_send_raw(const uint32_t timings[], uint32_t timings_cnt, bool start_from_mark) {
|
||||||
__disable_irq();
|
__disable_irq();
|
||||||
for (uint32_t i = 0; i < timings_cnt; ++i) {
|
for (uint32_t i = 0; i < timings_cnt; ++i) {
|
||||||
irda_set_tx(timings[i], (i % 2) ^ start_from_mark);
|
IRDA_SET_TX_COMMON(timings[i], (i % 2) ^ start_from_mark);
|
||||||
}
|
}
|
||||||
irda_set_tx(0, false);
|
IRDA_SET_TX_COMMON(0, false);
|
||||||
__enable_irq();
|
__enable_irq();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -49,7 +60,7 @@ void irda_send(const IrdaMessage* message, int times) {
|
|||||||
while (times) {
|
while (times) {
|
||||||
status = irda_encode(handler, &duration, &level);
|
status = irda_encode(handler, &duration, &level);
|
||||||
if (status != IrdaStatusError) {
|
if (status != IrdaStatusError) {
|
||||||
irda_set_tx(duration, level);
|
IRDA_SET_TX_COMMON(duration, level);
|
||||||
} else {
|
} else {
|
||||||
furi_assert(0);
|
furi_assert(0);
|
||||||
break;
|
break;
|
||||||
@ -58,7 +69,7 @@ void irda_send(const IrdaMessage* message, int times) {
|
|||||||
--times;
|
--times;
|
||||||
}
|
}
|
||||||
|
|
||||||
irda_set_tx(0, false);
|
IRDA_SET_TX_COMMON(0, false);
|
||||||
__enable_irq();
|
__enable_irq();
|
||||||
|
|
||||||
irda_free_encoder(handler);
|
irda_free_encoder(handler);
|
41
lib/irda/worker/irda_transmit.h
Normal file
41
lib/irda/worker/irda_transmit.h
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
#include <api-hal-irda.h>
|
||||||
|
#include <irda.h>
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Send message over IRDA.
|
||||||
|
*
|
||||||
|
* \param[in] message - message to send.
|
||||||
|
* \param[in] times - number of times message should be sent.
|
||||||
|
*/
|
||||||
|
void irda_send(const IrdaMessage* message, int times);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Send raw data through infrared port.
|
||||||
|
*
|
||||||
|
* \param[in] timings - array of timings to send.
|
||||||
|
* \param[in] timings_cnt - timings array size.
|
||||||
|
* \param[in] start_from_mark - true if timings starts from mark,
|
||||||
|
* otherwise from space
|
||||||
|
*/
|
||||||
|
void irda_send_raw(const uint32_t timings[], uint32_t timings_cnt, bool start_from_mark);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Send raw data through infrared port, with additional settings.
|
||||||
|
*
|
||||||
|
* \param[in] timings - array of timings to send.
|
||||||
|
* \param[in] timings_cnt - timings array size.
|
||||||
|
* \param[in] start_from_mark - true if timings starts from mark,
|
||||||
|
* otherwise from space
|
||||||
|
* \param[in] duty_cycle - duty cycle to generate on PWM
|
||||||
|
* \param[in] frequency - frequency to generate on PWM
|
||||||
|
*/
|
||||||
|
void irda_send_raw_ext(const uint32_t timings[], uint32_t timings_cnt, bool start_from_mark, float duty_cycle, float frequency);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
237
lib/irda/worker/irda_worker.c
Normal file
237
lib/irda/worker/irda_worker.c
Normal file
@ -0,0 +1,237 @@
|
|||||||
|
#include "irda_worker.h"
|
||||||
|
#include <irda.h>
|
||||||
|
#include <api-hal-irda.h>
|
||||||
|
#include <limits.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stream_buffer.h>
|
||||||
|
#include <furi.h>
|
||||||
|
#include <notification/notification-messages.h>
|
||||||
|
|
||||||
|
#define MAX_TIMINGS_AMOUNT 500
|
||||||
|
#define IRDA_WORKER_RX_TIMEOUT 150 // ms
|
||||||
|
#define IRDA_WORKER_RX_RECEIVED 0x01
|
||||||
|
#define IRDA_WORKER_RX_TIMEOUT_RECEIVED 0x02
|
||||||
|
#define IRDA_WORKER_OVERRUN 0x04
|
||||||
|
#define IRDA_WORKER_EXIT 0x08
|
||||||
|
|
||||||
|
struct IrdaWorkerSignal {
|
||||||
|
bool decoded;
|
||||||
|
size_t timings_cnt;
|
||||||
|
union {
|
||||||
|
IrdaMessage message;
|
||||||
|
uint32_t timings[MAX_TIMINGS_AMOUNT];
|
||||||
|
} data;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct IrdaWorker {
|
||||||
|
FuriThread* thread;
|
||||||
|
IrdaDecoderHandler* irda_decoder;
|
||||||
|
StreamBufferHandle_t stream;
|
||||||
|
|
||||||
|
TaskHandle_t worker_handle;
|
||||||
|
IrdaWorkerSignal signal;
|
||||||
|
|
||||||
|
IrdaWorkerReceivedSignalCallback received_signal_callback;
|
||||||
|
void* context;
|
||||||
|
bool blink_enable;
|
||||||
|
bool overrun;
|
||||||
|
NotificationApp* notification;
|
||||||
|
};
|
||||||
|
|
||||||
|
static void irda_worker_rx_timeout_callback(void* context) {
|
||||||
|
IrdaWorker* instance = context;
|
||||||
|
BaseType_t xHigherPriorityTaskWoken = pdFALSE;
|
||||||
|
xTaskNotifyFromISR(instance->worker_handle, IRDA_WORKER_RX_TIMEOUT_RECEIVED, eSetBits, &xHigherPriorityTaskWoken);
|
||||||
|
portYIELD_FROM_ISR(xHigherPriorityTaskWoken);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void irda_worker_rx_callback(void* context, bool level, uint32_t duration) {
|
||||||
|
IrdaWorker* instance = context;
|
||||||
|
|
||||||
|
BaseType_t xHigherPriorityTaskWoken = pdFALSE;
|
||||||
|
LevelDuration level_duration = level_duration_make(level, duration);
|
||||||
|
|
||||||
|
size_t ret =
|
||||||
|
xStreamBufferSendFromISR(instance->stream, &level_duration, sizeof(LevelDuration), &xHigherPriorityTaskWoken);
|
||||||
|
uint32_t notify_value = (ret == sizeof(LevelDuration)) ? IRDA_WORKER_RX_RECEIVED : IRDA_WORKER_OVERRUN;
|
||||||
|
xTaskNotifyFromISR(instance->worker_handle, notify_value, eSetBits, &xHigherPriorityTaskWoken);
|
||||||
|
portYIELD_FROM_ISR(xHigherPriorityTaskWoken);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void irda_worker_process_timeout(IrdaWorker* instance) {
|
||||||
|
if (instance->signal.timings_cnt < 2)
|
||||||
|
return;
|
||||||
|
|
||||||
|
instance->signal.decoded = false;
|
||||||
|
if (instance->received_signal_callback)
|
||||||
|
instance->received_signal_callback(instance->context, &instance->signal);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void irda_worker_process_timings(IrdaWorker* instance, uint32_t duration, bool level) {
|
||||||
|
const IrdaMessage* message_decoded = irda_decode(instance->irda_decoder, level, duration);
|
||||||
|
if (message_decoded) {
|
||||||
|
instance->signal.data.message = *message_decoded;
|
||||||
|
instance->signal.timings_cnt = 0;
|
||||||
|
instance->signal.decoded = true;
|
||||||
|
if (instance->received_signal_callback)
|
||||||
|
instance->received_signal_callback(instance->context, &instance->signal);
|
||||||
|
} else {
|
||||||
|
/* Skip first timing if it's starts from Space */
|
||||||
|
if ((instance->signal.timings_cnt == 0) && !level) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (instance->signal.timings_cnt < MAX_TIMINGS_AMOUNT) {
|
||||||
|
instance->signal.data.timings[instance->signal.timings_cnt] = duration;
|
||||||
|
++instance->signal.timings_cnt;
|
||||||
|
} else {
|
||||||
|
xTaskNotify(instance->worker_handle, IRDA_WORKER_OVERRUN, eSetBits);
|
||||||
|
instance->overrun = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static int32_t irda_worker_thread_callback(void* context) {
|
||||||
|
IrdaWorker* instance = context;
|
||||||
|
uint32_t notify_value = 0;
|
||||||
|
LevelDuration level_duration;
|
||||||
|
TickType_t last_blink_time = 0;
|
||||||
|
|
||||||
|
while(1) {
|
||||||
|
BaseType_t result;
|
||||||
|
result = xTaskNotifyWait(pdFALSE, ULONG_MAX, ¬ify_value, 1000);
|
||||||
|
if (result != pdPASS)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (notify_value & IRDA_WORKER_RX_RECEIVED) {
|
||||||
|
if (!instance->overrun && instance->blink_enable && ((xTaskGetTickCount() - last_blink_time) > 80)) {
|
||||||
|
last_blink_time = xTaskGetTickCount();
|
||||||
|
notification_message(instance->notification, &sequence_blink_blue_10);
|
||||||
|
}
|
||||||
|
if (instance->signal.timings_cnt == 0)
|
||||||
|
notification_message(instance->notification, &sequence_display_on);
|
||||||
|
while (sizeof(LevelDuration) == xStreamBufferReceive(instance->stream, &level_duration, sizeof(LevelDuration), 0)) {
|
||||||
|
if (!instance->overrun) {
|
||||||
|
bool level = level_duration_get_level(level_duration);
|
||||||
|
uint32_t duration = level_duration_get_duration(level_duration);
|
||||||
|
irda_worker_process_timings(instance, duration, level);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (notify_value & IRDA_WORKER_OVERRUN) {
|
||||||
|
printf("#");
|
||||||
|
irda_reset_decoder(instance->irda_decoder);
|
||||||
|
instance->signal.timings_cnt = 0;
|
||||||
|
if (instance->blink_enable)
|
||||||
|
notification_message(instance->notification, &sequence_set_red_255);
|
||||||
|
}
|
||||||
|
if (notify_value & IRDA_WORKER_RX_TIMEOUT_RECEIVED) {
|
||||||
|
if (instance->overrun) {
|
||||||
|
printf("\nOVERRUN, max samples: %d\n", MAX_TIMINGS_AMOUNT);
|
||||||
|
instance->overrun = false;
|
||||||
|
if (instance->blink_enable)
|
||||||
|
notification_message(instance->notification, &sequence_reset_red);
|
||||||
|
} else {
|
||||||
|
irda_worker_process_timeout(instance);
|
||||||
|
}
|
||||||
|
instance->signal.timings_cnt = 0;
|
||||||
|
}
|
||||||
|
if (notify_value & IRDA_WORKER_EXIT)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void irda_worker_set_received_signal_callback(IrdaWorker* instance, IrdaWorkerReceivedSignalCallback callback) {
|
||||||
|
furi_assert(instance);
|
||||||
|
instance->received_signal_callback = callback;
|
||||||
|
}
|
||||||
|
|
||||||
|
IrdaWorker* irda_worker_alloc() {
|
||||||
|
IrdaWorker* instance = furi_alloc(sizeof(IrdaWorker));
|
||||||
|
|
||||||
|
instance->thread = furi_thread_alloc();
|
||||||
|
furi_thread_set_name(instance->thread, "irda_worker");
|
||||||
|
furi_thread_set_stack_size(instance->thread, 2048);
|
||||||
|
furi_thread_set_context(instance->thread, instance);
|
||||||
|
furi_thread_set_callback(instance->thread, irda_worker_thread_callback);
|
||||||
|
|
||||||
|
instance->stream = xStreamBufferCreate(sizeof(LevelDuration) * 512, sizeof(LevelDuration));
|
||||||
|
|
||||||
|
instance->irda_decoder = irda_alloc_decoder();
|
||||||
|
instance->blink_enable = false;
|
||||||
|
instance->notification = furi_record_open("notification");
|
||||||
|
|
||||||
|
return instance;
|
||||||
|
}
|
||||||
|
|
||||||
|
void irda_worker_free(IrdaWorker* instance) {
|
||||||
|
furi_assert(instance);
|
||||||
|
furi_assert(!instance->worker_handle);
|
||||||
|
|
||||||
|
furi_record_close("notification");
|
||||||
|
irda_free_decoder(instance->irda_decoder);
|
||||||
|
vStreamBufferDelete(instance->stream);
|
||||||
|
furi_thread_free(instance->thread);
|
||||||
|
|
||||||
|
free(instance);
|
||||||
|
}
|
||||||
|
|
||||||
|
void irda_worker_set_context(IrdaWorker* instance, void* context) {
|
||||||
|
furi_assert(instance);
|
||||||
|
instance->context = context;
|
||||||
|
}
|
||||||
|
|
||||||
|
void irda_worker_start(IrdaWorker* instance) {
|
||||||
|
furi_assert(instance);
|
||||||
|
furi_assert(!instance->worker_handle);
|
||||||
|
|
||||||
|
furi_thread_start(instance->thread);
|
||||||
|
|
||||||
|
instance->worker_handle = furi_thread_get_thread_id(instance->thread);
|
||||||
|
api_hal_irda_rx_irq_init();
|
||||||
|
api_hal_irda_rx_timeout_irq_init(IRDA_WORKER_RX_TIMEOUT);
|
||||||
|
api_hal_irda_rx_irq_set_callback(irda_worker_rx_callback, instance);
|
||||||
|
api_hal_irda_rx_timeout_irq_set_callback(irda_worker_rx_timeout_callback, instance);
|
||||||
|
}
|
||||||
|
|
||||||
|
void irda_worker_stop(IrdaWorker* instance) {
|
||||||
|
furi_assert(instance);
|
||||||
|
furi_assert(instance->worker_handle);
|
||||||
|
|
||||||
|
api_hal_irda_rx_timeout_irq_set_callback(NULL, NULL);
|
||||||
|
api_hal_irda_rx_irq_set_callback(NULL, NULL);
|
||||||
|
api_hal_irda_rx_irq_deinit();
|
||||||
|
|
||||||
|
xTaskNotify(instance->worker_handle, IRDA_WORKER_EXIT, eSetBits);
|
||||||
|
|
||||||
|
instance->worker_handle = NULL;
|
||||||
|
|
||||||
|
furi_thread_join(instance->thread);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool irda_worker_signal_is_decoded(const IrdaWorkerSignal* signal) {
|
||||||
|
furi_assert(signal);
|
||||||
|
return signal->decoded;
|
||||||
|
}
|
||||||
|
|
||||||
|
void irda_worker_get_raw_signal(const IrdaWorkerSignal* signal, const uint32_t** timings, size_t* timings_cnt) {
|
||||||
|
furi_assert(signal);
|
||||||
|
furi_assert(timings);
|
||||||
|
furi_assert(timings_cnt);
|
||||||
|
|
||||||
|
*timings = signal->data.timings;
|
||||||
|
*timings_cnt = signal->timings_cnt;
|
||||||
|
}
|
||||||
|
|
||||||
|
const IrdaMessage* irda_worker_get_decoded_message(const IrdaWorkerSignal* signal) {
|
||||||
|
furi_assert(signal);
|
||||||
|
return &signal->data.message;
|
||||||
|
}
|
||||||
|
|
||||||
|
void irda_worker_enable_blink_on_receiving(IrdaWorker* instance, bool enable) {
|
||||||
|
furi_assert(instance);
|
||||||
|
instance->blink_enable = enable;
|
||||||
|
}
|
||||||
|
|
91
lib/irda/worker/irda_worker.h
Normal file
91
lib/irda/worker/irda_worker.h
Normal file
@ -0,0 +1,91 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <irda.h>
|
||||||
|
#include <api-hal.h>
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/** Interface struct of irda worker */
|
||||||
|
typedef struct IrdaWorker IrdaWorker;
|
||||||
|
/** Interface struct of received signal */
|
||||||
|
typedef struct IrdaWorkerSignal IrdaWorkerSignal;
|
||||||
|
|
||||||
|
/** Callback type to call by IrdaWorker thread when new signal is received */
|
||||||
|
typedef void (*IrdaWorkerReceivedSignalCallback)(void* context, IrdaWorkerSignal* received_signal);
|
||||||
|
|
||||||
|
/** Allocate IrdaWorker
|
||||||
|
*
|
||||||
|
* @return just created instance of IrdaWorker
|
||||||
|
*/
|
||||||
|
IrdaWorker* irda_worker_alloc();
|
||||||
|
|
||||||
|
/** Free IrdaWorker
|
||||||
|
*
|
||||||
|
* @param[in] instance - IrdaWorker instance
|
||||||
|
*/
|
||||||
|
void irda_worker_free(IrdaWorker* instance);
|
||||||
|
|
||||||
|
/** Received data callback IrdaWorker
|
||||||
|
*
|
||||||
|
* @param[in] instance - IrdaWorker instance
|
||||||
|
* @param[in] callback - IrdaWorkerReceivedSignalCallback callback
|
||||||
|
*/
|
||||||
|
void irda_worker_set_received_signal_callback(IrdaWorker* instance, IrdaWorkerReceivedSignalCallback callback);
|
||||||
|
|
||||||
|
/** Context callback IrdaWorker
|
||||||
|
*
|
||||||
|
* @param[in] instance - IrdaWorker instance
|
||||||
|
* @param[in] context - context to pass to callbacks
|
||||||
|
*/
|
||||||
|
void irda_worker_set_context(IrdaWorker* instance, void* context);
|
||||||
|
|
||||||
|
/** Start IrdaWorker thread, initialise api-hal, prepare all work.
|
||||||
|
*
|
||||||
|
* @param[in] instance - IrdaWorker instance
|
||||||
|
*/
|
||||||
|
void irda_worker_start(IrdaWorker* instance);
|
||||||
|
|
||||||
|
/** Stop IrdaWorker thread, deinitialize api-hal.
|
||||||
|
*
|
||||||
|
* @param[in] instance - IrdaWorker instance
|
||||||
|
*/
|
||||||
|
void irda_worker_stop(IrdaWorker* instance);
|
||||||
|
|
||||||
|
/** Clarify is received signal either decoded or raw
|
||||||
|
*
|
||||||
|
* @param[in] signal - received signal
|
||||||
|
* @return true if signal is decoded, false if signal is raw
|
||||||
|
*/
|
||||||
|
bool irda_worker_signal_is_decoded(const IrdaWorkerSignal* signal);
|
||||||
|
|
||||||
|
/** Acquire raw signal from interface struct 'IrdaWorkerSignal'.
|
||||||
|
* First, you have to ensure that signal is raw.
|
||||||
|
*
|
||||||
|
* @param[in] signal - received signal
|
||||||
|
* @param[out] timings - pointer to array of timings
|
||||||
|
* @param[out] timings_cnt - pointer to amount of timings
|
||||||
|
*/
|
||||||
|
void irda_worker_get_raw_signal(const IrdaWorkerSignal* signal, const uint32_t** timings, size_t* timings_cnt);
|
||||||
|
|
||||||
|
/** Acquire decoded message from interface struct 'IrdaWorkerSignal'.
|
||||||
|
* First, you have to ensure that signal is decoded.
|
||||||
|
*
|
||||||
|
* @param[in] signal - received signal
|
||||||
|
* @return decoded irda message
|
||||||
|
*/
|
||||||
|
const IrdaMessage* irda_worker_get_decoded_message(const IrdaWorkerSignal* signal);
|
||||||
|
|
||||||
|
/** Enable blinking on receiving any signal on IR port.
|
||||||
|
*
|
||||||
|
* @param[in] instance - instance of IrdaWorker
|
||||||
|
* @param[in] enable - true if you want to enable blinking
|
||||||
|
* false otherwise
|
||||||
|
*/
|
||||||
|
void irda_worker_enable_blink_on_receiving(IrdaWorker* instance, bool enable);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
@ -94,9 +94,11 @@ CFLAGS += -I$(LIB_DIR)/file_reader
|
|||||||
CPP_SOURCES += $(wildcard $(LIB_DIR)/file_reader/*.cpp)
|
CPP_SOURCES += $(wildcard $(LIB_DIR)/file_reader/*.cpp)
|
||||||
|
|
||||||
#irda lib
|
#irda lib
|
||||||
CFLAGS += -I$(LIB_DIR)/irda
|
CFLAGS += -I$(LIB_DIR)/irda/encoder_decoder
|
||||||
C_SOURCES += $(wildcard $(LIB_DIR)/irda/*.c)
|
CFLAGS += -I$(LIB_DIR)/irda/worker
|
||||||
C_SOURCES += $(wildcard $(LIB_DIR)/irda/*/*.c)
|
C_SOURCES += $(wildcard $(LIB_DIR)/irda/encoder_decoder/*.c)
|
||||||
|
C_SOURCES += $(wildcard $(LIB_DIR)/irda/encoder_decoder/*/*.c)
|
||||||
|
C_SOURCES += $(wildcard $(LIB_DIR)/irda/worker/*.c)
|
||||||
|
|
||||||
#args lib
|
#args lib
|
||||||
CFLAGS += -I$(LIB_DIR)/args
|
CFLAGS += -I$(LIB_DIR)/args
|
||||||
|
Loading…
x
Reference in New Issue
Block a user