1
1
// Methods for IR transmission
2
2
3
+ // infrared
3
4
#include <infrared.h>
4
5
#include <infrared/encoder_decoder/infrared.h>
5
- #include <applications/services/cli/cli.h>
6
+ #include <infrared/worker/infrared_transmit.h>
7
+ #include <infrared/worker/infrared_worker.h>
8
+
9
+ #include <flipper_format/flipper_format.h>
6
10
7
11
#include "action_i.h"
8
12
#include "quac.h"
9
13
14
+ #define INFRARED_FILE_TYPE "IR signals file"
15
+ #define INFRARED_FILE_VERSION 1
16
+
10
17
typedef struct {
11
18
size_t timings_size ; /**< Number of elements in the timings array. */
12
19
uint32_t * timings ; /**< Pointer to an array of timings describing the signal. */
@@ -17,7 +24,7 @@ typedef struct {
17
24
typedef struct InfraredSignal {
18
25
bool is_raw ;
19
26
union {
20
- InfraredMessage message ;
27
+ InfraredMessage message ; // protocol, address, command, repeat
21
28
InfraredRawSignal raw ;
22
29
} payload ;
23
30
} InfraredSignal ;
@@ -29,19 +36,149 @@ InfraredSignal* infrared_signal_alloc() {
29
36
return signal ;
30
37
}
31
38
39
+ void infrared_signal_free (InfraredSignal * signal ) {
40
+ if (signal -> is_raw ) {
41
+ free (signal -> payload .raw .timings );
42
+ signal -> payload .raw .timings = NULL ;
43
+ }
44
+ free (signal );
45
+ }
46
+
32
47
void action_ir_tx (void * context , const FuriString * action_path , FuriString * error ) {
33
- UNUSED (action_path );
34
48
UNUSED (error );
35
- UNUSED (context );
36
- // App* app = context;
37
-
38
- // InfraredSignal* signal = infrared_signal_alloc();
39
- // const char* ir_file = furi_string_get_cstr(action_path);
40
- // bool success = infrared_parse_message(ir_file, signal) || infrared_parse_raw(ir_file, signal);
41
- // if(success) {
42
- // infrared_signal_transmit(signal);
43
- // } else {
44
- // ACTION_SET_ERROR("IR: Error sending signal");
45
- // }
46
- // infrared_signal_free(signal);
49
+ App * app = context ;
50
+ const char * file_name = furi_string_get_cstr (action_path );
51
+ InfraredSignal * signal = infrared_signal_alloc ();
52
+
53
+ FlipperFormat * fff_data_file = flipper_format_file_alloc (app -> storage );
54
+ FuriString * temp_str ;
55
+ temp_str = furi_string_alloc ();
56
+ uint32_t temp_data32 ;
57
+
58
+ // https://developer.flipper.net/flipperzero/doxygen/infrared_file_format.html
59
+ // TODO: Right now we only read the first signal found in the file. Add support
60
+ // for reading any signal by 'name'
61
+ do {
62
+ if (!flipper_format_file_open_existing (fff_data_file , file_name )) {
63
+ ACTION_SET_ERROR ("IR: Error opening %s" , file_name );
64
+ break ;
65
+ }
66
+ if (!flipper_format_read_header (fff_data_file , temp_str , & temp_data32 )) {
67
+ ACTION_SET_ERROR ("IR: Missing or incorrect header" );
68
+ break ;
69
+ }
70
+ if (!furi_string_cmp_str (temp_str , INFRARED_FILE_TYPE ) &&
71
+ temp_data32 == INFRARED_FILE_VERSION ) {
72
+ } else {
73
+ ACTION_SET_ERROR ("IR: File type or version mismatch" );
74
+ break ;
75
+ }
76
+ if (!flipper_format_read_string (fff_data_file , "name" , temp_str )) {
77
+ ACTION_SET_ERROR ("IR: Invalid or missing name" );
78
+ break ;
79
+ }
80
+ // FURI_LOG_I(TAG, "Reading signal %s", furi_string_get_cstr(temp_str));
81
+ if (!flipper_format_read_string (fff_data_file , "type" , temp_str )) {
82
+ ACTION_SET_ERROR ("IR: Type missing" );
83
+ break ;
84
+ }
85
+ if (!furi_string_cmp_str (temp_str , "parsed" )) {
86
+ // FURI_LOG_I(TAG, "IR File is PARSED");
87
+ signal -> is_raw = false;
88
+
89
+ if (!flipper_format_read_string (fff_data_file , "protocol" , temp_str )) {
90
+ ACTION_SET_ERROR ("IR: Invalid or missing protocol" );
91
+ break ;
92
+ }
93
+ signal -> payload .message .protocol =
94
+ infrared_get_protocol_by_name (furi_string_get_cstr (temp_str ));
95
+ if (!infrared_is_protocol_valid (signal -> payload .message .protocol )) {
96
+ ACTION_SET_ERROR ("IR: Invalid or unknown protocol" );
97
+ break ;
98
+ }
99
+
100
+ // Why do these methods exist, when the spec says the address and command
101
+ // lengths MUST be 4 bytes?
102
+
103
+ // uint8_t address_len;
104
+ // address_len = infrared_get_protocol_address_length(signal->payload.message.protocol);
105
+
106
+ // uint8_t command_len;
107
+ // command_len = infrared_get_protocol_command_length(signal->payload.message.protocol);
108
+
109
+ if (!flipper_format_read_hex (
110
+ fff_data_file , "address" , (uint8_t * )& signal -> payload .message .address , 4 )) {
111
+ ACTION_SET_ERROR ("IR: Failed to read address" );
112
+ break ;
113
+ }
114
+ if (!flipper_format_read_hex (
115
+ fff_data_file , "command" , (uint8_t * )& signal -> payload .message .command , 4 )) {
116
+ ACTION_SET_ERROR ("IR: Failed to read command" );
117
+ break ;
118
+ }
119
+
120
+ // FURI_LOG_I(
121
+ // TAG,
122
+ // "IR: Sending parsed => %s %lu %lu",
123
+ // infrared_get_protocol_name(signal->payload.message.protocol),
124
+ // signal->payload.message.address,
125
+ // signal->payload.message.command);
126
+
127
+ infrared_send (& signal -> payload .message , 1 );
128
+
129
+ } else if (!furi_string_cmp_str (temp_str , "raw" )) {
130
+ // FURI_LOG_I(TAG, "IR File is RAW");
131
+ signal -> is_raw = true;
132
+
133
+ if (!flipper_format_read_uint32 (
134
+ fff_data_file , "frequency" , & signal -> payload .raw .frequency , 1 )) {
135
+ ACTION_SET_ERROR ("IR: Failed to read frequency" );
136
+ break ;
137
+ }
138
+ if (!flipper_format_read_float (
139
+ fff_data_file , "duty_cycle" , & signal -> payload .raw .duty_cycle , 1 )) {
140
+ ACTION_SET_ERROR ("IR: Failed to read duty cycle" );
141
+ break ;
142
+ }
143
+ if (!flipper_format_get_value_count (fff_data_file , "data" , & temp_data32 )) {
144
+ ACTION_SET_ERROR ("IR: Failed to get size of data" );
145
+ break ;
146
+ }
147
+ if (temp_data32 > MAX_TIMINGS_AMOUNT ) {
148
+ ACTION_SET_ERROR ("IR: Data size exceeds limit" );
149
+ break ;
150
+ }
151
+ signal -> payload .raw .timings_size = temp_data32 ;
152
+
153
+ signal -> payload .raw .timings =
154
+ malloc (sizeof (uint32_t ) * signal -> payload .raw .timings_size );
155
+ if (!flipper_format_read_uint32 (
156
+ fff_data_file , "data" , signal -> payload .raw .timings , temp_data32 )) {
157
+ ACTION_SET_ERROR ("IR: Failed to read data" );
158
+ break ;
159
+ }
160
+
161
+ // FURI_LOG_I(
162
+ // TAG,
163
+ // "IR: Sending raw => %d timings, %lu Hz, %f",
164
+ // signal->payload.raw.timings_size,
165
+ // signal->payload.raw.frequency,
166
+ // (double)signal->payload.raw.duty_cycle);
167
+
168
+ infrared_send_raw_ext (
169
+ signal -> payload .raw .timings ,
170
+ signal -> payload .raw .timings_size ,
171
+ true,
172
+ signal -> payload .raw .frequency ,
173
+ signal -> payload .raw .duty_cycle );
174
+ } else {
175
+ ACTION_SET_ERROR ("IR: Unknown type: %s" , furi_string_get_cstr (temp_str ));
176
+ break ;
177
+ }
178
+
179
+ } while (false);
180
+
181
+ furi_string_free (temp_str );
182
+ flipper_format_free (fff_data_file );
183
+ infrared_signal_free (signal );
47
184
}
0 commit comments