Skip to content

Commit f3be2ef

Browse files
committed
Add implementation for Boolean Operator blocks: AndConst, Not, Or, and Xor with corresponding tests.
Update CMakeLists to include new tests for these blocks.
1 parent 9221a43 commit f3be2ef

File tree

9 files changed

+280
-4
lines changed

9 files changed

+280
-4
lines changed
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
#ifndef ANDCONST_HPP
2+
#define ANDCONST_HPP
3+
4+
#include <concepts>
5+
#include <gnuradio-4.0/Block.hpp>
6+
#include <gnuradio-4.0/BlockRegistry.hpp>
7+
8+
namespace gr::basic {
9+
10+
GR_REGISTER_BLOCK(gr::basic::AndConst, [ uint8_t, int16_t, int32_t])
11+
12+
template<std::integral T>
13+
struct AndConst : Block<AndConst <T>> {
14+
using Description = Doc<"@brief Performs a bitwise AND operation on two inputs, producing one output stream.">;
15+
16+
PortIn<T> in;
17+
PortOut<T> out;
18+
19+
T constant = 1;
20+
21+
GR_MAKE_REFLECTABLE(AndConst, in, out, constant);
22+
23+
[[nodiscard]] constexpr T processOne(T input) const noexcept { return input & constant; }
24+
25+
// Validate constant value (restrict to 0 or 1)
26+
void settingsChanged(const property_map& /* old_settings */, const property_map& new_settings) {
27+
if (new_settings.contains("constant")) {
28+
if (constant != 0 && constant != 1) {
29+
throw std::runtime_error("Constant must be 0 or 1.");
30+
}
31+
}
32+
}
33+
};
34+
35+
} // namespace gr::basic
36+
37+
#endif // ANDCONST_HPP
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
#ifndef NOT_HPP
2+
#define NOT_HPP
3+
4+
#include <concepts>
5+
#include <gnuradio-4.0/Block.hpp>
6+
#include <gnuradio-4.0/BlockRegistry.hpp>
7+
8+
namespace gr::basic {
9+
10+
GR_REGISTER_BLOCK(gr::basic::Not, [ uint8_t, int16_t, int32_t])
11+
12+
template<std::integral T>
13+
struct Not : Block<Not<T>> {
14+
using Description = Doc<"@brief Performs a bitwise NOT operation on the input stream, producing an output stream with inverted bits.">;
15+
16+
PortIn<T> in;
17+
PortOut<T> out;
18+
19+
GR_MAKE_REFLECTABLE(Not, in, out);
20+
21+
[[nodiscard]] constexpr T processOne(T input) const noexcept { return ~input; }
22+
};
23+
24+
} // namespace gr::basic
25+
26+
#endif // NOT_HPP
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
#ifndef OR_HPP
2+
#define OR_HPP
3+
4+
#include <concepts>
5+
#include <gnuradio-4.0/Block.hpp>
6+
#include <gnuradio-4.0/BlockRegistry.hpp>
7+
8+
namespace gr::basic {
9+
10+
GR_REGISTER_BLOCK(gr::basic::Or, [ uint8_t, int16_t, int32_t ])
11+
12+
template<std::integral T>
13+
struct Or : Block<Or<T>> {
14+
using Description = Doc<"@brief Performs a bitwise OR operation on two inputs, producing one output stream.">;
15+
16+
PortIn<T> in1;
17+
PortIn<T> in2;
18+
PortOut<T> out;
19+
20+
GR_MAKE_REFLECTABLE(Or, in1, in2, out);
21+
22+
[[nodiscard]] constexpr T processOne(T input1, T input2) const noexcept { return input1 | input2; }
23+
};
24+
25+
} // namespace gr::basic
26+
27+
#endif // OR_HPP
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
#ifndef XOR_HPP
2+
#define XOR_HPP
3+
4+
#include <concepts>
5+
#include <gnuradio-4.0/Block.hpp>
6+
#include <gnuradio-4.0/BlockRegistry.hpp>
7+
8+
namespace gr::basic {
9+
10+
GR_REGISTER_BLOCK(gr::basic::Xor, [ uint8_t, int16_t, int32_t ])
11+
12+
template<std::integral T>
13+
struct Xor : Block<Xor<T>> {
14+
using Description = Doc<"@brief Performs a bitwise XOR operation on two input streams, producing one output stream.">;
15+
16+
PortIn<T> in1;
17+
PortIn<T> in2;
18+
PortOut<T> out;
19+
20+
GR_MAKE_REFLECTABLE(Xor, in1, in2, out);
21+
22+
[[nodiscard]] constexpr T processOne(T input1, T input2) const noexcept { return input1 ^ input2; }
23+
24+
};
25+
26+
} // namespace gr::basic
27+
28+
#endif // XOR_HPP

blocks/basic/test/CMakeLists.txt

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,10 @@ add_ut_test(qa_sources)
44
add_ut_test(qa_DataSink)
55
add_ut_test(qa_TriggerBlocks)
66
add_ut_test(qa_And)
7-
# add_ut_test(qa_AndConst)
8-
# add_ut_test(qa_Not)
9-
# add_ut_test(qa_Or)
10-
# add_ut_test(qa_Xor)
7+
add_ut_test(qa_AndConst)
8+
add_ut_test(qa_Not)
9+
add_ut_test(qa_Or)
10+
add_ut_test(qa_Xor)
1111

1212

1313
if(GR_ENABLE_BLOCK_REGISTRY AND INTERNAL_ENABLE_BLOCK_PLUGINS)

blocks/basic/test/qa_AndConst.cpp

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
#include <boost/ut.hpp>
2+
#include <gnuradio-4.0/basic/AndConst.hpp>
3+
4+
using namespace gr::basic;
5+
using namespace boost::ut;
6+
7+
const suite AndConstTests = [] {
8+
"uint8_t support"_test = [] {
9+
AndConst<uint8_t> andConstBlock;
10+
11+
// Test default constant = 1
12+
andConstBlock.constant = 1;
13+
expect(eq(andConstBlock.processOne(0xFF), 0x01));
14+
expect(eq(andConstBlock.processOne(0x00), 0x00));
15+
expect(eq(andConstBlock.processOne(0xAA), 0x00));
16+
17+
// Test constant = 0
18+
andConstBlock.constant = 0;
19+
expect(eq(andConstBlock.processOne(0xFF), 0x00));
20+
expect(eq(andConstBlock.processOne(0x00), 0x00));
21+
expect(eq(andConstBlock.processOne(0xAA), 0x00));
22+
};
23+
24+
"int16_t support"_test = [] {
25+
AndConst<int16_t> andConstBlock;
26+
27+
// Test default constant = 1
28+
andConstBlock.constant = 1;
29+
expect(eq(andConstBlock.processOne(static_cast<int16_t>(0xFF)), 0x0001));
30+
expect(eq(andConstBlock.processOne(static_cast<int16_t>(0x00)), 0x0000));
31+
expect(eq(andConstBlock.processOne(static_cast<int16_t>(0xAA)), 0x0000));
32+
33+
// Test constant = 0
34+
andConstBlock.constant = 0;
35+
expect(eq(andConstBlock.processOne(static_cast<int16_t>(0xFF)), 0x0000));
36+
expect(eq(andConstBlock.processOne(static_cast<int16_t>(0x00)), 0x0000));
37+
expect(eq(andConstBlock.processOne(static_cast<int16_t>(0xAA)), 0x0000));
38+
};
39+
40+
"int32_t support"_test = [] {
41+
AndConst<int32_t> andConstBlock;
42+
43+
// Test default constant = 1
44+
andConstBlock.constant = 1;
45+
expect(eq(andConstBlock.processOne((0xFF)), 0x00000001));
46+
expect(eq(andConstBlock.processOne((0x00)), 0x00000000));
47+
expect(eq(andConstBlock.processOne((0xAA)), 0x00000000));
48+
49+
// Test constant = 0
50+
andConstBlock.constant = 0;
51+
expect(eq(andConstBlock.processOne((0xFF)), 0x00000000));
52+
expect(eq(andConstBlock.processOne((0x00)), 0x00000000));
53+
expect(eq(andConstBlock.processOne((0xAA)), 0x00000000));
54+
};
55+
};
56+
57+
int main() { return boost::ut::cfg<boost::ut::override>.run(); }

blocks/basic/test/qa_Not.cpp

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
#include <boost/ut.hpp>
2+
#include <gnuradio-4.0/basic/Not.hpp>
3+
4+
using namespace gr::basic;
5+
using namespace boost::ut;
6+
7+
const suite NotTests = [] {
8+
"uint8_t support"_test = [] {
9+
Not<uint8_t> notBlock;
10+
11+
expect(eq(notBlock.processOne(0xFF), 0x00));
12+
expect(eq(notBlock.processOne(0x00), 0xFF));
13+
expect(eq(notBlock.processOne(0xAA), 0x55)); // ~(10101010) = 01010101
14+
};
15+
16+
"int16_t support"_test = [] {
17+
Not<int16_t> notBlock;
18+
19+
expect(eq(notBlock.processOne(static_cast<int16_t>(0x00FF)), static_cast<int16_t>(0xFF00)));
20+
expect(eq(notBlock.processOne(static_cast<int16_t>(0x0000)), static_cast<int16_t>(0xFFFF)));
21+
expect(eq(notBlock.processOne(static_cast<int16_t>(0xAAAA)), static_cast<int16_t>(0x5555)));
22+
};
23+
24+
25+
"int32_t support"_test = [] {
26+
Not<int32_t> notBlock;
27+
28+
expect(eq(notBlock.processOne(0x000000FF), static_cast<int32_t>(0xFFFFFF00)));
29+
expect(eq(notBlock.processOne(0x00000000), static_cast<int32_t>(0xFFFFFFFF)));
30+
expect(eq(notBlock.processOne(0x0000AAAA), static_cast<int32_t>(0xFFFF5555)));
31+
};
32+
};
33+
34+
35+
int main() { return boost::ut::cfg<boost::ut::override>.run(); }

