1 /* -*- c++ -*- */
2 /*
3  * Copyright 2004,2006,2013,2018 Free Software Foundation, Inc.
4  *
5  * This file is part of GNU Radio
6  *
7  * GNU Radio is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation; either version 3, or (at your option)
10  * any later version.
11  *
12  * GNU Radio is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with GNU Radio; see the file COPYING.  If not, write to
19  * the Free Software Foundation, Inc., 51 Franklin Street,
20  * Boston, MA 02110-1301, USA.
21  */
22 
23 
24 #ifdef HAVE_CONFIG_H
25 #include "config.h"
26 #endif
27 
28 #include "unpacked_to_packed_impl.h"
29 #include <gnuradio/io_signature.h>
30 #include <assert.h>
31 
32 namespace gr {
33 namespace blocks {
34 
35 
36 template <class T>
37 typename unpacked_to_packed<T>::sptr
make(unsigned int bits_per_chunk,endianness_t endianness)38 unpacked_to_packed<T>::make(unsigned int bits_per_chunk, endianness_t endianness)
39 {
40     return gnuradio::get_initial_sptr(
41         new unpacked_to_packed_impl<T>(bits_per_chunk, endianness));
42 }
43 
44 template <class T>
unpacked_to_packed_impl(unsigned int bits_per_chunk,endianness_t endianness)45 unpacked_to_packed_impl<T>::unpacked_to_packed_impl(unsigned int bits_per_chunk,
46                                                     endianness_t endianness)
47     : block("unpacked_to_packed",
48             io_signature::make(1, -1, sizeof(T)),
49             io_signature::make(1, -1, sizeof(T))),
50       d_bits_per_chunk(bits_per_chunk),
51       d_endianness(endianness),
52       d_index(0)
53 {
54     assert(bits_per_chunk <= d_bits_per_type);
55     assert(bits_per_chunk > 0);
56 
57     this->set_relative_rate((uint64_t)bits_per_chunk, (uint64_t)this->d_bits_per_type);
58 }
59 
60 template <class T>
~unpacked_to_packed_impl()61 unpacked_to_packed_impl<T>::~unpacked_to_packed_impl()
62 {
63 }
64 
65 template <class T>
forecast(int noutput_items,gr_vector_int & ninput_items_required)66 void unpacked_to_packed_impl<T>::forecast(int noutput_items,
67                                           gr_vector_int& ninput_items_required)
68 {
69     int input_required =
70         (int)ceil((d_index + noutput_items * 1.0 * d_bits_per_type) / d_bits_per_chunk);
71     unsigned ninputs = ninput_items_required.size();
72     for (unsigned int i = 0; i < ninputs; i++) {
73         ninput_items_required[i] = input_required;
74     }
75 }
76 
77 template <class T>
get_bit_be1(const T * in_vector,unsigned int bit_addr,unsigned int bits_per_chunk)78 unsigned int unpacked_to_packed_impl<T>::get_bit_be1(const T* in_vector,
79                                                      unsigned int bit_addr,
80                                                      unsigned int bits_per_chunk)
81 {
82     unsigned int byte_addr = (int)bit_addr / bits_per_chunk;
83     T x = in_vector[byte_addr];
84     unsigned int residue = bit_addr - byte_addr * bits_per_chunk;
85     // printf("Bit addr %d  byte addr %d  residue %d  val
86     // %d\n",bit_addr,byte_addr,residue,(x>>(bits_per_chunk-1-residue))&1);
87     return (x >> (bits_per_chunk - 1 - residue)) & 1;
88 }
89 
90 template <class T>
general_work(int noutput_items,gr_vector_int & ninput_items,gr_vector_const_void_star & input_items,gr_vector_void_star & output_items)91 int unpacked_to_packed_impl<T>::general_work(int noutput_items,
92                                              gr_vector_int& ninput_items,
93                                              gr_vector_const_void_star& input_items,
94                                              gr_vector_void_star& output_items)
95 {
96     unsigned int index_tmp = d_index;
97 
98     assert(input_items.size() == output_items.size());
99     int nstreams = input_items.size();
100 
101     for (int m = 0; m < nstreams; m++) {
102         const T* in = (T*)input_items[m];
103         T* out = (T*)output_items[m];
104         index_tmp = d_index;
105 
106         // per stream processing
107 
108         // assert((ninput_items[m]-d_index)*d_bits_per_chunk >=
109         // noutput_items*d_bits_per_type);
110 
111         switch (d_endianness) {
112 
113         case GR_MSB_FIRST:
114             for (int i = 0; i < noutput_items; i++) {
115                 T tmp = 0;
116                 for (unsigned int j = 0; j < d_bits_per_type; j++) {
117                     tmp = (tmp << 1) | get_bit_be1(in, index_tmp, d_bits_per_chunk);
118                     index_tmp++;
119                 }
120                 out[i] = tmp;
121             }
122             break;
123 
124         case GR_LSB_FIRST:
125             for (int i = 0; i < noutput_items; i++) {
126                 unsigned long tmp = 0;
127                 for (unsigned int j = 0; j < d_bits_per_type; j++) {
128                     tmp = (tmp >> 1) | (get_bit_be1(in, index_tmp, d_bits_per_chunk)
129                                         << (d_bits_per_type - 1));
130                     index_tmp++;
131                 }
132                 out[i] = tmp;
133             }
134             break;
135 
136         default:
137             assert(0);
138         }
139     }
140 
141     d_index = index_tmp;
142     this->consume_each((int)(d_index / d_bits_per_chunk));
143     d_index = d_index % d_bits_per_chunk;
144 
145     return noutput_items;
146 }
147 
148 template class unpacked_to_packed<std::uint8_t>;
149 template class unpacked_to_packed<std::int16_t>;
150 template class unpacked_to_packed<std::int32_t>;
151 } /* namespace blocks */
152 } /* namespace gr */
153