/*
* Copyright 2017 <+YOU OR YOUR COMPANY+>.
*
* This 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 3, or (at your option)
* any later version.
*
* This software 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 this software; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street,
* Boston, MA 02110-1301, USA.
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <gnuradio/io_signature.h>
#include "my_demux_impl.h"
namespace gr {
namespace my_module_demux {
enum demux_states_t {
STATE_FIND_TRIGGER, // "Idle" state (waiting for burst)
STATE_HEADER // Copy data
};
enum out_port_indexes_t {
PORT_HEADER = 0,
PORT_INPUTDATA = 0,
PORT_TRIGGER = 1
};
my_demux::sptr
my_demux::make(
int header_len,
int items_per_symbol,
const std::string &trigger_tag_key,
unsigned int itemsize,
const float samp_rate
){
return gnuradio::get_initial_sptr(
new my_demux_impl(
header_len,
items_per_symbol,
trigger_tag_key,
itemsize,
samp_rate
)
);
}
/*
* The private constructor
*/
my_demux_impl::my_demux_impl(
int header_len,
int items_per_symbol,
const std::string &trigger_tag_key,
unsigned int itemsize,
const float samp_rate
) : gr::block("my_demux",
gr::io_signature::make2(1, 2, itemsize, sizeof(char)),
gr::io_signature::make(1, 1, itemsize)),
d_header_len(header_len),
d_items_per_symbol(items_per_symbol),
d_trigger_tag_key(pmt::string_to_symbol(trigger_tag_key)),
d_itemsize(itemsize),
d_uses_trigger_tag(!trigger_tag_key.empty()),
d_state(STATE_FIND_TRIGGER),
d_sampling_time(1.0/samp_rate)
{
if (d_header_len < 1) {
throw std::invalid_argument("Header length must be at least 1 symbol.");
}
if (d_items_per_symbol < 1 || d_itemsize < 1) {
throw std::invalid_argument("Items and symbol sizes must be at least 1.");
}
set_relative_rate(1.0);
set_output_multiple(d_items_per_symbol);
set_tag_propagation_policy(TPP_DONT);
}
/*
* Our virtual destructor.
*/
my_demux_impl::~my_demux_impl()
{
}
// forecast() depends on state:
// - When waiting for a Header, we require at least the header length
// - Otherwise, pretend this is a sync block with a decimation/interpolation
// depending on symbol size and if we output symbols or items
void
my_demux_impl::forecast (int noutput_items, gr_vector_int &ninput_items_required)
{
int n_items_reqd = 0;
if (d_state == STATE_HEADER){
n_items_reqd = d_header_len * d_items_per_symbol;
}else{
n_items_reqd = noutput_items;
}
for (unsigned int i = 0; i < ninput_items_required.size(); i++){
ninput_items_required[i] = n_items_reqd;
}
}
int
my_demux_impl::general_work (int noutput_items,
gr_vector_int &ninput_items,
gr_vector_const_void_star &input_items,
gr_vector_void_star &output_items)
{
const unsigned char *in = (const unsigned char *) input_items[PORT_INPUTDATA];
unsigned char *out_header = (unsigned char *) output_items[PORT_HEADER];
const int n_input_items = (ninput_items.size() == 2) ?
std::min(ninput_items[0], ninput_items[1]) :
ninput_items[0];
// Items read going into general_work()
const uint64_t n_items_read_base = nitems_read(PORT_INPUTDATA);
// Items read during this call to general_work()
int n_items_read = 0;
#define CONSUME_ITEMS(items_to_consume) \
consume_each(items_to_consume); \
n_items_read += (items_to_consume); \
in += (items_to_consume) * d_itemsize;
switch (d_state){
case STATE_FIND_TRIGGER:{
// Assumptions going into this state:
// - No other state was active for this call to general_work()
// - i.e. n_items_read == 0
// Start looking for a trigger after any header padding.
// The trigger offset is relative to 'in'.
// => The absolute trigger offset is on n_items_read_base + n_items_read + trigger_offset
const int max_rel_offset = n_input_items - n_items_read;
const int trigger_offset = find_trigger_signal(
max_rel_offset,
n_items_read_base + n_items_read,
(input_items.size() == 2) ?
((const unsigned char *) input_items[PORT_TRIGGER]) + n_items_read : NULL
);
if (trigger_offset < max_rel_offset){
d_state = STATE_HEADER;
}
const int items_to_consume = trigger_offset;
CONSUME_ITEMS(items_to_consume);
break;
} /* case STATE_FIND_TRIGGER */
case STATE_HEADER:{
// Assumptions going into this state:
// - The first items on `in' are the Data samples
// - So we can just copy from the beginning of `in'
// - The trigger is on item index `d_header_padding * d_items_per_symbol'
// Actions:
// - Copy the entire header to the Output port
if (check_buffers_ready(
d_header_len,
noutput_items,
d_header_len * d_items_per_symbol,
ninput_items,
n_items_read)) {
copy_n_symbols(
in,
out_header,
PORT_HEADER,
n_items_read_base + n_items_read,
d_header_len // Number of symbols to copy
);
}
const int items_to_consume = d_header_len * d_items_per_symbol;
CONSUME_ITEMS(items_to_consume);
d_state = STATE_FIND_TRIGGER;
break;
} /* case STATE_HEADER */
default:
throw std::runtime_error("invalid state");
} /* switch */
return WORK_CALLED_PRODUCE;
} /* general_work */
int
my_demux_impl::find_trigger_signal(
int max_rel_offset,
uint64_t base_offset,
const unsigned char *in_trigger
) {
int rel_offset = max_rel_offset;
if (in_trigger) {
for (int i = 0; i < max_rel_offset; i++) {
if (in_trigger[i]) {
rel_offset = i;
break;
}
}
}
return rel_offset;
} /* find_trigger_signal() */
bool
my_demux_impl::check_buffers_ready(
int output_symbols_reqd,
int noutput_items,
int input_items_reqd,
gr_vector_int &ninput_items,
int n_items_read
) {
// Check there's enough space on the output buffer
if (noutput_items < (output_symbols_reqd * d_items_per_symbol)) {
return false;
}
// Check there's enough items on the input
if (input_items_reqd > (ninput_items[0]-n_items_read)
|| (ninput_items.size() == 2 && (input_items_reqd > (ninput_items[1]-n_items_read)))) {
return false;
}
// All good
return true;
} /* check_buffers_ready */
void
my_demux_impl::copy_n_symbols(
const unsigned char *in,
unsigned char *out,
int port,
const uint64_t n_items_read_base,
int n_symbols
) {
// Copy samples
memcpy(
(void *) out,
(void *) in,
(n_symbols * d_items_per_symbol) * d_itemsize
);
// Advance write pointers
// Items to produce might actually be symbols
const int items_to_produce = n_symbols * d_items_per_symbol;
produce(port, items_to_produce);
} /* copy_n_symbols() */
} /* namespace my_module_demux */
} /* namespace gr */
/* -*- c++ -*- */
/*
* Copyright 2017 <+YOU OR YOUR COMPANY+>.
*
* This 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 3, or (at your option)
* any later version.
*
* This software 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 this software; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street,
* Boston, MA 02110-1301, USA.
*/
#ifndef INCLUDED_MY_MODULE_DEMUX_MY_DEMUX_IMPL_H
#define INCLUDED_MY_MODULE_DEMUX_MY_DEMUX_IMPL_H
#include <my_module_demux/my_demux.h>
namespace gr {
namespace my_module_demux {
class my_demux_impl : public my_demux
{
private:
int d_header_len; //!< Number of bytes per header
int d_items_per_symbol; //!< Bytes per symbol
pmt::pmt_t d_trigger_tag_key; //!< Key of trigger tag (if used)
size_t d_itemsize; //!< Bytes per item
bool d_uses_trigger_tag; //!< If a trigger tag is used
int d_state; //!< Current read state
double d_sampling_time; //!< Inverse sampling rate
int find_trigger_signal(
int max_rel_offset,
uint64_t base_offset,
const unsigned char *in_trigger
);
bool
check_buffers_ready(
int output_symbols_reqd,
int noutput_items,
int input_items_reqd,
gr_vector_int &ninput_items,
int n_items_read
);
void
copy_n_symbols(
const unsigned char *in,
unsigned char *out,
int port,
const uint64_t n_items_read_base,
int n_symbols
);
public:
my_demux_impl(int header_len, int items_per_symbol, const std::string &trigger_tag_key, unsigned int itemsize, const float samp_rate);
~my_demux_impl();
// Where all the action really happens
void forecast (int noutput_items, gr_vector_int &ninput_items_required);
int general_work(int noutput_items,
gr_vector_int &ninput_items,
gr_vector_const_void_star &input_items,
gr_vector_void_star &output_items);
};
} // namespace my_module_demux
} // namespace gr
#endif /* INCLUDED_MY_MODULE_DEMUX_MY_DEMUX_IMPL_H */
No comments:
Post a Comment