From 42c03de385e4eeb94fe852a1ab2fc00ac6f38366 Mon Sep 17 00:00:00 2001 From: Sylvain Munaut Date: Sun, 5 Apr 2015 11:30:20 +0200 Subject: rtfwk: Create a new rxfwk subdir to contain the 'RealTime framework' files So that other apps can re-use it. Note that it's not part of the gmr1 lib proper and so include files are in that dir and not installed. Signed-off-by: Sylvain Munaut --- configure.ac | 1 + src/Makefile.am | 5 +- src/gmr1_rx_live.c | 4 +- src/ringbuf.c | 141 -------------------- src/ringbuf.h | 86 ------------ src/rtfwk/Makefile.am | 8 ++ src/rtfwk/ringbuf.c | 141 ++++++++++++++++++++ src/rtfwk/ringbuf.h | 86 ++++++++++++ src/rtfwk/sa_file.c | 115 ++++++++++++++++ src/rtfwk/sa_file.h | 30 +++++ src/rtfwk/sampbuf.c | 358 ++++++++++++++++++++++++++++++++++++++++++++++++++ src/rtfwk/sampbuf.h | 111 ++++++++++++++++ src/sa_file.c | 115 ---------------- src/sa_file.h | 30 ----- src/sampbuf.c | 358 -------------------------------------------------- src/sampbuf.h | 111 ---------------- 16 files changed, 855 insertions(+), 845 deletions(-) delete mode 100644 src/ringbuf.c delete mode 100644 src/ringbuf.h create mode 100644 src/rtfwk/Makefile.am create mode 100644 src/rtfwk/ringbuf.c create mode 100644 src/rtfwk/ringbuf.h create mode 100644 src/rtfwk/sa_file.c create mode 100644 src/rtfwk/sa_file.h create mode 100644 src/rtfwk/sampbuf.c create mode 100644 src/rtfwk/sampbuf.h delete mode 100644 src/sa_file.c delete mode 100644 src/sa_file.h delete mode 100644 src/sampbuf.c delete mode 100644 src/sampbuf.h diff --git a/configure.ac b/configure.ac index 5fc0560..1211ca5 100644 --- a/configure.ac +++ b/configure.ac @@ -51,6 +51,7 @@ AC_OUTPUT( src/Makefile src/codec/Makefile src/l1/Makefile + src/rtfwk/Makefile src/sdr/Makefile Makefile Doxyfile diff --git a/src/Makefile.am b/src/Makefile.am index 601ea86..844bc46 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -1,4 +1,4 @@ -SUBDIRS = codec l1 sdr +SUBDIRS = codec l1 rtfwk sdr AM_CPPFLAGS = $(all_includes) -I$(top_srcdir)/include -I$(top_builddir) AM_CFLAGS = -Wall $(LIBOSMOCORE_CFLAGS) $(LIBOSMODSP_CFLAGS) @@ -10,9 +10,10 @@ gmr1_rx_LDADD = $(top_builddir)/src/l1/libgmr1-l1.a \ $(top_builddir)/src/sdr/libgmr1-sdr.a \ $(LIBOSMOCORE_LIBS) $(LIBOSMODSP_LIBS) $(FFTW3F_LIBS) -gmr1_rx_live_SOURCES = gmr1_rx_live.c gsmtap.c ringbuf.c sa_file.c sampbuf.c +gmr1_rx_live_SOURCES = gmr1_rx_live.c gsmtap.c gmr1_rx_live_LDADD = $(top_builddir)/src/l1/libgmr1-l1.a \ $(top_builddir)/src/sdr/libgmr1-sdr.a \ + $(top_builddir)/src/rtfwk/libgmr1-rtfwk.a \ $(LIBOSMOCORE_LIBS) $(LIBOSMODSP_LIBS) $(FFTW3F_LIBS) gmr1_rach_gen_SOURCES = gmr1_rach_gen.c diff --git a/src/gmr1_rx_live.c b/src/gmr1_rx_live.c index b3254d9..1c66288 100644 --- a/src/gmr1_rx_live.c +++ b/src/gmr1_rx_live.c @@ -44,8 +44,8 @@ #include #include -#include "sampbuf.h" -#include "sa_file.h" +#include "rtfwk/sampbuf.h" +#include "rtfwk/sa_file.h" struct app_state diff --git a/src/ringbuf.c b/src/ringbuf.c deleted file mode 100644 index 64604fb..0000000 --- a/src/ringbuf.c +++ /dev/null @@ -1,141 +0,0 @@ -/* Ring Buffer implementation */ - -/* (C) 2012 by Sylvain Munaut - * All Rights Reserved - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as published by - * the Free Software Foundation; either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see . - */ - -#include -#include -#include -#include - -#include -#include -#include - -#include "ringbuf.h" - - -static int -_osmo_rb_create_file(off_t len) -{ - char path[] = "/dev/shm/osmo-rb-XXXXXX"; - mode_t oum; - int fd, rv; - - /* Make sure only user can use temp file */ - oum = umask(0777); - - /* Create temporary file */ - fd = mkstemp(path); - if (fd < 0) - return -errno; - - /* Restore umask */ - umask(oum); - - /* Remove file */ - rv = unlink(path); - if (rv) { - close(fd); - return -errno; - } - - /* Adjust size */ - rv = ftruncate(fd, len); - if (rv < 0) { - close(fd); - return -errno; - } - - return fd; -} - -static void * -_osmo_rb_mmap_file(int fd, off_t len) -{ - void *base, *p; - - base = mmap(NULL, len << 1, PROT_NONE, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0); - if (base == MAP_FAILED) - return NULL; - - p = mmap(base, len, PROT_READ | PROT_WRITE, MAP_FIXED | MAP_SHARED, fd, 0); - if (p != base) - return NULL; - - p = mmap(base + len, len, PROT_READ | PROT_WRITE, MAP_FIXED | MAP_SHARED, fd, 0); - if (p != (base + len)) - return NULL; - - return base; -} - -int -osmo_rb_init(struct osmo_ringbuf *rb, unsigned int len) -{ - int fd, rv = 0; - - memset(rb, 0x00, sizeof(struct osmo_ringbuf)); - - rb->len = len; - - fd = _osmo_rb_create_file(len); - if (fd < 0) - return fd; - - rb->base = _osmo_rb_mmap_file(fd, len); - if (!rb->base) - rv = -errno; - - close(fd); - - return rv; -} - -void -osmo_rb_deinit(struct osmo_ringbuf *rb) -{ - munmap(rb->base, rb->len); - munmap(rb->base + rb->len, rb->len); - munmap(rb->base, rb->len << 1); -} - -struct osmo_ringbuf * -osmo_rb_alloc(unsigned int len) -{ - struct osmo_ringbuf *rb; - - rb = malloc(sizeof(struct osmo_ringbuf)); - if (!rb) - return NULL; - - if (osmo_rb_init(rb, len)) { - free(rb); - return NULL; - } - - return rb; -} - -void -osmo_rb_free(struct osmo_ringbuf *rb) -{ - if (rb) { - osmo_rb_deinit(rb); - free(rb); - } -} diff --git a/src/ringbuf.h b/src/ringbuf.h deleted file mode 100644 index bd7060a..0000000 --- a/src/ringbuf.h +++ /dev/null @@ -1,86 +0,0 @@ -/* Ring Buffer implementation */ - -/* (C) 2012 by Sylvain Munaut - * All Rights Reserved - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as published by - * the Free Software Foundation; either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see . - */ - -#ifndef __OSMO_RINGBUF_H__ -#define __OSMO_RINGBUF_H__ - - -struct osmo_ringbuf -{ - /* Memory zone */ - void *base; /*!< Base pointer */ - unsigned int len; /*!< Length in bytes */ - - /* Pointers */ - unsigned int ri; /*!< Read index */ - unsigned int wi; /*!< Write index */ -}; - - -int osmo_rb_init(struct osmo_ringbuf *rb, unsigned int len); -void osmo_rb_deinit(struct osmo_ringbuf *rb); -struct osmo_ringbuf *osmo_rb_alloc(unsigned int len); -void osmo_rb_free(struct osmo_ringbuf *rb); - - -static inline void -osmo_rb_clear(struct osmo_ringbuf *rb) -{ - rb->wi = 0; - rb->ri = 0; -} - -static inline unsigned int -osmo_rb_used_bytes(struct osmo_ringbuf *rb) -{ - return (rb->wi - rb->ri + rb->len) % rb->len; -} - -static inline unsigned int -osmo_rb_free_bytes(struct osmo_ringbuf *rb) -{ - return rb->len - osmo_rb_used_bytes(rb) - 1; -} - -static inline void * -osmo_rb_write_ptr(struct osmo_ringbuf *rb) -{ - return rb->base + rb->wi; -} - -static inline void * -osmo_rb_read_ptr(struct osmo_ringbuf *rb) -{ - return rb->base + rb->ri; -} - -static inline void -osmo_rb_write_advance(struct osmo_ringbuf *rb, unsigned int bytes) -{ - rb->wi = (rb->wi + bytes) % rb->len; -} - -static inline void -osmo_rb_read_advance(struct osmo_ringbuf *rb, unsigned int bytes) -{ - rb->ri = (rb->ri + bytes) % rb->len; -} - - -#endif /* __OSMO_RINGBUF_H__ */ diff --git a/src/rtfwk/Makefile.am b/src/rtfwk/Makefile.am new file mode 100644 index 0000000..cba617c --- /dev/null +++ b/src/rtfwk/Makefile.am @@ -0,0 +1,8 @@ +AM_CPPFLAGS = $(all_includes) -I$(top_srcdir)/include -I$(top_builddir) +AM_CFLAGS = -Wall $(LIBOSMOCORE_CFLAGS) $(LIBOSMODSP_CFLAGS) +AM_LDFLAGS = $(LIBOSMOCORE_LIBS) $(LIBOSMODSP_LIBS) $(FFTW3F_LIBS) + +noinst_LIBRARIES = libgmr1-rtfwk.a + +libgmr1_rtfwk_a_SOURCES = \ + ringbuf.c sa_file.c sampbuf.c diff --git a/src/rtfwk/ringbuf.c b/src/rtfwk/ringbuf.c new file mode 100644 index 0000000..64604fb --- /dev/null +++ b/src/rtfwk/ringbuf.c @@ -0,0 +1,141 @@ +/* Ring Buffer implementation */ + +/* (C) 2012 by Sylvain Munaut + * All Rights Reserved + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +#include +#include +#include +#include + +#include +#include +#include + +#include "ringbuf.h" + + +static int +_osmo_rb_create_file(off_t len) +{ + char path[] = "/dev/shm/osmo-rb-XXXXXX"; + mode_t oum; + int fd, rv; + + /* Make sure only user can use temp file */ + oum = umask(0777); + + /* Create temporary file */ + fd = mkstemp(path); + if (fd < 0) + return -errno; + + /* Restore umask */ + umask(oum); + + /* Remove file */ + rv = unlink(path); + if (rv) { + close(fd); + return -errno; + } + + /* Adjust size */ + rv = ftruncate(fd, len); + if (rv < 0) { + close(fd); + return -errno; + } + + return fd; +} + +static void * +_osmo_rb_mmap_file(int fd, off_t len) +{ + void *base, *p; + + base = mmap(NULL, len << 1, PROT_NONE, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0); + if (base == MAP_FAILED) + return NULL; + + p = mmap(base, len, PROT_READ | PROT_WRITE, MAP_FIXED | MAP_SHARED, fd, 0); + if (p != base) + return NULL; + + p = mmap(base + len, len, PROT_READ | PROT_WRITE, MAP_FIXED | MAP_SHARED, fd, 0); + if (p != (base + len)) + return NULL; + + return base; +} + +int +osmo_rb_init(struct osmo_ringbuf *rb, unsigned int len) +{ + int fd, rv = 0; + + memset(rb, 0x00, sizeof(struct osmo_ringbuf)); + + rb->len = len; + + fd = _osmo_rb_create_file(len); + if (fd < 0) + return fd; + + rb->base = _osmo_rb_mmap_file(fd, len); + if (!rb->base) + rv = -errno; + + close(fd); + + return rv; +} + +void +osmo_rb_deinit(struct osmo_ringbuf *rb) +{ + munmap(rb->base, rb->len); + munmap(rb->base + rb->len, rb->len); + munmap(rb->base, rb->len << 1); +} + +struct osmo_ringbuf * +osmo_rb_alloc(unsigned int len) +{ + struct osmo_ringbuf *rb; + + rb = malloc(sizeof(struct osmo_ringbuf)); + if (!rb) + return NULL; + + if (osmo_rb_init(rb, len)) { + free(rb); + return NULL; + } + + return rb; +} + +void +osmo_rb_free(struct osmo_ringbuf *rb) +{ + if (rb) { + osmo_rb_deinit(rb); + free(rb); + } +} diff --git a/src/rtfwk/ringbuf.h b/src/rtfwk/ringbuf.h new file mode 100644 index 0000000..bd7060a --- /dev/null +++ b/src/rtfwk/ringbuf.h @@ -0,0 +1,86 @@ +/* Ring Buffer implementation */ + +/* (C) 2012 by Sylvain Munaut + * All Rights Reserved + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +#ifndef __OSMO_RINGBUF_H__ +#define __OSMO_RINGBUF_H__ + + +struct osmo_ringbuf +{ + /* Memory zone */ + void *base; /*!< Base pointer */ + unsigned int len; /*!< Length in bytes */ + + /* Pointers */ + unsigned int ri; /*!< Read index */ + unsigned int wi; /*!< Write index */ +}; + + +int osmo_rb_init(struct osmo_ringbuf *rb, unsigned int len); +void osmo_rb_deinit(struct osmo_ringbuf *rb); +struct osmo_ringbuf *osmo_rb_alloc(unsigned int len); +void osmo_rb_free(struct osmo_ringbuf *rb); + + +static inline void +osmo_rb_clear(struct osmo_ringbuf *rb) +{ + rb->wi = 0; + rb->ri = 0; +} + +static inline unsigned int +osmo_rb_used_bytes(struct osmo_ringbuf *rb) +{ + return (rb->wi - rb->ri + rb->len) % rb->len; +} + +static inline unsigned int +osmo_rb_free_bytes(struct osmo_ringbuf *rb) +{ + return rb->len - osmo_rb_used_bytes(rb) - 1; +} + +static inline void * +osmo_rb_write_ptr(struct osmo_ringbuf *rb) +{ + return rb->base + rb->wi; +} + +static inline void * +osmo_rb_read_ptr(struct osmo_ringbuf *rb) +{ + return rb->base + rb->ri; +} + +static inline void +osmo_rb_write_advance(struct osmo_ringbuf *rb, unsigned int bytes) +{ + rb->wi = (rb->wi + bytes) % rb->len; +} + +static inline void +osmo_rb_read_advance(struct osmo_ringbuf *rb, unsigned int bytes) +{ + rb->ri = (rb->ri + bytes) % rb->len; +} + + +#endif /* __OSMO_RINGBUF_H__ */ diff --git a/src/rtfwk/sa_file.c b/src/rtfwk/sa_file.c new file mode 100644 index 0000000..37e910e --- /dev/null +++ b/src/rtfwk/sa_file.c @@ -0,0 +1,115 @@ +/* File source/sink for use with Sample Buffer */ + +/* (C) 2012 by Sylvain Munaut + * All Rights Reserved + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +#include +#include + +#include "sampbuf.h" + + +#define MAX_CHUNK_SIZE (1 << 14) /* 128k samples = 1 Mo */ + + +struct sa_file_priv { + FILE *fh; +}; + +static int +sa_file_src_init(struct sample_actor *sc, void *params) +{ + struct sa_file_priv *p = sc->priv; + const char *filename = params; + + p->fh = fopen(filename, "rb"); + if (!p->fh) { + fprintf(stderr, "[!] File Source: Failed to open input file '%s'\n", filename); + perror("fopen"); + return -errno; + } + + return 0; +} + +static int +sa_file_sink_init(struct sample_actor *sc, void *params) +{ + struct sa_file_priv *p = sc->priv; + const char *filename = params; + + p->fh = fopen(filename, "wb"); + if (!p->fh) { + fprintf(stderr, "[!] File Sink: Failed to open output file '%s'\n", filename); + perror("fopen"); + return -errno; + } + + return 0; +} + +static void +sa_file_fini(struct sample_actor *sc) +{ + struct sa_file_priv *p = sc->priv; + fclose(p->fh); +} + +static int +sa_file_src_work(struct sample_actor *sc, + float complex *data, unsigned int len) +{ + struct sa_file_priv *p = sc->priv; + size_t rv; + + if (len > MAX_CHUNK_SIZE) + len = MAX_CHUNK_SIZE; + + rv = fread(data, sizeof(float complex), len, p->fh); + + return rv > 0 ? rv : -1; +} + +static int +sa_file_sink_work(struct sample_actor *sc, + float complex *data, unsigned int len) +{ + struct sa_file_priv *p = sc->priv; + size_t rv; + + if (len > MAX_CHUNK_SIZE) + len = MAX_CHUNK_SIZE; + + rv = fwrite(data, sizeof(float complex), len, p->fh); + + return rv > 0 ? rv : -1; +} + + +const struct sample_actor_desc sa_file_src = { + .init = sa_file_src_init, + .fini = sa_file_fini, + .work = sa_file_src_work, + .priv_size = sizeof(struct sa_file_priv), +}; + +const struct sample_actor_desc sa_file_sink = { + .init = sa_file_sink_init, + .fini = sa_file_fini, + .work = sa_file_sink_work, + .priv_size = sizeof(struct sa_file_priv), +}; diff --git a/src/rtfwk/sa_file.h b/src/rtfwk/sa_file.h new file mode 100644 index 0000000..e65301a --- /dev/null +++ b/src/rtfwk/sa_file.h @@ -0,0 +1,30 @@ +/* File source/sink for use with Sample Buffer */ + +/* (C) 2012 by Sylvain Munaut + * All Rights Reserved + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +#ifndef __SA_FILE_H__ +#define __SA_FILE_H__ + + +#include "sampbuf.h" + +extern const struct sample_actor_desc sa_file_src; +extern const struct sample_actor_desc sa_file_sink; + + +#endif /* __SA_FILE_H__ */ diff --git a/src/rtfwk/sampbuf.c b/src/rtfwk/sampbuf.c new file mode 100644 index 0000000..93db857 --- /dev/null +++ b/src/rtfwk/sampbuf.c @@ -0,0 +1,358 @@ +/* Sample Buffer with producer / consummer model */ + +/* (C) 2012 by Sylvain Munaut + * All Rights Reserved + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +#include +#include +#include +#include +#include + +#include + +#include "ringbuf.h" +#include "sampbuf.h" + + +/* ------------------------------------------------------------------------ */ +/* Sample Actor */ +/* ------------------------------------------------------------------------ */ + +struct sample_actor * +sact_alloc(const struct sample_actor_desc *desc, void *params) +{ + struct sample_actor *sact; + int rv; + + sact = calloc(1, sizeof(struct sample_actor)); + if (!sact) + return NULL; + + INIT_LLIST_HEAD(&sact->list); + + sact->desc = desc; + + if (desc->priv_size > 0) { + sact->priv = calloc(1, desc->priv_size); + if (!sact->priv) + goto err; + } + + rv = sact->desc->init(sact, params); + if (rv) + goto err; + + return sact; + +err: + free(sact->priv); + free(sact); + return NULL; +} + +void +sact_free(struct sample_actor *sact) +{ + if (sact) { + sact->desc->fini(sact); + if (sact->desc->priv_size > 0) + free(sact->priv); + free(sact); + } +} + + +/* ------------------------------------------------------------------------ */ +/* Sample Buffer */ +/* ------------------------------------------------------------------------ */ + +struct sample_buf * +sbuf_alloc(int n_chans) +{ + struct sample_buf *sbuf; + int i; + + sbuf = calloc(1, sizeof(struct sample_buf)); + if (!sbuf) + return NULL; + + sbuf->n_chans = n_chans; + + for (i=0; iconsumers[i]); + + sbuf->rb[i] = osmo_rb_alloc(RB_LEN); + if (!sbuf->rb[i]) { + sbuf_free(sbuf); + return NULL; + } + } + + return sbuf; +} + +void +sbuf_free(struct sample_buf *sbuf) +{ + int i; + + if (!sbuf) + return; + + for (i=0; in_chans; i++) + { + sact_free(sbuf->producer[i]); + + /* FIXME release consumers */ + + osmo_rb_free(sbuf->rb[i]); + } + + free(sbuf); +} + + +struct sample_actor * +sbuf_set_producer(struct sample_buf *sbuf, int chan_id, + const struct sample_actor_desc *desc, void *params) +{ + struct sample_actor *sact = NULL; + + sact_free(sbuf->producer[chan_id]); + + if (desc) { + sact = sact_alloc(desc, params); + if (!sact) + return NULL; + + sact->time = sbuf->chan_wtime[chan_id]; + } + + sbuf->producer[chan_id] = sact; + + return sact; +} + +struct sample_actor * +sbuf_add_consumer(struct sample_buf *sbuf, int chan_id, + const struct sample_actor_desc *desc, void *params) +{ + struct sample_actor *sact; + + sact = sact_alloc(desc, params); + if (!sact) + return NULL; + + sact->time = sbuf->chan_rtime[chan_id]; + + llist_add(&sact->list, &sbuf->consumers[chan_id]); + + return sact; +} + + +#define WORK_CHUNK (1 << 17) /* 128k samples */ + +static int +_sbuf_chan_produce(struct sample_buf *sbuf, int chan_id) +{ + struct sample_actor *sact; + float complex *data; + int rv, free; + + /* Check free space */ + free = osmo_rb_free_bytes(sbuf->rb[chan_id]) / sizeof(float complex); + if (free < WORK_CHUNK) + return 0; + + /* Get producer */ + sact = sbuf->producer[chan_id]; + if (!sact) + return 0; + + /* Get where to write */ + data = osmo_rb_write_ptr(sbuf->rb[chan_id]); + + /* Do some work */ + rv = sact->desc->work(sact, data, WORK_CHUNK); + + /* If nothing was done, return directly */ + if (!rv) + return 0; + + /* If < 0, then this producer is done */ + if (rv < 0) { + sbuf_set_producer(sbuf, chan_id, NULL, NULL); + return 0; + } + + /* Update state */ + osmo_rb_write_advance(sbuf->rb[chan_id], sizeof(float complex) * rv); + + sact->time += rv; + sbuf->chan_wtime[chan_id] += rv; + + return 1; +} + +static int +_sbuf_produce(struct sample_buf *sbuf) +{ + int i; + int work_done = 0; + + for (i=0; in_chans; i++) + work_done |= _sbuf_chan_produce(sbuf, i); + + return work_done; +} + +static int +_sbuf_chan_consume(struct sample_buf *sbuf, int chan_id) +{ + struct sample_actor *sact, *tmp; + float complex *data; + uint64_t rtime; + int used, rv; + int work_done = 0; + + /* Check available data */ + used = osmo_rb_used_bytes(sbuf->rb[chan_id]) / sizeof(float complex); + + /* Get where to write & matchine timestamp */ + data = osmo_rb_read_ptr(sbuf->rb[chan_id]); + rtime = sbuf->chan_rtime[chan_id]; + + /* Scan all consumers */ + llist_for_each_entry_safe(sact, tmp, &sbuf->consumers[chan_id], list) + { + int adv = sact->time - rtime; + + /* Can we do anything ? */ + if (used == adv) + continue; + + /* Do some work */ + rv = sact->desc->work(sact, &data[adv], used - adv); + + /* If nothing was done, ... next */ + if (!rv) + continue; + + /* If < 0, then this consumer is done */ + if (rv < 0) { + llist_del(&sact->list); + sact_free(sact); + continue; + } + + /* Update state */ + sact->time += rv; + + work_done = 1; + } + + /* If we did no work and no producer left, we remove all consumers */ + if (!work_done && !sbuf->producer[chan_id]) { + llist_for_each_entry_safe(sact, tmp, &sbuf->consumers[chan_id], list) + { + llist_del(&sact->list); + sact_free(sact); + } + } + + return work_done; +} + +static int +_sbuf_consume(struct sample_buf *sbuf) +{ + int i, found; + uint64_t rtime; + int work_done = 0; + + /* Consume data */ + for (i=0; in_chans; i++) + work_done |= _sbuf_chan_consume(sbuf, i); + + /* Find time up to where we can discard */ + found = 0; + + for (i=0; in_chans; i++) + { + struct sample_actor *sact, *tmp; + + llist_for_each_entry_safe(sact, tmp, &sbuf->consumers[i], list) + { + if (!found || (rtime > sact->time)) { + rtime = sact->time; + found = 1; + } + } + } + + /* Actually discard */ + for (i=0; in_chans; i++) { + int discard_bytes = (rtime - sbuf->chan_rtime[i]) * sizeof(float complex); + if (osmo_rb_used_bytes(sbuf->rb[i]) >= discard_bytes) + osmo_rb_read_advance(sbuf->rb[i], discard_bytes); + else + osmo_rb_clear(sbuf->rb[i]); + sbuf->chan_rtime[i] = rtime; + } + + return work_done; +} + +void +sbuf_work(struct sample_buf *sbuf) +{ + int i, rv; + int has_produced, has_consumed; + int has_producers, has_consumers; + + while (1) { + /* Produce / Consume */ + has_produced = _sbuf_produce(sbuf); + + has_consumed = 0; + do { + rv = _sbuf_consume(sbuf); + has_consumed |= rv; + } while (rv); + + /* Check if there is any producers left */ + has_producers = 0; + for (i=0; in_chans; i++) + has_producers |= (sbuf->producer[i] != NULL); + + /* Check if there is any consumer left */ + for (i=0; in_chans; i++) + if (!llist_empty(&sbuf->consumers[i])) + break; + has_consumers = (i != sbuf->n_chans); + + /* Check exit conditions */ + if (!has_consumers) + break; + + if (!has_consumed && !has_producers) + break; + } +} diff --git a/src/rtfwk/sampbuf.h b/src/rtfwk/sampbuf.h new file mode 100644 index 0000000..d7fe23b --- /dev/null +++ b/src/rtfwk/sampbuf.h @@ -0,0 +1,111 @@ +/* Sample Buffer with producer / consummer model */ + +/* (C) 2012 by Sylvain Munaut + * All Rights Reserved + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +#ifndef __SAMPBUF_H__ +#define __SAMPBUF_H__ + + +#include +#include + +#include + +#include "ringbuf.h" + + +/* Sample Actor */ +/* ------------ */ + +struct sample_actor; + +struct sample_actor_desc { + int (*init)(struct sample_actor *sc, void *params); + void (*fini)(struct sample_actor *sc); + int (*work)(struct sample_actor *sc, + float complex *data, unsigned int len); + int priv_size; +}; + +struct sample_actor { + /* List */ + struct llist_head list; + + /* Desc */ + const struct sample_actor_desc *desc; + + /* State tracking */ + uint64_t time; + + /* Private data */ + void *priv; +}; + + +struct sample_actor * +sact_alloc(const struct sample_actor_desc *desc, void *params); + +void +sact_free(struct sample_actor *sact); + + +/* Sample Buffer */ +/* ------------- */ + +#define RB_LEN (1 << 24) /* 16 Mb */ +#define MAX_CHANS 10 + +struct sample_buf { + /* Channels */ + int n_chans; + + /* Underlying storage */ + struct osmo_ringbuf *rb[MAX_CHANS]; + + /* Time/Sample tracking */ + uint64_t chan_wtime[MAX_CHANS]; + uint64_t chan_rtime[MAX_CHANS]; + + /* Producer */ + struct sample_actor *producer[MAX_CHANS]; + + /* Consumers */ + struct llist_head consumers[MAX_CHANS]; +}; + + +struct sample_buf * +sbuf_alloc(int n_chans); + +void +sbuf_free(struct sample_buf *sbuf); + + +struct sample_actor * +sbuf_set_producer(struct sample_buf *sbuf, int chan_id, + const struct sample_actor_desc *desc, void *params); + +struct sample_actor * +sbuf_add_consumer(struct sample_buf *sbuf, int chan_id, + const struct sample_actor_desc *desc, void *params); + + +void sbuf_work(struct sample_buf *sbuf); + + +#endif /* __SAMPBUF_H__ */ diff --git a/src/sa_file.c b/src/sa_file.c deleted file mode 100644 index 37e910e..0000000 --- a/src/sa_file.c +++ /dev/null @@ -1,115 +0,0 @@ -/* File source/sink for use with Sample Buffer */ - -/* (C) 2012 by Sylvain Munaut - * All Rights Reserved - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as published by - * the Free Software Foundation; either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see . - */ - -#include -#include - -#include "sampbuf.h" - - -#define MAX_CHUNK_SIZE (1 << 14) /* 128k samples = 1 Mo */ - - -struct sa_file_priv { - FILE *fh; -}; - -static int -sa_file_src_init(struct sample_actor *sc, void *params) -{ - struct sa_file_priv *p = sc->priv; - const char *filename = params; - - p->fh = fopen(filename, "rb"); - if (!p->fh) { - fprintf(stderr, "[!] File Source: Failed to open input file '%s'\n", filename); - perror("fopen"); - return -errno; - } - - return 0; -} - -static int -sa_file_sink_init(struct sample_actor *sc, void *params) -{ - struct sa_file_priv *p = sc->priv; - const char *filename = params; - - p->fh = fopen(filename, "wb"); - if (!p->fh) { - fprintf(stderr, "[!] File Sink: Failed to open output file '%s'\n", filename); - perror("fopen"); - return -errno; - } - - return 0; -} - -static void -sa_file_fini(struct sample_actor *sc) -{ - struct sa_file_priv *p = sc->priv; - fclose(p->fh); -} - -static int -sa_file_src_work(struct sample_actor *sc, - float complex *data, unsigned int len) -{ - struct sa_file_priv *p = sc->priv; - size_t rv; - - if (len > MAX_CHUNK_SIZE) - len = MAX_CHUNK_SIZE; - - rv = fread(data, sizeof(float complex), len, p->fh); - - return rv > 0 ? rv : -1; -} - -static int -sa_file_sink_work(struct sample_actor *sc, - float complex *data, unsigned int len) -{ - struct sa_file_priv *p = sc->priv; - size_t rv; - - if (len > MAX_CHUNK_SIZE) - len = MAX_CHUNK_SIZE; - - rv = fwrite(data, sizeof(float complex), len, p->fh); - - return rv > 0 ? rv : -1; -} - - -const struct sample_actor_desc sa_file_src = { - .init = sa_file_src_init, - .fini = sa_file_fini, - .work = sa_file_src_work, - .priv_size = sizeof(struct sa_file_priv), -}; - -const struct sample_actor_desc sa_file_sink = { - .init = sa_file_sink_init, - .fini = sa_file_fini, - .work = sa_file_sink_work, - .priv_size = sizeof(struct sa_file_priv), -}; diff --git a/src/sa_file.h b/src/sa_file.h deleted file mode 100644 index e65301a..0000000 --- a/src/sa_file.h +++ /dev/null @@ -1,30 +0,0 @@ -/* File source/sink for use with Sample Buffer */ - -/* (C) 2012 by Sylvain Munaut - * All Rights Reserved - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as published by - * the Free Software Foundation; either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see . - */ - -#ifndef __SA_FILE_H__ -#define __SA_FILE_H__ - - -#include "sampbuf.h" - -extern const struct sample_actor_desc sa_file_src; -extern const struct sample_actor_desc sa_file_sink; - - -#endif /* __SA_FILE_H__ */ diff --git a/src/sampbuf.c b/src/sampbuf.c deleted file mode 100644 index 93db857..0000000 --- a/src/sampbuf.c +++ /dev/null @@ -1,358 +0,0 @@ -/* Sample Buffer with producer / consummer model */ - -/* (C) 2012 by Sylvain Munaut - * All Rights Reserved - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as published by - * the Free Software Foundation; either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see . - */ - -#include -#include -#include -#include -#include - -#include - -#include "ringbuf.h" -#include "sampbuf.h" - - -/* ------------------------------------------------------------------------ */ -/* Sample Actor */ -/* ------------------------------------------------------------------------ */ - -struct sample_actor * -sact_alloc(const struct sample_actor_desc *desc, void *params) -{ - struct sample_actor *sact; - int rv; - - sact = calloc(1, sizeof(struct sample_actor)); - if (!sact) - return NULL; - - INIT_LLIST_HEAD(&sact->list); - - sact->desc = desc; - - if (desc->priv_size > 0) { - sact->priv = calloc(1, desc->priv_size); - if (!sact->priv) - goto err; - } - - rv = sact->desc->init(sact, params); - if (rv) - goto err; - - return sact; - -err: - free(sact->priv); - free(sact); - return NULL; -} - -void -sact_free(struct sample_actor *sact) -{ - if (sact) { - sact->desc->fini(sact); - if (sact->desc->priv_size > 0) - free(sact->priv); - free(sact); - } -} - - -/* ------------------------------------------------------------------------ */ -/* Sample Buffer */ -/* ------------------------------------------------------------------------ */ - -struct sample_buf * -sbuf_alloc(int n_chans) -{ - struct sample_buf *sbuf; - int i; - - sbuf = calloc(1, sizeof(struct sample_buf)); - if (!sbuf) - return NULL; - - sbuf->n_chans = n_chans; - - for (i=0; iconsumers[i]); - - sbuf->rb[i] = osmo_rb_alloc(RB_LEN); - if (!sbuf->rb[i]) { - sbuf_free(sbuf); - return NULL; - } - } - - return sbuf; -} - -void -sbuf_free(struct sample_buf *sbuf) -{ - int i; - - if (!sbuf) - return; - - for (i=0; in_chans; i++) - { - sact_free(sbuf->producer[i]); - - /* FIXME release consumers */ - - osmo_rb_free(sbuf->rb[i]); - } - - free(sbuf); -} - - -struct sample_actor * -sbuf_set_producer(struct sample_buf *sbuf, int chan_id, - const struct sample_actor_desc *desc, void *params) -{ - struct sample_actor *sact = NULL; - - sact_free(sbuf->producer[chan_id]); - - if (desc) { - sact = sact_alloc(desc, params); - if (!sact) - return NULL; - - sact->time = sbuf->chan_wtime[chan_id]; - } - - sbuf->producer[chan_id] = sact; - - return sact; -} - -struct sample_actor * -sbuf_add_consumer(struct sample_buf *sbuf, int chan_id, - const struct sample_actor_desc *desc, void *params) -{ - struct sample_actor *sact; - - sact = sact_alloc(desc, params); - if (!sact) - return NULL; - - sact->time = sbuf->chan_rtime[chan_id]; - - llist_add(&sact->list, &sbuf->consumers[chan_id]); - - return sact; -} - - -#define WORK_CHUNK (1 << 17) /* 128k samples */ - -static int -_sbuf_chan_produce(struct sample_buf *sbuf, int chan_id) -{ - struct sample_actor *sact; - float complex *data; - int rv, free; - - /* Check free space */ - free = osmo_rb_free_bytes(sbuf->rb[chan_id]) / sizeof(float complex); - if (free < WORK_CHUNK) - return 0; - - /* Get producer */ - sact = sbuf->producer[chan_id]; - if (!sact) - return 0; - - /* Get where to write */ - data = osmo_rb_write_ptr(sbuf->rb[chan_id]); - - /* Do some work */ - rv = sact->desc->work(sact, data, WORK_CHUNK); - - /* If nothing was done, return directly */ - if (!rv) - return 0; - - /* If < 0, then this producer is done */ - if (rv < 0) { - sbuf_set_producer(sbuf, chan_id, NULL, NULL); - return 0; - } - - /* Update state */ - osmo_rb_write_advance(sbuf->rb[chan_id], sizeof(float complex) * rv); - - sact->time += rv; - sbuf->chan_wtime[chan_id] += rv; - - return 1; -} - -static int -_sbuf_produce(struct sample_buf *sbuf) -{ - int i; - int work_done = 0; - - for (i=0; in_chans; i++) - work_done |= _sbuf_chan_produce(sbuf, i); - - return work_done; -} - -static int -_sbuf_chan_consume(struct sample_buf *sbuf, int chan_id) -{ - struct sample_actor *sact, *tmp; - float complex *data; - uint64_t rtime; - int used, rv; - int work_done = 0; - - /* Check available data */ - used = osmo_rb_used_bytes(sbuf->rb[chan_id]) / sizeof(float complex); - - /* Get where to write & matchine timestamp */ - data = osmo_rb_read_ptr(sbuf->rb[chan_id]); - rtime = sbuf->chan_rtime[chan_id]; - - /* Scan all consumers */ - llist_for_each_entry_safe(sact, tmp, &sbuf->consumers[chan_id], list) - { - int adv = sact->time - rtime; - - /* Can we do anything ? */ - if (used == adv) - continue; - - /* Do some work */ - rv = sact->desc->work(sact, &data[adv], used - adv); - - /* If nothing was done, ... next */ - if (!rv) - continue; - - /* If < 0, then this consumer is done */ - if (rv < 0) { - llist_del(&sact->list); - sact_free(sact); - continue; - } - - /* Update state */ - sact->time += rv; - - work_done = 1; - } - - /* If we did no work and no producer left, we remove all consumers */ - if (!work_done && !sbuf->producer[chan_id]) { - llist_for_each_entry_safe(sact, tmp, &sbuf->consumers[chan_id], list) - { - llist_del(&sact->list); - sact_free(sact); - } - } - - return work_done; -} - -static int -_sbuf_consume(struct sample_buf *sbuf) -{ - int i, found; - uint64_t rtime; - int work_done = 0; - - /* Consume data */ - for (i=0; in_chans; i++) - work_done |= _sbuf_chan_consume(sbuf, i); - - /* Find time up to where we can discard */ - found = 0; - - for (i=0; in_chans; i++) - { - struct sample_actor *sact, *tmp; - - llist_for_each_entry_safe(sact, tmp, &sbuf->consumers[i], list) - { - if (!found || (rtime > sact->time)) { - rtime = sact->time; - found = 1; - } - } - } - - /* Actually discard */ - for (i=0; in_chans; i++) { - int discard_bytes = (rtime - sbuf->chan_rtime[i]) * sizeof(float complex); - if (osmo_rb_used_bytes(sbuf->rb[i]) >= discard_bytes) - osmo_rb_read_advance(sbuf->rb[i], discard_bytes); - else - osmo_rb_clear(sbuf->rb[i]); - sbuf->chan_rtime[i] = rtime; - } - - return work_done; -} - -void -sbuf_work(struct sample_buf *sbuf) -{ - int i, rv; - int has_produced, has_consumed; - int has_producers, has_consumers; - - while (1) { - /* Produce / Consume */ - has_produced = _sbuf_produce(sbuf); - - has_consumed = 0; - do { - rv = _sbuf_consume(sbuf); - has_consumed |= rv; - } while (rv); - - /* Check if there is any producers left */ - has_producers = 0; - for (i=0; in_chans; i++) - has_producers |= (sbuf->producer[i] != NULL); - - /* Check if there is any consumer left */ - for (i=0; in_chans; i++) - if (!llist_empty(&sbuf->consumers[i])) - break; - has_consumers = (i != sbuf->n_chans); - - /* Check exit conditions */ - if (!has_consumers) - break; - - if (!has_consumed && !has_producers) - break; - } -} diff --git a/src/sampbuf.h b/src/sampbuf.h deleted file mode 100644 index d7fe23b..0000000 --- a/src/sampbuf.h +++ /dev/null @@ -1,111 +0,0 @@ -/* Sample Buffer with producer / consummer model */ - -/* (C) 2012 by Sylvain Munaut - * All Rights Reserved - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as published by - * the Free Software Foundation; either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see . - */ - -#ifndef __SAMPBUF_H__ -#define __SAMPBUF_H__ - - -#include -#include - -#include - -#include "ringbuf.h" - - -/* Sample Actor */ -/* ------------ */ - -struct sample_actor; - -struct sample_actor_desc { - int (*init)(struct sample_actor *sc, void *params); - void (*fini)(struct sample_actor *sc); - int (*work)(struct sample_actor *sc, - float complex *data, unsigned int len); - int priv_size; -}; - -struct sample_actor { - /* List */ - struct llist_head list; - - /* Desc */ - const struct sample_actor_desc *desc; - - /* State tracking */ - uint64_t time; - - /* Private data */ - void *priv; -}; - - -struct sample_actor * -sact_alloc(const struct sample_actor_desc *desc, void *params); - -void -sact_free(struct sample_actor *sact); - - -/* Sample Buffer */ -/* ------------- */ - -#define RB_LEN (1 << 24) /* 16 Mb */ -#define MAX_CHANS 10 - -struct sample_buf { - /* Channels */ - int n_chans; - - /* Underlying storage */ - struct osmo_ringbuf *rb[MAX_CHANS]; - - /* Time/Sample tracking */ - uint64_t chan_wtime[MAX_CHANS]; - uint64_t chan_rtime[MAX_CHANS]; - - /* Producer */ - struct sample_actor *producer[MAX_CHANS]; - - /* Consumers */ - struct llist_head consumers[MAX_CHANS]; -}; - - -struct sample_buf * -sbuf_alloc(int n_chans); - -void -sbuf_free(struct sample_buf *sbuf); - - -struct sample_actor * -sbuf_set_producer(struct sample_buf *sbuf, int chan_id, - const struct sample_actor_desc *desc, void *params); - -struct sample_actor * -sbuf_add_consumer(struct sample_buf *sbuf, int chan_id, - const struct sample_actor_desc *desc, void *params); - - -void sbuf_work(struct sample_buf *sbuf); - - -#endif /* __SAMPBUF_H__ */ -- cgit v1.2.3