]> sigrok.org Git - libsigrok.git/blob - src/sw_limits.c
output/csv: use intermediate time_t var, silence compiler warning
[libsigrok.git] / src / sw_limits.c
1 /*
2  * This file is part of the libsigrok project.
3  *
4  * Copyright (C) 2016 Lars-Peter Clausen <lars@metafoo.de>
5  *
6  * This program is free software: you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation, either version 3 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
18  */
19
20 /**
21  * @file
22  * Software limits helper functions
23  */
24
25 #include "config.h"
26
27 #include <ctype.h>
28 #include <libsigrok/libsigrok.h>
29 #include <stdint.h>
30 #include <stdio.h>
31 #include <string.h>
32
33 #include "libsigrok-internal.h"
34
35 #define LOG_PREFIX "sw_limits"
36
37 /**
38  * Initialize a software limit instance
39  *
40  * Must be called before any other operations are performed on a struct
41  * sr_sw_limits and should typically be called after the data structure has been
42  * allocated.
43  *
44  * @param limits the software limit instance to initialize
45  */
46 SR_PRIV void sr_sw_limits_init(struct sr_sw_limits *limits)
47 {
48         memset(limits, 0, sizeof(*limits));
49 }
50
51 /**
52  * Get software limit configuration
53  *
54  * Retrieve the currently configured software limit for the specified key.
55  * Should be called from the drivers config_get() callback.
56  *
57  * @param limits software limit instance
58  * @param key config item key
59  * @param data config item data
60  *
61  * @return SR_ERR_NA if @p key is not a supported limit, SR_OK otherwise
62  */
63 SR_PRIV int sr_sw_limits_config_get(const struct sr_sw_limits *limits,
64         uint32_t key, GVariant **data)
65 {
66         switch (key) {
67         case SR_CONF_LIMIT_SAMPLES:
68                 *data = g_variant_new_uint64(limits->limit_samples);
69                 break;
70         case SR_CONF_LIMIT_FRAMES:
71                 *data = g_variant_new_uint64(limits->limit_frames);
72                 break;
73         case SR_CONF_LIMIT_MSEC:
74                 *data = g_variant_new_uint64(limits->limit_msec / 1000);
75                 break;
76         default:
77                 return SR_ERR_NA;
78         }
79
80         return SR_OK;
81 }
82
83 /**
84  * Set software limit configuration
85  *
86  * Configure software limit for the specified key. Should be called from the
87  * drivers config_set() callback.
88  *
89  * @param limits software limit instance
90  * @param key config item key
91  * @param data config item data
92  *
93  * @return SR_ERR_NA if @p key is not a supported limit, SR_OK otherwise
94  */
95 SR_PRIV int sr_sw_limits_config_set(struct sr_sw_limits *limits,
96         uint32_t key, GVariant *data)
97 {
98         switch (key) {
99         case SR_CONF_LIMIT_SAMPLES:
100                 limits->limit_samples = g_variant_get_uint64(data);
101                 break;
102         case SR_CONF_LIMIT_FRAMES:
103                 limits->limit_frames = g_variant_get_uint64(data);
104                 break;
105         case SR_CONF_LIMIT_MSEC:
106                 limits->limit_msec = g_variant_get_uint64(data) * 1000;
107                 break;
108         default:
109                 return SR_ERR_NA;
110         }
111
112         return SR_OK;
113 }
114
115 /**
116  * Start a new data acquisition session
117  *
118  * Resets the internal accounting for all software limits. Usually should be
119  * called from the drivers acquisition_start() callback.
120  *
121  * @param limits software limits instance
122  */
123 SR_PRIV void sr_sw_limits_acquisition_start(struct sr_sw_limits *limits)
124 {
125         limits->samples_read = 0;
126         limits->frames_read = 0;
127         limits->start_time = g_get_monotonic_time();
128 }
129
130 /**
131  * Check if any of the configured software limits has been reached
132  *
133  * Usually should be called at the end of the drivers work function after all
134  * processing has been done.
135  *
136  * @param limits software limits instance
137  *
138  * @returns TRUE if any of the software limits has been reached and the driver
139  *               should stop data acquisition, otherwise FALSE.
140  */
141 SR_PRIV gboolean sr_sw_limits_check(struct sr_sw_limits *limits)
142 {
143         if (limits->limit_samples) {
144                 if (limits->samples_read >= limits->limit_samples) {
145                         sr_dbg("Requested number of samples (%" PRIu64
146                                ") reached.", limits->limit_samples);
147                         return TRUE;
148                 }
149         }
150
151         if (limits->limit_frames) {
152                 if (limits->frames_read >= limits->limit_frames) {
153                         sr_dbg("Requested number of frames (%" PRIu64
154                                ") reached.", limits->limit_frames);
155                         return TRUE;
156                 }
157         }
158
159         if (limits->limit_msec && limits->start_time) {
160                 guint64 now;
161                 now = g_get_monotonic_time();
162                 if (now > limits->start_time &&
163                         now - limits->start_time > limits->limit_msec) {
164                         sr_dbg("Requested sampling time (%" PRIu64
165                                "ms) reached.", limits->limit_msec / 1000);
166                         return TRUE;
167                 }
168         }
169
170         return FALSE;
171 }
172
173 /**
174  * Get remaining counts until software limits are reached.
175  *
176  * This routine fills in those C language variables which callers
177  * requested, and provides the remaining value until a specified limit
178  * would be reached.
179  *
180  * The @ref sr_sw_limits_config_get() routine is suitable for rare
181  * configuration calls and interfaces nicely with Glib data types. The
182  * @ref sr_sw_limits_check() routine only provides a weak "exceeded"
183  * result. This @ref sr_sw_limits_get_remain() routine is suitable for
184  * additional checks and more eager limits enforcement in (potentially
185  * tight) acquisition code paths. Hardware compression may result in
186  * rather large "overshoots" when checks are done only late.
187  *
188  * @param[in] limits software limit instance
189  * @param[out] samples remaining samples count until the limit is reached
190  * @param[out] frames remaining frames count until the limit is reached
191  * @param[out] msecs remaining milliseconds until the limit is reached
192  * @param[out] exceeded whether configured limits were reached before
193  *
194  * @return SR_ERR_* upon error, SR_OK otherwise
195  */
196 SR_PRIV int sr_sw_limits_get_remain(const struct sr_sw_limits *limits,
197         uint64_t *samples, uint64_t *frames, uint64_t *msecs,
198         gboolean *exceeded)
199 {
200
201         if (!limits)
202                 return SR_ERR_ARG;
203
204         if (exceeded)
205                 *exceeded = FALSE;
206
207         if (samples) do {
208                 *samples = 0;
209                 if (!limits->limit_samples)
210                         break;
211                 if (limits->samples_read >= limits->limit_samples) {
212                         if (exceeded)
213                                 *exceeded = TRUE;
214                         break;
215                 }
216                 *samples = limits->limit_samples - limits->samples_read;
217         } while (0);
218
219         if (frames) do {
220                 *frames = 0;
221                 if (!limits->limit_frames)
222                         break;
223                 if (limits->frames_read >= limits->limit_frames) {
224                         if (exceeded)
225                                 *exceeded = TRUE;
226                         break;
227                 }
228                 *frames = limits->limit_frames - limits->frames_read;
229         } while (0);
230
231         if (msecs) do {
232                 guint64 now, elapsed, remain;
233
234                 *msecs = 0;
235                 if (!limits->limit_msec)
236                         break;
237                 if (!limits->start_time)
238                         break;
239                 now = g_get_monotonic_time();
240                 if (now < limits->start_time)
241                         break;
242                 elapsed = now - limits->start_time;
243                 if (elapsed >= limits->limit_msec) {
244                         if (exceeded)
245                                 *exceeded = TRUE;
246                         break;
247                 }
248                 remain = limits->limit_msec - elapsed;
249                 *msecs = remain / 1000;
250         } while (0);
251
252         return SR_OK;
253 }
254
255 /**
256  * Update the amount of samples that have been read
257  *
258  * Update the amount of samples that have been read in the current data
259  * acquisition run. For each invocation @p samples_read will be accumulated and
260  * once the configured sample limit has been reached sr_sw_limits_check() will
261  * return TRUE.
262  *
263  * @param limits software limits instance
264  * @param samples_read the amount of samples that have been read
265  */
266 SR_PRIV void sr_sw_limits_update_samples_read(struct sr_sw_limits *limits,
267         uint64_t samples_read)
268 {
269         limits->samples_read += samples_read;
270 }
271
272 /**
273  * Update the amount of frames that have been read
274  *
275  * Update the amount of frames that have been read in the current data
276  * acquisition run. For each invocation @p frames_read will be accumulated and
277  * once the configured frame limit has been reached sr_sw_limits_check() will
278  * return TRUE.
279  *
280  * @param limits software limits instance
281  * @param frames_read the amount of frames that have been read
282  */
283 SR_PRIV void sr_sw_limits_update_frames_read(struct sr_sw_limits *limits,
284         uint64_t frames_read)
285 {
286         limits->frames_read += frames_read;
287 }