baylibre-acme: Use timerfd instead of a fake pipe.
Currently baylibre-acme uses a fake pipe as the input channel required by libsigrok API and calls sleep() in the data acquisition callback to create intervals between measurements. Switch to a more elegant approach: use Linux' timerfd and set a periodic timer equal to the sampling rate. Then read the data every time the timer expires. Signed-off-by: Daniel Lezcano <daniel.lezcano@linaro.org> Signed-off-by: Bartosz Golaszewski <bgolaszewski@baylibre.com>
This commit is contained in:
parent
f9b0ab6b2d
commit
a0648b1a12
|
@ -18,6 +18,8 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "protocol.h"
|
#include "protocol.h"
|
||||||
|
#include <time.h>
|
||||||
|
#include <sys/timerfd.h>
|
||||||
|
|
||||||
SR_PRIV struct sr_dev_driver baylibre_acme_driver_info;
|
SR_PRIV struct sr_dev_driver baylibre_acme_driver_info;
|
||||||
|
|
||||||
|
@ -349,6 +351,10 @@ static int dev_acquisition_open(const struct sr_dev_inst *sdi)
|
||||||
static int dev_acquisition_start(const struct sr_dev_inst *sdi, void *cb_data)
|
static int dev_acquisition_start(const struct sr_dev_inst *sdi, void *cb_data)
|
||||||
{
|
{
|
||||||
struct dev_context *devc;
|
struct dev_context *devc;
|
||||||
|
struct itimerspec tspec = {
|
||||||
|
.it_interval = { 0, 0 },
|
||||||
|
.it_value = { 0, 0 }
|
||||||
|
};
|
||||||
|
|
||||||
(void)cb_data;
|
(void)cb_data;
|
||||||
|
|
||||||
|
@ -360,19 +366,30 @@ static int dev_acquisition_start(const struct sr_dev_inst *sdi, void *cb_data)
|
||||||
|
|
||||||
devc = sdi->priv;
|
devc = sdi->priv;
|
||||||
devc->samples_read = 0;
|
devc->samples_read = 0;
|
||||||
|
devc->samples_missed = 0;
|
||||||
if (pipe(devc->pipe_fds)) {
|
devc->timer_fd = timerfd_create(CLOCK_MONOTONIC, 0);
|
||||||
sr_err("Error setting up pipe");
|
if (devc->timer_fd < 0) {
|
||||||
|
sr_err("Error creating timer fd");
|
||||||
return SR_ERR;
|
return SR_ERR;
|
||||||
}
|
}
|
||||||
|
|
||||||
devc->channel = g_io_channel_unix_new(devc->pipe_fds[0]);
|
tspec.it_interval.tv_sec = 0;
|
||||||
|
tspec.it_interval.tv_nsec = (1000000000L / devc->samplerate);
|
||||||
|
tspec.it_value = tspec.it_interval;
|
||||||
|
|
||||||
|
if (timerfd_settime(devc->timer_fd, 0, &tspec, NULL)) {
|
||||||
|
sr_err("Failed to set timer");
|
||||||
|
close(devc->timer_fd);
|
||||||
|
return SR_ERR;
|
||||||
|
}
|
||||||
|
|
||||||
|
devc->channel = g_io_channel_unix_new(devc->timer_fd);
|
||||||
g_io_channel_set_flags(devc->channel, G_IO_FLAG_NONBLOCK, NULL);
|
g_io_channel_set_flags(devc->channel, G_IO_FLAG_NONBLOCK, NULL);
|
||||||
g_io_channel_set_encoding(devc->channel, NULL, NULL);
|
g_io_channel_set_encoding(devc->channel, NULL, NULL);
|
||||||
g_io_channel_set_buffered(devc->channel, FALSE);
|
g_io_channel_set_buffered(devc->channel, FALSE);
|
||||||
|
|
||||||
sr_session_source_add_channel(sdi->session, devc->channel,
|
sr_session_source_add_channel(sdi->session, devc->channel,
|
||||||
G_IO_IN | G_IO_ERR, 1, bl_acme_receive_data, (void *)sdi);
|
G_IO_IN | G_IO_ERR, 1000, bl_acme_receive_data, (void *)sdi);
|
||||||
|
|
||||||
/* Send header packet to the session bus. */
|
/* Send header packet to the session bus. */
|
||||||
std_session_send_df_header(sdi, LOG_PREFIX);
|
std_session_send_df_header(sdi, LOG_PREFIX);
|
||||||
|
@ -398,11 +415,15 @@ static int dev_acquisition_stop(struct sr_dev_inst *sdi, void *cb_data)
|
||||||
g_io_channel_shutdown(devc->channel, FALSE, NULL);
|
g_io_channel_shutdown(devc->channel, FALSE, NULL);
|
||||||
g_io_channel_unref(devc->channel);
|
g_io_channel_unref(devc->channel);
|
||||||
devc->channel = NULL;
|
devc->channel = NULL;
|
||||||
|
close(devc->timer_fd);
|
||||||
|
|
||||||
/* Send last packet. */
|
/* Send last packet. */
|
||||||
packet.type = SR_DF_END;
|
packet.type = SR_DF_END;
|
||||||
sr_session_send(sdi, &packet);
|
sr_session_send(sdi, &packet);
|
||||||
|
|
||||||
|
if (devc->samples_missed > 0)
|
||||||
|
sr_warn("%d samples missed", devc->samples_missed);
|
||||||
|
|
||||||
return SR_OK;
|
return SR_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -560,8 +560,8 @@ SR_PRIV void bl_acme_close_channel(struct sr_channel *ch)
|
||||||
|
|
||||||
SR_PRIV int bl_acme_receive_data(int fd, int revents, void *cb_data)
|
SR_PRIV int bl_acme_receive_data(int fd, int revents, void *cb_data)
|
||||||
{
|
{
|
||||||
uint32_t cur_time, elapsed_time, diff_time;
|
uint32_t cur_time, elapsed_time;
|
||||||
int64_t time_to_sleep;
|
uint64_t nrexpiration;
|
||||||
struct sr_datafeed_packet packet, framep;
|
struct sr_datafeed_packet packet, framep;
|
||||||
struct sr_datafeed_analog analog;
|
struct sr_datafeed_analog analog;
|
||||||
struct sr_dev_inst *sdi;
|
struct sr_dev_inst *sdi;
|
||||||
|
@ -586,17 +586,18 @@ SR_PRIV int bl_acme_receive_data(int fd, int revents, void *cb_data)
|
||||||
memset(&analog, 0, sizeof(struct sr_datafeed_analog));
|
memset(&analog, 0, sizeof(struct sr_datafeed_analog));
|
||||||
analog.data = &valf;
|
analog.data = &valf;
|
||||||
|
|
||||||
/*
|
if (read(devc->timer_fd, &nrexpiration, sizeof(nrexpiration)) < 0) {
|
||||||
* Reading from sysfs takes some time - try to keep up with samplerate.
|
sr_warn("Failed to read timer information");
|
||||||
*/
|
return TRUE;
|
||||||
if (devc->samples_read) {
|
|
||||||
cur_time = g_get_monotonic_time();
|
|
||||||
diff_time = cur_time - devc->last_sample_fin;
|
|
||||||
time_to_sleep = G_USEC_PER_SEC / devc->samplerate - diff_time;
|
|
||||||
if (time_to_sleep > 0)
|
|
||||||
g_usleep(time_to_sleep);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* We were not able to process the previous timer expiration, we are
|
||||||
|
* overloaded.
|
||||||
|
*/
|
||||||
|
if (nrexpiration > 1)
|
||||||
|
devc->samples_missed += nrexpiration - 1;
|
||||||
|
|
||||||
framep.type = SR_DF_FRAME_BEGIN;
|
framep.type = SR_DF_FRAME_BEGIN;
|
||||||
sr_session_send(cb_data, &framep);
|
sr_session_send(cb_data, &framep);
|
||||||
|
|
||||||
|
|
|
@ -65,9 +65,10 @@ struct dev_context {
|
||||||
|
|
||||||
uint32_t num_channels;
|
uint32_t num_channels;
|
||||||
uint64_t samples_read;
|
uint64_t samples_read;
|
||||||
|
uint64_t samples_missed;
|
||||||
int64_t start_time;
|
int64_t start_time;
|
||||||
int64_t last_sample_fin;
|
int64_t last_sample_fin;
|
||||||
int pipe_fds[2];
|
int timer_fd;
|
||||||
GIOChannel *channel;
|
GIOChannel *channel;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue