1 // Copyright 2020 The Pigweed Authors
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License"); you may not
4 // use this file except in compliance with the License. You may obtain a copy of
5 // the License at
6 //
7 // https://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
11 // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12 // License for the specific language governing permissions and limitations under
13 // the License.
14
15 // Copyright 2020 The Pigweed Authors
16 //
17 // Licensed under the Apache License, Version 2.0 (the "License"); you may not
18 // use this file except in compliance with the License. You may obtain a copy of
19 // the License at
20 //
21 // https://www.apache.org/licenses/LICENSE-2.0
22 //
23 // Unless required by applicable law or agreed to in writing, software
24 // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
25 // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
26 // License for the specific language governing permissions and limitations under
27 // the License.
28
29 #include "pw_hdlc/rpc_channel.h"
30
31 #include <algorithm>
32 #include <array>
33 #include <cstddef>
34
35 #include "gtest/gtest.h"
36 #include "pw_bytes/array.h"
37 #include "pw_stream/memory_stream.h"
38
39 using std::byte;
40
41 namespace pw::hdlc {
42 namespace {
43
44 constexpr byte kFlag = byte{0x7E};
45 constexpr uint8_t kAddress = 0x7b; // 123
46 constexpr uint8_t kEncodedAddress = (kAddress << 1) | 1;
47 constexpr byte kControl = byte{0x3}; // UI-frame control sequence.
48
49 // Size of the in-memory buffer to use for this test.
50 constexpr size_t kSinkBufferSize = 15;
51
52 TEST(RpcChannelOutput, 1BytePayload) {
53 stream::MemoryWriterBuffer<kSinkBufferSize> memory_writer;
54
55 RpcChannelOutput output(memory_writer, kAddress, "RpcChannelOutput");
56
57 constexpr byte test_data = byte{'A'};
58 std::array<std::byte, 128> buffer;
59 std::memcpy(buffer.data(), &test_data, sizeof(test_data));
60
61 constexpr auto expected = bytes::Concat(
62 kFlag, kEncodedAddress, kControl, 'A', uint32_t{0x653c9e82}, kFlag);
63
64 EXPECT_EQ(OkStatus(),
65 output.Send(std::span(buffer).first(sizeof(test_data))));
66
67 ASSERT_EQ(memory_writer.bytes_written(), expected.size());
68 EXPECT_EQ(
69 std::memcmp(
70 memory_writer.data(), expected.data(), memory_writer.bytes_written()),
71 0);
72 }
73
TEST(RpcChannelOutput,EscapingPayloadTest)74 TEST(RpcChannelOutput, EscapingPayloadTest) {
75 stream::MemoryWriterBuffer<kSinkBufferSize> memory_writer;
76
77 RpcChannelOutput output(memory_writer, kAddress, "RpcChannelOutput");
78
79 constexpr auto test_data = bytes::Array<0x7D>();
80 std::array<std::byte, 128> buffer;
81 std::memcpy(buffer.data(), test_data.data(), test_data.size());
82
83 constexpr auto expected = bytes::Concat(kFlag,
84 kEncodedAddress,
85 kControl,
86 byte{0x7d},
87 byte{0x7d} ^ byte{0x20},
88 uint32_t{0x4a53e205},
89 kFlag);
90 EXPECT_EQ(OkStatus(), output.Send(std::span(buffer).first(test_data.size())));
91
92 ASSERT_EQ(memory_writer.bytes_written(), 10u);
93 EXPECT_EQ(
94 std::memcmp(
95 memory_writer.data(), expected.data(), memory_writer.bytes_written()),
96 0);
97 }
98
99 TEST(RpcChannelOutputBuffer, 1BytePayload) {
100 stream::MemoryWriterBuffer<kSinkBufferSize> memory_writer;
101
102 RpcChannelOutput output(memory_writer, kAddress, "RpcChannelOutput");
103
104 constexpr byte test_data = byte{'A'};
105 std::array<std::byte, 128> buffer;
106 std::memcpy(buffer.data(), &test_data, sizeof(test_data));
107
108 constexpr auto expected = bytes::Concat(
109 kFlag, kEncodedAddress, kControl, 'A', uint32_t{0x653c9e82}, kFlag);
110
111 EXPECT_EQ(OkStatus(),
112 output.Send(std::span(buffer).first(sizeof(test_data))));
113
114 ASSERT_EQ(memory_writer.bytes_written(), expected.size());
115 EXPECT_EQ(
116 std::memcmp(
117 memory_writer.data(), expected.data(), memory_writer.bytes_written()),
118 0);
119 }
120
TEST(RpcChannelOutputBuffer,MultibyteAddress)121 TEST(RpcChannelOutputBuffer, MultibyteAddress) {
122 stream::MemoryWriterBuffer<kSinkBufferSize> memory_writer;
123
124 RpcChannelOutput output(memory_writer, 0x3fff, "RpcChannelOutput");
125
126 constexpr byte test_data = byte{'A'};
127 std::array<std::byte, 128> buffer;
128 std::memcpy(buffer.data(), &test_data, sizeof(test_data));
129
130 constexpr auto expected = bytes::Concat(kFlag,
131 bytes::String("\xfe\xff"),
132 kControl,
133 'A',
134 uint32_t{0xd393a8a0},
135 kFlag);
136
137 EXPECT_EQ(OkStatus(),
138 output.Send(std::span(buffer).first(sizeof(test_data))));
139
140 ASSERT_EQ(memory_writer.bytes_written(), expected.size());
141 EXPECT_EQ(
142 std::memcmp(
143 memory_writer.data(), expected.data(), memory_writer.bytes_written()),
144 0);
145 }
146
147 } // namespace
148 } // namespace pw::hdlc
149