blob: 8c36380fd7970697402e2a2218c016237ba881bc [file] [log] [blame]
// Copyright 2018 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "garnet/drivers/bluetooth/lib/rfcomm/mux_commands.h"
#include "gtest/gtest.h"
namespace btlib {
namespace rfcomm {
namespace {
class RFCOMM_MuxCommandTest : public ::testing::Test {};
// Manual contruction of multiplexer command for this test:
// Please see GSM 5.4.6.3.4.
// Our frame will have the following characteristics:
// - Test command
// - Command/response: command
// - Pattern: "fuchsia" (length 7)
//
// We now form the packet as follows.
// All octets are written LSB...MSB as in the GSM spec.
//
// Type octet is EA ++ C/R ++ type bits. EA is always 1 for RFCOMM/GSM; there
// are no commands which take more than one type octet. C/R bit is 1 for
// commands. Type bits are 000100. Thus, type octet is 11000100.
//
// Length field is one octet long; the octet is EA ++ length, or 1 ++ 1110000.
TEST_F(RFCOMM_MuxCommandTest, TestCommand) {
auto test_pattern =
common::CreateStaticByteBuffer('f', 'u', 'c', 'h', 's', 'i', 'a');
TestCommand command(CommandResponse::kCommand, test_pattern);
ASSERT_EQ(command.written_size(), 1ul // Type
+ 1ul // Length
+ test_pattern.size()); // Payload
common::DynamicByteBuffer buffer(command.written_size());
command.Write(buffer.mutable_view());
ASSERT_EQ(buffer,
common::CreateStaticByteBuffer(0b00100011, 0b00001111, 'f', 'u',
'c', 'h', 's', 'i', 'a'));
auto read_command = MuxCommand::Parse(buffer);
EXPECT_EQ(read_command->command_response(), CommandResponse::kCommand);
ASSERT_EQ(read_command->command_type(), MuxCommandType::kTestCommand);
auto test_command = std::unique_ptr<TestCommand>(
static_cast<TestCommand*>(read_command.release()));
EXPECT_EQ(test_command->test_pattern(), test_pattern);
}
// Manual contruction of multiplexer command for this test:
// Please see GSM 5.4.6.3.5.
// Our frame will have the following characteristics:
// - Flow Control On Command
// - Command/response: response
//
// We now form the packet as follows.
// All octets are written LSB...MSB as in the GSM spec.
//
// Type octet is EA ++ C/R ++ type bits. EA is always 1 for RFCOMM/GSM; there
// are no commands which take more than one type octet. C/R bit is 0 for
// response. Type bits are 000101. Thus, type octet is 10000101.
//
// Length field is one octet long; the octet is EA ++ length, or 1 ++ 0000000.
TEST_F(RFCOMM_MuxCommandTest, FconCommand) {
FlowControlOnCommand command(CommandResponse::kResponse);
ASSERT_EQ(command.written_size(), 1ul // Type
+ 1ul); // Length
common::DynamicByteBuffer buffer(command.written_size());
command.Write(buffer.mutable_view());
ASSERT_EQ(buffer, common::CreateStaticByteBuffer(0b10100001, 0b00000001));
auto read_command = MuxCommand::Parse(buffer);
EXPECT_EQ(read_command->command_response(), CommandResponse::kResponse);
ASSERT_EQ(read_command->command_type(),
MuxCommandType::kFlowControlOnCommand);
}
// Manual contruction of multiplexer command for this test:
// Please see GSM 5.4.6.3.6.
// Our frame will have the following characteristics:
// - Flow Control Off Command
// - Command/response: command
//
// We now form the packet as follows.
// All octets are written LSB...MSB as in the GSM spec.
//
// Type octet is EA ++ C/R ++ type bits. EA is always 1 for RFCOMM/GSM; there
// are no commands which take more than one type octet. C/R bit is 1 for
// command. Type bits are 000110. Thus, type octet is 11000110.
//
// Length field is one octet long; the octet is EA ++ length, or 1 ++ 0000000.
TEST_F(RFCOMM_MuxCommandTest, FcoffCommand) {
FlowControlOffCommand command(CommandResponse::kCommand);
ASSERT_EQ(command.written_size(), 1ul // Type
+ 1ul); // Length
common::DynamicByteBuffer buffer(command.written_size());
command.Write(buffer.mutable_view());
ASSERT_EQ(buffer, common::CreateStaticByteBuffer(0b01100011, 0b00000001));
auto read_command = MuxCommand::Parse(buffer);
EXPECT_EQ(read_command->command_response(), CommandResponse::kCommand);
ASSERT_EQ(read_command->command_type(),
MuxCommandType::kFlowControlOffCommand);
}
// Manual contruction of multiplexer command for this test:
// Please see GSM 5.4.6.3.7.
// Our frame will have the following characteristics:
// - Modem Status command
// - Command/response: command
// - DLCI: 0x23
// - Signals: FC=1, RTC=0, RTR=1, IC=0, DV=1
// - Break value: 0b1010
//
// We now form the packet as follows.
// All octets are written LSB...MSB as in the GSM spec.
//
// Type octet is EA ++ C/R ++ type bits. EA is always 1 for RFCOMM/GSM; there
// are no commands which take more than one type octet. C/R bit is 1 for
// command. Type bits are 000111. Thus, type octet is 11000111.
//
// Length field is one octet long; the octet is EA ++ length, or 1 ++ 1100000.
//
// DLCI octet is EA ++ 1 ++ DLCI, or 1 ++ 1 ++ 010011.
//
// Signal octet is EA ++ FC ++ RTC ++ RTR ++ 00 ++ IC ++ DV, or 0 ++ 1 ++ 0 ++ 1
// ++ 00 ++ 0 ++ 1.
//
// Break octet is EA ++ B1 ++ 00 ++ break value, or 1 ++ 1 ++ 00 ++ 0101.
TEST_F(RFCOMM_MuxCommandTest, ModemStatusCommand) {
ModemStatusCommandSignals signals = {true, false, true, false, true};
BreakValue break_value = 0b1010;
ModemStatusCommand command(CommandResponse::kCommand, 0x23, signals,
break_value);
ASSERT_EQ(command.written_size(), 5ul);
common::DynamicByteBuffer buffer(command.written_size());
command.Write(buffer.mutable_view());
ASSERT_EQ(buffer,
common::CreateStaticByteBuffer(0b11100011, 0b00000111, 0b10001111,
0b10001010, 0b10100011));
auto read_command = MuxCommand::Parse(buffer);
EXPECT_EQ(read_command->command_response(), CommandResponse::kCommand);
ASSERT_EQ(read_command->command_type(), MuxCommandType::kModemStatusCommand);
auto msc = std::unique_ptr<ModemStatusCommand>(
static_cast<ModemStatusCommand*>(read_command.release()));
EXPECT_EQ(msc->dlci(), 0x23);
EXPECT_EQ(msc->signals().flow_control, signals.flow_control);
EXPECT_EQ(msc->signals().ready_to_communicate, signals.ready_to_communicate);
EXPECT_EQ(msc->signals().ready_to_receive, signals.ready_to_receive);
EXPECT_EQ(msc->signals().incoming_call, signals.incoming_call);
EXPECT_EQ(msc->signals().data_valid, signals.data_valid);
EXPECT_TRUE(msc->has_break_signal());
EXPECT_EQ(msc->break_value(), break_value);
}
TEST_F(RFCOMM_MuxCommandTest, RemotePortNegotiationCommand8Octets) {
FlowControlFlagsBitfield flow_control = FlowControlFlags::kXonXoffInputFlag |
FlowControlFlags::kRTRInputFlag |
FlowControlFlags::kRTCInputFlag;
RemotePortNegotiationParams params;
params.baud = Baud::k115200;
params.data_bits = DataBits::k7Bits;
params.stop_bits = StopBits::k1AndHalfBits;
params.parity = true;
params.parity_type = ParityType::kOdd;
params.flow_control = flow_control;
params.xon_character = 0x23;
params.xoff_character = 0xDA;
RemotePortNegotiationMaskBitfield mask;
mask = RemotePortNegotiationMask::kBitRate |
RemotePortNegotiationMask::kStopBits |
RemotePortNegotiationMask::kParityType |
RemotePortNegotiationMask::kXOFFCharacter |
RemotePortNegotiationMask::kXonXoffInput |
RemotePortNegotiationMask::kXonXoffOutput |
RemotePortNegotiationMask::kRTROutput |
RemotePortNegotiationMask::kRTCInput;
RemotePortNegotiationCommand command(CommandResponse::kCommand, 61, params,
mask);
EXPECT_EQ(command.written_size(), 10ul);
common::DynamicByteBuffer buffer(command.written_size());
command.Write(buffer.mutable_view());
EXPECT_EQ(buffer,
common::CreateStaticByteBuffer(0b10010011, 0b00010001, 0b11110111,
0b00000111, 0b00001101, 0b00010101,
0x23, 0xDA, 0b01010101, 0b00011011));
auto read_command = MuxCommand::Parse(buffer);
EXPECT_EQ(read_command->command_response(), CommandResponse::kCommand);
EXPECT_EQ(read_command->command_type(),
MuxCommandType::kRemotePortNegotiationCommand);
auto rpn_command = std::unique_ptr<RemotePortNegotiationCommand>(
static_cast<RemotePortNegotiationCommand*>(read_command.release()));
EXPECT_EQ(rpn_command->dlci(), 61);
EXPECT_EQ(rpn_command->mask(), mask);
EXPECT_EQ(rpn_command->params().baud, params.baud);
EXPECT_EQ(rpn_command->params().data_bits, params.data_bits);
EXPECT_EQ(rpn_command->params().stop_bits, params.stop_bits);
EXPECT_EQ(rpn_command->params().parity, params.parity);
EXPECT_EQ(rpn_command->params().parity_type, params.parity_type);
EXPECT_EQ(rpn_command->params().xon_character, params.xon_character);
EXPECT_EQ(rpn_command->params().xoff_character, params.xoff_character);
EXPECT_EQ(rpn_command->params().flow_control, flow_control);
}
TEST_F(RFCOMM_MuxCommandTest, RemotePortNegotiationCommand1Octet) {
RemotePortNegotiationCommand command(CommandResponse::kCommand, 61);
ASSERT_EQ(command.written_size(), 3ul);
common::DynamicByteBuffer buffer(command.written_size());
command.Write(buffer.mutable_view());
ASSERT_EQ(buffer,
common::CreateStaticByteBuffer(0b10010011, 0b00000011, 0b11110111));
auto read_command = MuxCommand::Parse(buffer);
EXPECT_EQ(read_command->command_response(), CommandResponse::kCommand);
ASSERT_EQ(read_command->command_type(),
MuxCommandType::kRemotePortNegotiationCommand);
auto rpn_command = std::unique_ptr<RemotePortNegotiationCommand>(
static_cast<RemotePortNegotiationCommand*>(read_command.release()));
EXPECT_EQ(rpn_command->dlci(), 61);
}
TEST_F(RFCOMM_MuxCommandTest, RemoteLineStatusCommand) {
RemoteLineStatusCommand command(CommandResponse::kCommand, 61, true,
LineError::kFramingError);
ASSERT_EQ(command.written_size(), 4ul);
common::DynamicByteBuffer buffer(command.written_size());
command.Write(buffer.mutable_view());
ASSERT_EQ(buffer, common::CreateStaticByteBuffer(0b01010011, 0b00000101,
0b11110111, 0b00001001));
auto read_command = MuxCommand::Parse(buffer);
EXPECT_EQ(read_command->command_response(), CommandResponse::kCommand);
ASSERT_EQ(read_command->command_type(),
MuxCommandType::kRemoteLineStatusCommand);
auto rpn_command = std::unique_ptr<RemoteLineStatusCommand>(
static_cast<RemoteLineStatusCommand*>(read_command.release()));
EXPECT_EQ(rpn_command->dlci(), 61);
EXPECT_EQ(rpn_command->error_occurred(), true);
EXPECT_EQ(rpn_command->error(), LineError::kFramingError);
}
TEST_F(RFCOMM_MuxCommandTest, NonSupportedCommandResponse) {
NonSupportedCommandResponse command(CommandResponse::kResponse, 0b00101001);
ASSERT_EQ(command.written_size(), 3ul);
common::DynamicByteBuffer buffer(command.written_size());
command.Write(buffer.mutable_view());
ASSERT_EQ(buffer,
common::CreateStaticByteBuffer(0b00010001, 0b00000011, 0b10100101));
auto read_command = MuxCommand::Parse(buffer);
EXPECT_EQ(read_command->command_response(), CommandResponse::kResponse);
ASSERT_EQ(read_command->command_type(),
MuxCommandType::kNonSupportedCommandResponse);
auto nsc_response = std::unique_ptr<NonSupportedCommandResponse>(
static_cast<NonSupportedCommandResponse*>(read_command.release()));
EXPECT_EQ(nsc_response->incoming_command_response(),
CommandResponse::kResponse);
EXPECT_EQ(nsc_response->incoming_non_supported_command(), 0b00101001);
}
TEST_F(RFCOMM_MuxCommandTest, DLCParameterNegotiationCommand) {
ParameterNegotiationParams params;
params.dlci = 61;
params.credit_based_flow_handshake =
CreditBasedFlowHandshake::kSupportedResponse;
params.priority = kMaxPriority;
params.maximum_frame_size = 0x1234;
params.initial_credits = kMaxInitialCredits;
DLCParameterNegotiationCommand command(CommandResponse::kResponse, params);
ASSERT_EQ(command.written_size(), 10ul);
common::DynamicByteBuffer buffer(command.written_size());
command.Write(buffer.mutable_view());
ASSERT_EQ(buffer, common::CreateStaticByteBuffer(
0b10000001, 0b00010001, 0b00111101, 0xE0, kMaxPriority,
0, 0x34, 0x12, 0, kMaxInitialCredits));
auto read_command = MuxCommand::Parse(buffer);
EXPECT_EQ(read_command->command_response(), CommandResponse::kResponse);
ASSERT_EQ(read_command->command_type(),
MuxCommandType::kDLCParameterNegotiation);
auto pn_command = std::unique_ptr<DLCParameterNegotiationCommand>(
static_cast<DLCParameterNegotiationCommand*>(read_command.release()));
EXPECT_EQ(pn_command->params().dlci, 61);
EXPECT_EQ(pn_command->params().credit_based_flow_handshake,
CreditBasedFlowHandshake::kSupportedResponse);
EXPECT_EQ(pn_command->params().priority, kMaxPriority);
EXPECT_EQ(pn_command->params().maximum_frame_size, 0x1234);
EXPECT_EQ(pn_command->params().initial_credits, kMaxInitialCredits);
}
} // namespace
} // namespace rfcomm
} // namespace btlib