]> sigrok.org Git - libsigrokdecode.git/blob - irmp/irmp-main-sharedlib.c
cbf239a3341eab68975eb4f419a1856fb6bcecdb
[libsigrokdecode.git] / irmp / irmp-main-sharedlib.c
1 /*
2  * irmp-main-sharedlib.c
3  *
4  * Copyright (c) 2009-2019 Frank Meyer - frank(at)fli4l.de
5  * Copyright (c) 2009-2019 RenĂ© Staffen - r.staffen(at)gmx.de
6  *
7  * This program is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation; either version 2 of the License, or
10  * (at your option) any later version.
11  */
12
13 /*
14  * Declare the library's public API first. Prove it's consistent and
15  * complete as a standalone header file.
16  */
17 #include "irmp-main-sharedlib.h"
18
19 #include <stdlib.h>
20 #include <string.h>
21
22 /*
23  * Include the IRMP core logic. This approach is required because of
24  * static variables which hold internal state. The core logic started
25  * as an MCU project where resources are severely constrained.
26  *
27  * This libsigrokdecode incarnation of IRMP will always be used in the
28  * UNIX_OR_WINDOWS configuration. But libtool(1) breaks the upstream
29  * logic's platform detection. Check reliably available conditions here
30  * and provide expected symbols to the library, to reduce changes to the
31  * upstream project.
32  */
33 #if defined _WIN32
34 #  if !defined WIN32
35 #    define WIN32
36 #  endif
37 #else
38 #  if !defined unix
39 #    define unix
40 #  endif
41 #endif
42 #include "irmp.h"
43 #include "irmp.c"
44
45 /*
46  * The remaining source code implements the PC library, which accepts
47  * sample data from API callers, and provides detector results as they
48  * become available after seeing input data.
49  *
50  * TODO items, known constraints
51  * - Counters in the IRMP core logic and the library wrapper are 32bit
52  *   only. In the strictest sense they only need to cover the span of
53  *   an IR frame. In the PC side library case they need to cover "a
54  *   detection phase", which happens to be under calling applications'
55  *   control. The library shall not mess with the core's internal state,
56  *   and may even not be able to reliably tell whether detection of a
57  *   frame started in the core. Fortunately the 32bit counters only roll
58  *   over after some 2.5 days at the highest available sample rate. So
59  *   this limitation is not a blocker.
60  * - The IRMP core keeps internal state in global variables. Which is
61  *   appropriate for MCU configurations. For the PC library use case
62  *   this constraint prevents concurrency, only a single data stream
63  *   can get processed at any time. This limitation can get addressed
64  *   later, making the flexible and featureful IRMP detection available
65  *   in the first place is considered highly desirable, and is a great
66  *   improvement in itself.
67  * - The detection of IR frames from buffered data is both limited and
68  *   complicated at the same time. The routine re-uses the caller's
69  *   buffer _and_ internal state across multiple calls. Thus windowed
70  *   operation over a larger set of input data is not available. The
71  *   API lacks a flag for failed detection, thus applications need to
72  *   guess from always returned payload data.
73  * - Is it worth adding a "detection in progress" query to the API? Is
74  *   the information available to the library wrapper, and reliable?
75  *   Shall applications be able to "poll" the started, and completed
76  *   state for streamed operation including periodic state resets which
77  *   won't interfere with pending detection? (It's assumed that this
78  *   is only required when feeding single values in individual calls is
79  *   found to be rather expensive.
80  * - Some of the result data reflects the core's internal presentation
81  *   while there is no declaration in the library's API. This violates
82  *   API layers, and needs to get addressed properly.
83  * - The IRMP core logic (strictly speaking the specific details of
84  *   preprocessor symbol arrangements in the current implementation)
85  *   appears to assume either to run on an MCU and capture IR signals
86  *   from hardware pins, falling back to AVR if no other platform got
87  *   detected. Or assumes to run on a (desktop) PC, and automatically
88  *   enables ANALYZE mode, which results in lots of stdio traffic that
89  *   is undesirable for application code which uses the shared library
90  *   for strict detection purposes but no further analysis or research.
91  *   It's a pity that turning off ANALYZE switches to MCU mode, and that
92  *   keeping ANALYZE enabled but silencing the output is rather messy
93  *   and touches the innards of the core logic (the irmp.c source file
94  *   and its dependency header files).
95  */
96
97 #ifndef ARRAY_SIZE
98 #  define ARRAY_SIZE(x) (sizeof(x) / sizeof(x[0]))
99 #endif
100
101 static uint32_t s_end_sample;
102
103 IRMP_DLLEXPORT uint32_t irmp_get_sample_rate(void)
104 {
105         return F_INTERRUPTS;
106 }
107
108 IRMP_DLLEXPORT void irmp_reset_state(void)
109 {
110         size_t i;
111         IRMP_DATA data;
112
113         /*
114          * Provide the equivalent of 1s idle input signal level. Then
115          * drain any potentially accumulated result data. This clears
116          * the internal decoder state.
117          */
118         IRMP_PIN = 0xff;
119         i = F_INTERRUPTS;
120         while (i-- > 0) {
121                 (void)irmp_ISR();
122         }
123         (void)irmp_get_data(&data);
124
125         time_counter = 0;
126         s_startBitSample = 0;
127         s_curSample = 0;
128         s_end_sample = 0;
129
130         /*
131          * TODO This is not the most appropriate location to control the
132          * core logic's verbosity. But out of the public set of library
133          * routines this call is closest to some initialization routine.
134          * The query for compile time parameter values is optional, the
135          * state reset is not. Multiple verbosity setup activities in
136          * the same program lifetime won't harm. This HACK is clearly
137          * preferrable over more fiddling with core logic innards, or
138          * the introduction of yet another DLL routine.
139          */
140         silent = 1;
141         verbose = 0;
142 }
143
144 IRMP_DLLEXPORT int irmp_add_one_sample(int sample)
145 {
146         int ret;
147
148         IRMP_PIN = sample ? 0xff : 0x00;
149         ret = irmp_ISR() ? 1 : 0;
150         s_end_sample = s_curSample++;
151         return ret;
152 }
153
154 IRMP_DLLEXPORT int irmp_get_result_data(struct irmp_result_data *data)
155 {
156         IRMP_DATA d;
157
158         if (!irmp_get_data(&d))
159                 return 0;
160
161         data->address = d.address;
162         data->command = d.command;
163         data->protocol = d.protocol;
164         data->protocol_name = irmp_get_protocol_name(d.protocol);
165         data->flags = d.flags;
166         data->start_sample = s_startBitSample;
167         data->end_sample = s_end_sample;
168         return 1;
169 }
170
171 #if WITH_IRMP_DETECT_BUFFER
172 IRMP_DLLEXPORT struct irmp_result_data irmp_detect_buffer(const uint8_t *buff, size_t len)
173 {
174         struct irmp_result_data ret;
175
176         memset(&ret, 0, sizeof(ret));
177         while (s_curSample < len) {
178                 if (irmp_add_one_sample(buff[s_curSample])) {
179                         irmp_get_result_data(&ret);
180                         return ret;
181                 }
182         }
183         return ret;
184 }
185 #endif
186
187 IRMP_DLLEXPORT const char *irmp_get_protocol_name(uint32_t protocol)
188 {
189         const char *name;
190
191         if (protocol >= ARRAY_SIZE(irmp_protocol_names))
192                 return "unknown";
193         name = irmp_protocol_names[protocol];
194         if (!name || !*name)
195                 return "unknown";
196         return name;
197 }