1
0
mirror of https://github.com/gnss-sdr/gnss-sdr synced 2024-12-14 12:10:34 +00:00

Added unpack_2bit_samples

This is a generic gnuradio block for handling 2 bit samples packed into
bytes or shorts. It can handle big or little endian ordering of the
samples within the byte, as well as big or little endian ordering of the
bytes within a short.

This is a utility function for a generic sample source which will be
able to handle all of these cases for both real and complex signals.
This commit is contained in:
Cillian O'Driscoll 2015-09-30 22:15:00 +01:00
parent 62b77c3f73
commit 3ca18df229
3 changed files with 300 additions and 0 deletions

View File

@ -22,6 +22,7 @@ set(SIGNAL_SOURCE_GR_BLOCKS_SOURCES
unpack_byte_2bit_cpx_samples.cc
unpack_intspir_1bit_samples.cc
rtl_tcp_signal_source_c.cc
unpack_2bit_samples.cc
)
include_directories(

View File

@ -0,0 +1,184 @@
/*!
* \file unpack_2bit_samples.cc
*
* \brief Unpacks 2 bit samples that have been packed into bytes or shorts
* \author Cillian O'Driscoll cillian.odriscoll (at) gmail.com
* -------------------------------------------------------------------------
*
* Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors)
*
* GNSS-SDR is a software defined Global Navigation
* Satellite Systems receiver
*
* This file is part of GNSS-SDR.
*
* GNSS-SDR 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 of the License, or
* (at your option) any later version.
*
* GNSS-SDR 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 GNSS-SDR. If not, see <http://www.gnu.org/licenses/>.
*
* -------------------------------------------------------------------------
*/
#include "unpack_2bit_samples.h"
#include <iostream>
#include <gnuradio/io_signature.h>
struct byte_2bit_struct
{
signed sample_0:2; // <- 2 bits wide only
signed sample_1:2; // <- 2 bits wide only
signed sample_2:2; // <- 2 bits wide only
signed sample_3:2; // <- 2 bits wide only
};
union byte_and_samples
{
int8_t byte;
byte_2bit_struct samples;
};
bool systemIsBigEndian()
{
union
{
uint32_t i;
char c[4];
} test_int = {0x01020304};
return test_int.c[0] == 1;
}
bool systemBytesAreBigEndian()
{
byte_and_samples b;
b.byte = static_cast< int8_t>(0x1B);
return b.samples.sample_0 == 0x3;
}
void swapEndianness( int8_t const *in, std::vector< int8_t > &out, size_t item_size, unsigned int ninput_items )
{
unsigned int i;
unsigned int j = 0;
int k = 0;
size_t skip = item_size - 1;
for( i = 0; i < ninput_items; ++i )
{
k = j + skip;
while( k >= 0 )
{
out[j++] = in[k--];
}
}
}
unpack_2bit_samples_sptr make_unpack_2bit_samples( bool big_endian_bytes,
size_t item_size,
bool big_endian_items )
{
return unpack_2bit_samples_sptr(
new unpack_2bit_samples( big_endian_bytes,
item_size,
big_endian_items )
);
}
unpack_2bit_samples::unpack_2bit_samples( bool big_endian_bytes,
size_t item_size,
bool big_endian_items )
: sync_interpolator("unpack_2bit_samples",
gr::io_signature::make(1, 1, item_size),
gr::io_signature::make(1, 1, sizeof(char)),
4*item_size ), // we make 4 bytes out for every byte in
big_endian_bytes_(big_endian_bytes),
item_size_(item_size),
big_endian_items_(big_endian_items),
swap_endian_items_(false)
{
bool big_endian_system = systemIsBigEndian();
// Only swap the item bytes if the item size > 1 byte and the system
// endianess is not the same as the item endianness:
swap_endian_items_ = ( item_size_ > 1 ) &&
( big_endian_system != big_endian_items);
bool big_endian_bytes_system = systemBytesAreBigEndian();
swap_endian_bytes_ = ( big_endian_bytes_system != big_endian_bytes_ );
}
unpack_2bit_samples::~unpack_2bit_samples()
{}
int unpack_2bit_samples::work(int noutput_items,
gr_vector_const_void_star &input_items,
gr_vector_void_star &output_items)
{
signed char const *in = (signed char const *)input_items[0];
int8_t *out = (int8_t*)output_items[0];
size_t ninput_bytes = noutput_items/4;
size_t ninput_items = ninput_bytes/item_size_;
// Handle endian swap if needed
if( swap_endian_items_ )
{
work_buffer_.resize( ninput_bytes );
swapEndianness( in, work_buffer_, item_size_, ninput_items );
in = const_cast< signed char const *> ( &work_buffer_[0] );
}
// Here the in pointer can be interpreted as a stream of bytes to be
// converted. But we now have two possibilities:
// 1) The samples in a byte are in big endian order
// 2) The samples in a byte are in little endian order
byte_and_samples raw_byte;
int n = 0;
if( swap_endian_bytes_ )
{
for(int i = 0; i < ninput_bytes; ++i)
{
// Read packed input sample (1 byte = 4 samples)
raw_byte.byte = in[i];
out[n++] = (int8_t)( 2*raw_byte.samples.sample_3 + 1 );
out[n++] = (int8_t)( 2*raw_byte.samples.sample_2 + 1 );
out[n++] = (int8_t)( 2*raw_byte.samples.sample_1 + 1 );
out[n++] = (int8_t)( 2*raw_byte.samples.sample_0 + 1 );
}
}
else
{
for( int i = 0; i < ninput_bytes; ++i )
{
// Read packed input sample (1 byte = 4 samples)
raw_byte.byte = in[i];
out[n++] = (int8_t)( 2*raw_byte.samples.sample_0 + 1 );
out[n++] = (int8_t)( 2*raw_byte.samples.sample_1 + 1 );
out[n++] = (int8_t)( 2*raw_byte.samples.sample_2 + 1 );
out[n++] = (int8_t)( 2*raw_byte.samples.sample_3 + 1 );
}
}
return noutput_items;
}

View File

@ -0,0 +1,115 @@
/*!
* \file unpack_2bit_samples.h
*
* \brief Unpacks 2 bit samples
* samples may be packed in any of the following ways:
* 1) Into bytes [ item == byte ]
* 1a) Big endian ordering within the byte
* 1b) Little endian ordering within the byte
* 2) Into shorts [ item == short ]
* 2a) Big endian ordering of bytes, big endian within the byte
* 2b) Big endian ordering of bytes, little endian within the byte
* 2c) Little endian ordering of bytes, big endian within the byte
* 2d) Little endian ordering of bytes, little endian within the byte
*
* Within a byte the two possibilities look like this:
* 7 6 5 4 3 2 1 0 : Bit number
* x_n,1 x_n,0 x_n+1,1 x_n+1,0 x_n+2,1 x_n+2,0 x_n+3,1 x_n+3,0 : Little endian
* x_n+3,1 x_n+3,0 x_n+2,1 x_n+2,0 x_n+1,0 x_n+1,0 x_n,1 x_n, 0 : Big Endian
*
* For a short (uint16_t) the bytes are either transmitted as follows:
*
* 1 0 : Byte number
* Byte_n Byte_n+1 : Little endian
* Byte_n+1 Byte_n : Bit endian
*
* The two bit values are assumed to have the following mapping:
*
* x_1 x_0 Value
* 0 0 +1
* 0 1 +3
* 1 0 -3
* 1 1 -1
*
* Letting x denote the two's complement interpretation of x_1 x_0, then:
*
* Value = 2*x + 1
*
* We want to output the data in the order:
*
* Value_0, Value_1, Value_2, ..., Value_n, Value_n+1, Value_n+2, ...
*
* \author Cillian O'Driscoll cillian.odriscoll (at) gmail . com
* -------------------------------------------------------------------------
*
* Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors)
*
* GNSS-SDR is a software defined Global Navigation
* Satellite Systems receiver
*
* This file is part of GNSS-SDR.
*
* GNSS-SDR 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 of the License, or
* (at your option) any later version.
*
* GNSS-SDR 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 GNSS-SDR. If not, see <http://www.gnu.org/licenses/>.
*
* -------------------------------------------------------------------------
*/
#ifndef GNSS_SDR_UNPACK_2BIT_SAMPLES_H
#define GNSS_SDR_UNPACK_2BIT_SAMPLES_H
#include <gnuradio/sync_interpolator.h>
class unpack_2bit_samples;
typedef boost::shared_ptr<unpack_2bit_samples> unpack_2bit_samples_sptr;
unpack_2bit_samples_sptr make_unpack_2bit_samples( bool big_endian_bytes,
size_t item_size,
bool big_endian_items );
/*!
* \brief This class takes 2 bit samples that have been packed into bytes or
* shorts as input and generates a byte for each sample. It generates eight
* times as much data as is input (every two bits become 16 bits)
*/
class unpack_2bit_samples: public gr::sync_interpolator
{
private:
friend unpack_2bit_samples_sptr
make_unpack_2bit_samples_sptr( bool big_endian_bytes,
size_t item_size,
bool big_endian_items );
public:
unpack_2bit_samples( bool big_endianBytes,
size_t item_size,
bool big_endian_items );
~unpack_2bit_samples();
int work (int noutput_items,
gr_vector_const_void_star &input_items,
gr_vector_void_star &output_items);
private:
bool big_endian_bytes_;
size_t item_size_;
bool big_endian_items_;
bool swap_endian_items_;
bool swap_endian_bytes_;
std::vector< int8_t > work_buffer_;
};
#endif