1 #ifndef __SDR_AUTOCAST_HH__
2 #define __SDR_AUTOCAST_HH__
3 
4 #include "node.hh"
5 #include "traits.hh"
6 #include "logger.hh"
7 
8 namespace sdr {
9 
10 /** This class performs some automatic casts to a certain buffer type if possible specified by
11  * the template argument. Currently only integer casts are supported. */
12 template <class Scalar>
13 class AutoCast: public SinkBase, public Source
14 {
15 public:
16   /** Constructor. */
AutoCast()17   AutoCast()
18     : SinkBase(), Source(), _buffer(), _cast(0)
19   {
20     // pass...
21   }
22 
23   /** Configures the auto cast node. */
config(const Config & src_cfg)24   virtual void config(const Config &src_cfg) {
25     // Requires buffer size, sample rate and type:
26     if ((Config::Type_UNDEFINED==src_cfg.type()) || (0==src_cfg.sampleRate()) || (0==src_cfg.bufferSize())) { return; }
27 
28     // Check type cast combination
29     if (Config::Type_s8 == Traits<Scalar>::scalarId) {
30       switch (src_cfg.type()) {
31       case Config::Type_u8:
32       case Config::Type_s8: _cast = _identity; break;
33       case Config::Type_u16:
34       case Config::Type_s16: _cast = _int16_int8; break;
35       default: break;
36       }
37     } else if (Config::Type_cs8 == Traits<Scalar>::scalarId) {
38       switch (src_cfg.type()) {
39       case Config::Type_u8: _cast = _uint8_cint8; break;
40       case Config::Type_s8: _cast = _int8_cint8; break;
41       case Config::Type_cu8: _cast = _cuint8_cint8; break;
42       case Config::Type_cs8: _cast = _identity; break;
43       case Config::Type_u16:
44       case Config::Type_s16: _cast = _int16_cint8; break;
45       default: break;
46       }
47     } else if (Config::Type_s16 == Traits<Scalar>::scalarId) {
48       switch (src_cfg.type()) {
49       case Config::Type_u8:
50       case Config::Type_s8: _cast = _int8_int16; break;
51       case Config::Type_u16:
52       case Config::Type_s16: _cast = _identity; break;
53       default: break;
54       }
55     } else if (Config::Type_cs16 == Traits<Scalar>::scalarId) {
56       switch (src_cfg.type()) {
57       case Config::Type_u8: _cast = _uint8_cint16; break;
58       case Config::Type_s8: _cast = _int8_cint16; break;
59       case Config::Type_cu8: _cast = _cuint8_cint16; break;
60       case Config::Type_cs8: _cast = _cint8_cint16; break;
61       case Config::Type_u16: _cast = _uint16_cint16; break;
62       case Config::Type_s16: _cast = _int16_cint16; break;
63       case Config::Type_cu16:
64       case Config::Type_cs16: _cast = _identity; break;
65       default: break;
66       }
67     }
68 
69     // Check if there exists a cast to the required type
70     if (0 == _cast) {
71       ConfigError err;
72       err << "AutoCast: Can not cast from type " << src_cfg.type() << " to " << Traits<Scalar>::scalarId;
73       throw err;
74     }
75 
76     // Allocate buffer
77     _buffer = Buffer<Scalar>(src_cfg.bufferSize());
78 
79     LogMessage msg(LOG_DEBUG);
80     msg << "Configure AutoCast node:" << std::endl
81         << " input type: " << src_cfg.type() << std::endl
82         << " output type: " << Traits<Scalar>::scalarId;
83     Logger::get().log(msg);
84 
85     // Propergate config
86     this->setConfig(Config(Config::typeId<Scalar>(), src_cfg.sampleRate(), src_cfg.bufferSize(), 1));
87   }
88 
handleBuffer(const RawBuffer & buffer,bool allow_overwrite)89   virtual void handleBuffer(const RawBuffer &buffer, bool allow_overwrite) {
90     // If no conversion is selected
91     if (0 == _cast) { return; }
92     // If the identity conversion is selected -> forward buffer
93     if (_identity == _cast) { this->send(buffer, allow_overwrite); return; }
94     // Otherwise cast
95     size_t bytes = _cast(buffer, _buffer);
96     this->send(RawBuffer(_buffer, 0, bytes), false);
97   }
98 
99 
100 protected:
101   /** Output buffer. */
102   Buffer<Scalar> _buffer;
103   /** Cast function. */
104   size_t (*_cast)(const RawBuffer &in, const RawBuffer &out);
105 
106 protected:
107   /** Performs no cast at all. */
_identity(const RawBuffer & in,const RawBuffer & out)108   static size_t _identity(const RawBuffer &in, const RawBuffer &out) {
109     memcpy(out.ptr(), in.data(), in.bytesLen());
110     return in.bytesLen();
111   }
112 
113   /** int16 -> int8 */
_int16_int8(const RawBuffer & in,const RawBuffer & out)114   static size_t _int16_int8(const RawBuffer &in, const RawBuffer &out) {
115     size_t N = in.bytesLen()/2;
116     for (size_t i=0; i<N; i++) {
117       reinterpret_cast<int8_t *>(out.data())[i] = reinterpret_cast<int16_t *>(in.data())[i]>>8;
118     }
119     return N;
120   }
121 
122   /** uint8 -> complex int8. */
_uint8_cint8(const RawBuffer & in,const RawBuffer & out)123   static size_t _uint8_cint8(const RawBuffer &in, const RawBuffer &out) {
124     size_t N = in.bytesLen();
125     uint8_t *values = reinterpret_cast<uint8_t *>(in.data());
126     for (size_t i=0; i<N; i++) {
127       reinterpret_cast<std::complex<int8_t> *>(out.data())[i] =
128           (int16_t(values[i])-127);
129     }
130     return 2*N;
131   }
132 
133   /** int8 -> complex int8. */
_int8_cint8(const RawBuffer & in,const RawBuffer & out)134   static size_t _int8_cint8(const RawBuffer &in, const RawBuffer &out) {
135     size_t N = in.bytesLen();
136     for (size_t i=0; i<N; i++) {
137       reinterpret_cast<std::complex<int8_t> *>(out.data())[i] = reinterpret_cast<int8_t *>(in.data())[i];
138     }
139     return 2*N;
140   }
141 
142   /** std::complex<uint8_t> -> std::complex<int8_t>. */
_cuint8_cint8(const RawBuffer & in,const RawBuffer & out)143   static size_t _cuint8_cint8(const RawBuffer &in, const RawBuffer &out) {
144     size_t N = in.bytesLen()/2;
145     std::complex<uint8_t> *values = reinterpret_cast<std::complex<uint8_t> *>(in.data());
146     for (size_t i=0; i<N; i++) {
147       reinterpret_cast<std::complex<int8_t> *>(out.data())[i] =
148           std::complex<int8_t>(int16_t(values[i].real())-127, int16_t(values[i].imag())-127);
149     }
150     return 2*N;
151   }
152 
153   /** int16 -> complex int 8. */
_int16_cint8(const RawBuffer & in,const RawBuffer & out)154   static size_t _int16_cint8(const RawBuffer &in, const RawBuffer &out) {
155     size_t N = in.bytesLen()/2;
156     for (size_t i=0; i<N; i++) {
157       reinterpret_cast<std::complex<int8_t> *>(out.data())[i] = reinterpret_cast<int16_t *>(in.data())[i]>>8;
158     }
159     return 2*N;
160   }
161 
162   /** complex int16 -> complex int 8. */
_cint16_cint8(const RawBuffer & in,const RawBuffer & out)163   static size_t _cint16_cint8(const RawBuffer &in, const RawBuffer &out) {
164     size_t N = in.bytesLen()/4;
165     std::complex<int16_t> *values = reinterpret_cast<std::complex<int16_t> *>(in.data());
166     for (size_t i=0; i<N; i++) {
167       reinterpret_cast<std::complex<int8_t> *>(out.data())[i] = std::complex<int8_t>(values[i].real()>>8, values[i].imag()>>8);
168     }
169     return 2*N;
170   }
171 
172   /** int8 -> int16. */
_int8_int16(const RawBuffer & in,const RawBuffer & out)173   static size_t _int8_int16(const RawBuffer &in, const RawBuffer &out) {
174     size_t N = in.bytesLen();
175     int8_t *values = reinterpret_cast<int8_t *>(in.data());
176     for (size_t i=0; i<N; i++) {
177       reinterpret_cast<int16_t *>(out.data())[i] = int16_t(values[i])<<8;
178     }
179     return 2*N;
180   }
181 
182   /** unsinged int8 -> complex int16. */
_uint8_cint16(const RawBuffer & in,const RawBuffer & out)183   static size_t _uint8_cint16(const RawBuffer &in, const RawBuffer &out) {
184     size_t N = in.bytesLen();
185     uint8_t *values = reinterpret_cast<uint8_t *>(in.data());
186     for (size_t i=0; i<N; i++) {
187       reinterpret_cast<std::complex<int16_t> *>(out.data())[i]
188           = std::complex<int16_t>((int16_t(values[i])-127)<<8);
189     }
190     return 4*N;
191   }
192 
193   /** int8 -> complex int16. */
_int8_cint16(const RawBuffer & in,const RawBuffer & out)194   static size_t _int8_cint16(const RawBuffer &in, const RawBuffer &out) {
195     size_t N = in.bytesLen();
196     int8_t *values = reinterpret_cast<int8_t *>(in.data());
197     for (size_t i=0; i<N; i++) {
198       reinterpret_cast<std::complex<int16_t> *>(out.data())[i]
199           = std::complex<int16_t>(int16_t(values[i])*(1<<8));
200     }
201     return 4*N;
202   }
203 
204   /** complex unsigned int8 -> complex int16. */
_cuint8_cint16(const RawBuffer & in,const RawBuffer & out)205   static size_t _cuint8_cint16(const RawBuffer &in, const RawBuffer &out) {
206     size_t N = in.bytesLen()/2;
207     std::complex<uint8_t> *values = reinterpret_cast<std::complex<uint8_t> *>(in.data());
208     for (size_t i=0; i<N; i++) {
209       reinterpret_cast<std::complex<int16_t> *>(out.data())[i] =
210           std::complex<int16_t>((int16_t(values[i].real())-127)*(1<<8),
211                                 (int16_t(values[i].imag())-127)*(1<<8));
212     }
213     return 4*N;
214   }
215 
216   /** complex int8 -> complex int16. */
_cint8_cint16(const RawBuffer & in,const RawBuffer & out)217   static size_t _cint8_cint16(const RawBuffer &in, const RawBuffer &out) {
218     size_t N = in.bytesLen()/2;
219     std::complex<int8_t> *values = reinterpret_cast<std::complex<int8_t> *>(in.data());
220     for (size_t i=0; i<N; i++) {
221       reinterpret_cast<std::complex<int16_t> *>(out.data())[i] =
222           std::complex<int16_t>(int16_t(values[i].real())*(1<<8),
223                                 int16_t(values[i].imag())*(1<<8));
224     }
225     return 4*N;
226   }
227 
228   /** uint16 -> complex int16. */
_uint16_cint16(const RawBuffer & in,const RawBuffer & out)229   static size_t _uint16_cint16(const RawBuffer &in, const RawBuffer &out) {
230     size_t N = in.bytesLen()/2;
231     uint16_t *values = reinterpret_cast<uint16_t *>(in.data());
232     for (size_t i=0; i<N; i++) {
233       reinterpret_cast<std::complex<int16_t> *>(out.data())[i]
234           = std::complex<int16_t>(int32_t(values[i])-(1<<15));
235     }
236     return 4*N;
237   }
238 
239   /** int16 -> complex int16. */
_int16_cint16(const RawBuffer & in,const RawBuffer & out)240   static size_t _int16_cint16(const RawBuffer &in, const RawBuffer &out) {
241     size_t N = in.bytesLen()/2;
242     int16_t *values = reinterpret_cast<int16_t *>(in.data());
243     for (size_t i=0; i<N; i++) {
244       reinterpret_cast<std::complex<int16_t> *>(out.data())[i] = std::complex<int16_t>(values[i]);
245     }
246     return 4*N;
247   }
248 };
249 
250 
251 }
252 #endif // __SDR_AUTOCAST_HH__
253