This repository has been archived on 2022-02-17. You can view files and clone it, but cannot push or open issues or pull requests.
op25-legacy/repeater/src/lib/repeater_pipe.cc

267 lines
7.4 KiB
C++

/* -*- c++ -*- */
/*
* Copyright 2004 Free Software Foundation, Inc.
*
* This file is part of GNU Radio
*
* GNU Radio is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* GNU Radio 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with GNU Radio; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
/*
* config.h is generated by configure. It contains the results
* of probing for features, options etc. It should be the first
* file included in your .cc file.
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <repeater_pipe.h>
#include <gr_io_signature.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
#include <errno.h>
#include <signal.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/ioctl.h>
#include <sys/time.h>
/*
* Create a new instance of repeater_pipe and return
* a boost shared_ptr. This is effectively the public constructor.
*/
repeater_pipe_sptr
repeater_make_pipe (size_t input_size, size_t output_size, const char* pathname, float io_ratio)
{
return repeater_pipe_sptr (new repeater_pipe (input_size, output_size, pathname, io_ratio));
}
/*
* The private constructor
*/
repeater_pipe::repeater_pipe (size_t input_size, size_t output_size, const char* pathname, float io_ratio)
: gr_block ("pipe",
gr_make_io_signature ((input_size>0) ? 1 : 0, (input_size>0) ? 1 : 0, input_size),
gr_make_io_signature ((output_size>0) ? 1 : 0, (output_size>0) ? 1 : 0, output_size)),
d_pid(0),
d_e_in(0),
d_e_out(0)
{
d_input_size = input_size;
d_output_size = output_size;
d_io_ratio = io_ratio;
d_pathname = pathname;
switch(input_size) {
case 0:
d_e_in = 0;
break;
case 1:
d_e_in = 1;
break;
case 2:
d_e_in = 2;
break;
case 4:
d_e_in = 3;
break;
case 8:
d_e_in = 4;
break;
default:
d_e_in = 0;
fprintf(stderr, "error: repeater_pipe: input_size invalid\n");
break;
}
switch(output_size) {
case 0:
d_e_out = 0;
break;
case 1:
d_e_out = 1;
break;
case 2:
d_e_out = 2;
break;
case 4:
d_e_out = 3;
break;
case 8:
d_e_out = 4;
break;
default:
d_e_out = 0;
fprintf(stderr, "error: repeater_pipe: output_size invalid\n");
break;
}
// parent writes to fd_in[1], reads from fd_out[0]
// child writes to fd_out[1], reads from fd_in[0]
if (pipe(pipe_fd_in) == -1) {
fprintf(stderr, "pipe: %s\n", strerror(errno));
return;
}
if (pipe(pipe_fd_out) == -1) {
fprintf(stderr, "pipe: %s\n", strerror(errno));
return;
}
pid_t pid = fork();
if (pid < 0) {
fprintf(stderr, "fork: %s\n", strerror(errno));
return;
} else if (pid == 0) { /* in child */
// close unused fd's
close(pipe_fd_in[1]);
close(pipe_fd_out[0]);
// setup stdin and stdout for child
dup2(pipe_fd_in[0], 0);
dup2(pipe_fd_out[1], 1);
// close duped fd's
close(pipe_fd_in[0]);
close(pipe_fd_out[1]);
system(d_pathname);
exit(0);
} /* end of if(in child) */
/* in parent */
d_pid = pid;
// close unused fd's
close(pipe_fd_in[0]);
close(pipe_fd_out[1]);
if (fcntl(pipe_fd_in[1], F_SETFL, O_NONBLOCK) == -1) {
fprintf(stderr, "fcntl: %s\n", strerror(errno));
return;
}
#if 1
if (fcntl(pipe_fd_out[0], F_SETFL, O_NONBLOCK) == -1) {
fprintf(stderr, "fcntl: %s\n", strerror(errno));
return;
}
#endif
}
/*
* Our virtual destructor.
*/
repeater_pipe::~repeater_pipe ()
{
if (d_pid)
kill (d_pid, SIGTERM);
}
void
repeater_pipe::forecast(int nof_output_items, gr_vector_int &nof_input_items_reqd)
{
const size_t nof_inputs = nof_input_items_reqd.size();
// const int nof_samples_reqd = (int)(d_io_ratio * nof_output_items) << 1;
const int nof_samples_reqd = d_io_ratio * nof_output_items;
std::fill(&nof_input_items_reqd[0], &nof_input_items_reqd[nof_inputs], nof_samples_reqd);
// fprintf(stderr, "forecast nout %d nin %d sr %d\n", nof_output_items, nof_inputs, nof_samples_reqd);
}
int
repeater_pipe::general_work (int noutput_items,
gr_vector_int &ninput_items,
gr_vector_const_void_star &input_items,
gr_vector_void_star &output_items)
{
unsigned char *in;
unsigned char *out;
if (d_input_size > 0)
in = (unsigned char *) input_items[0];
if (d_output_size > 0)
out = (unsigned char *) output_items[0];
static const unsigned int e_masks[] = {0, 1, 3, 0xf, 0xff};
static int tot1=0;
static int tot2=0;
struct timeval tv;
struct timezone tz;
gettimeofday(&tv, &tz);
#define min(a,b) ((a<b)?a:b)
// fprintf(stderr, "nout %d, nin[0] %d\n", noutput_items, ninput_items[0]);
//////////////////////////////////////////////////////////////////////
// first, handle parent write from gr's source to child's stdin
//////////////////////////////////////////////////////////////////////
size_t amt = noutput_items * d_input_size;
amt = min(amt, 512);
amt = ((tot1 - tot2) > 512) ? 0 : amt;
if (amt > 0) {
int rc = write(pipe_fd_in[1], in, amt);
if (rc < 0 && errno != EAGAIN) {
fprintf(stderr, "write: %d: %s\n", errno, strerror(errno));
}
if (rc > 0) {
// FIXME: handle if amt actually written not exact multiple of size
// if not, for size 2, 4, or 8, bytewise alignment would be lost
// if(rc & e_masks[d_e_in] != 0)
fprintf(stderr, "%d amt %d rc %d d_e_in %d mask %x t1 %d t2 %d nin0 %d\n", (int)tv.tv_usec, amt, rc, d_e_in, e_masks[d_e_in], tot1, tot2, ninput_items[0]);
// Tell runtime system how many input items we consumed on
// each input stream.
consume_each(rc >> (d_e_in - 1));
tot1 += rc;
}
}
//////////////////////////////////////////////////////////////////////
// do parent read from child's stdout to gr's sink
//////////////////////////////////////////////////////////////////////
amt = noutput_items * d_output_size;
#if 1
size_t read_amt=0;
if (ioctl(pipe_fd_out[0], FIONREAD, &read_amt) == -1) {
fprintf(stderr, "ioctl: %s\n", strerror(errno));
return 0;
}
// fprintf(stderr, "%d read_amt: %d noutput %d\n", (int)tv.tv_usec, read_amt, noutput_items);
amt = min(amt, read_amt);
#endif
if (amt > 0) {
int rc = read(pipe_fd_out[0], out, amt);
if (rc < 0 && errno != EAGAIN)
fprintf(stderr, "read: %s\n", strerror(errno));
if (rc < 0)
return 0;
else if (rc == 0) { /* if EOF */
fprintf(stderr, "tot1 %d tot2 %d\n", tot1, tot2);
return 0;
}
// FIXME: check that amt is exact multiple of size
// if not, for size 2, 4, or 8, bytewise alignment would be lost
// if (rc & e_masks[d_e_out] != 0)
fprintf(stderr, "%d amt %d rc %d d_e_out %d mask %x t1 %d t2 %d\n", (int)tv.tv_usec, amt, rc, d_e_in, e_masks[d_e_in], tot1, tot2);
tot2 += rc;
return rc >> (d_e_out - 1);
}
// Tell runtime system how many output items we produced.
return 0;
}