267 lines
7.4 KiB
C++
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;
|
|
}
|