1 //
2 // Copyright 2017 Ettus Research LLC
3 // Copyright 2018 Ettus Research, a National Instruments Company
4 //
5 // SPDX-License-Identifier: GPL-3.0-or-later
6 //
7
8 #include "convert_common.hpp"
9 #include <uhd/utils/byteswap.hpp>
10 #include <type_traits>
11
12 using namespace uhd::convert;
13
14 typedef uint32_t (*tohost32_type)(uint32_t);
15
16 /* C language specification requires this to be packed
17 * (i.e., line0, line1, line2 will be in adjacent memory locations).
18 * If this was not true, we'd need compiler flags here to specify
19 * alignment/packing.
20 */
21 struct item32_sc12_3x
22 {
23 item32_t line0;
24 item32_t line1;
25 item32_t line2;
26 };
27
28 /*
29 * convert_sc12_item32_3_to_star_4 takes in 3 lines with 32 bit each
30 * and converts them 4 samples of type 'std::complex<type>'.
31 * The structure of the 3 lines is as follows:
32 * _ _ _ _ _ _ _ _
33 * |_ _ _1_ _ _|_ _|
34 * |_2_ _ _|_ _ _3_|
35 * |_ _|_ _ _4_ _ _|
36 *
37 * The numbers mark the position of one complex sample.
38 */
39 template <typename type, tohost32_type tohost>
convert_sc12_item32_3_to_star_4(const item32_sc12_3x & input,std::complex<type> & out0,std::complex<type> & out1,std::complex<type> & out2,std::complex<type> & out3,const double scalar,typename std::enable_if<std::is_floating_point<type>::value>::type * =NULL)40 void convert_sc12_item32_3_to_star_4(const item32_sc12_3x& input,
41 std::complex<type>& out0,
42 std::complex<type>& out1,
43 std::complex<type>& out2,
44 std::complex<type>& out3,
45 const double scalar,
46 typename std::enable_if<std::is_floating_point<type>::value>::type* = NULL)
47 {
48 // step 0: extract the lines from the input buffer
49 const item32_t line0 = tohost(input.line0);
50 const item32_t line1 = tohost(input.line1);
51 const item32_t line2 = tohost(input.line2);
52 const uint64_t line01 = (uint64_t(line0) << 32) | line1;
53 const uint64_t line12 = (uint64_t(line1) << 32) | line2;
54
55 // step 1: shift out and mask off the individual numbers
56 const type i0 = type(int16_t((line0 >> 16) & 0xfff0) * scalar);
57 const type q0 = type(int16_t((line0 >> 4) & 0xfff0) * scalar);
58
59 const type i1 = type(int16_t((line01 >> 24) & 0xfff0) * scalar);
60 const type q1 = type(int16_t((line1 >> 12) & 0xfff0) * scalar);
61
62 const type i2 = type(int16_t((line1 >> 0) & 0xfff0) * scalar);
63 const type q2 = type(int16_t((line12 >> 20) & 0xfff0) * scalar);
64
65 const type i3 = type(int16_t((line2 >> 8) & 0xfff0) * scalar);
66 const type q3 = type(int16_t((line2 << 4) & 0xfff0) * scalar);
67
68 // step 2: load the outputs
69 out0 = std::complex<type>(i0, q0);
70 out1 = std::complex<type>(i1, q1);
71 out2 = std::complex<type>(i2, q2);
72 out3 = std::complex<type>(i3, q3);
73 }
74
75 template <typename type, tohost32_type tohost>
convert_sc12_item32_3_to_star_4(const item32_sc12_3x & input,std::complex<type> & out0,std::complex<type> & out1,std::complex<type> & out2,std::complex<type> & out3,const double,typename std::enable_if<std::is_integral<type>::value>::type * =NULL)76 void convert_sc12_item32_3_to_star_4(const item32_sc12_3x& input,
77 std::complex<type>& out0,
78 std::complex<type>& out1,
79 std::complex<type>& out2,
80 std::complex<type>& out3,
81 const double,
82 typename std::enable_if<std::is_integral<type>::value>::type* = NULL)
83 {
84 // step 0: extract the lines from the input buffer
85 const item32_t line0 = tohost(input.line0);
86 const item32_t line1 = tohost(input.line1);
87 const item32_t line2 = tohost(input.line2);
88 const uint64_t line01 = (uint64_t(line0) << 32) | line1;
89 const uint64_t line12 = (uint64_t(line1) << 32) | line2;
90
91 // step 1: extract and load the outputs
92 out0 = std::complex<type>(line0 >> 16 & 0xfff0, line0 >> 4 & 0xfff0);
93 out1 = std::complex<type>(line01 >> 24 & 0xfff0, line1 >> 12 & 0xfff0);
94 out2 = std::complex<type>(line1 >> 0 & 0xfff0, line12 >> 20 & 0xfff0);
95 out3 = std::complex<type>(line2 >> 8 & 0xfff0, line2 << 4 & 0xfff0);
96 }
97