blocks/basic/test/qa_Or.cpp

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
#include <boost/ut.hpp>
2+
#include <gnuradio-4.0/basic/Or.hpp>
3+
4+
using namespace gr::basic;
5+
using namespace boost::ut;
6+
7+
const suite OrTests = [] {
8+
"uint8_t support"_test = [] {
9+
Or<uint8_t> orBlock;
10+
11+
expect(eq(orBlock.processOne(0xAA, 0x55), 0xFF));
12+
expect(eq(orBlock.processOne(0x00, 0xFF), 0xFF));
13+
expect(eq(orBlock.processOne(0x01, 0x02), 0x03)); // 1 | 2 = 3
14+
};
15+
16+
"int16_t support"_test = [] {
17+
Or<int16_t> orBlock;
18+
19+
expect(eq(orBlock.processOne(static_cast<int16_t>(0x00AA), static_cast<int16_t>(0x0055)), static_cast<int16_t>(0x00FF)));
20+
expect(eq(orBlock.processOne(static_cast<int16_t>(0x0000), static_cast<int16_t>(0xFFFF)), static_cast<int16_t>(0xFFFF)));
21+
expect(eq(orBlock.processOne(static_cast<int16_t>(0xAAAA), static_cast<int16_t>(0x5555)), static_cast<int16_t>(0xFFFF)));
22+
};
23+
24+
"int32_t support"_test = [] {
25+
Or<int32_t> orBlock;
26+
27+
expect(eq(orBlock.processOne(0x000000AA, 0x00000055), 0x000000FF));
28+
expect(eq(orBlock.processOne(0x00000000, 0x0000FFFF), 0x0000FFFF));
29+
expect(eq(orBlock.processOne(0x0000AAAA, 0x00005555), 0x0000FFFF));
30+
};
31+
};
32+
33+
int main() { return boost::ut::cfg<boost::ut::override>.run(); }

blocks/basic/test/qa_Xor.cpp

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
#include <boost/ut.hpp>
2+
#include <gnuradio-4.0/basic/Xor.hpp>
3+
4+
using namespace gr::basic;
5+
using namespace boost::ut;
6+
7+
const suite XorTests = [] {
8+
"uint8_t support"_test = [] {
9+
Xor<uint8_t> xorBlock;
10+
11+
expect(eq(xorBlock.processOne(0xAA, 0x55), 0xFF));
12+
expect(eq(xorBlock.processOne(0xFF, 0xFF), 0x00));
13+
expect(eq(xorBlock.processOne(0x01, 0x03), 0x02)); // 1 ^ 2 = 3
14+
};
15+
16+
"int16_t support"_test = [] {
17+
Xor<int16_t> xorBlock;
18+
19+
expect(eq(xorBlock.processOne(static_cast<int16_t>(0x00AA), static_cast<int16_t>(0x0055)), static_cast<int16_t>(0x00FF)));
20+
expect(eq(xorBlock.processOne(static_cast<int16_t>(0xAAAA), static_cast<int16_t>(0xAAAA)), static_cast<int16_t>(0x0000)));
21+
expect(eq(xorBlock.processOne(static_cast<int16_t>(0x0F0F), static_cast<int16_t>(0xF0F0)), static_cast<int16_t>(0xFFFF)));
22+
};
23+
24+
"int32_t support"_test = [] {
25+
Xor<int32_t> xorBlock;
26+
27+
expect(eq(xorBlock.processOne(0x000000AA, 0x00000055), 0x000000FF));
28+
expect(eq(xorBlock.processOne(0x0000AAAA, 0x0000AAAA), 0x00000000));
29+
expect(eq(xorBlock.processOne(0x00000F0F, 0x0000F0F0), 0x0000FFFF));
30+
};
31+
};
32+
33+
int main() { return boost::ut::cfg<boost::ut::override>.run(); }

0 commit comments

Comments
 (0)