1//
2// Copyright 2015 The Android Open Source Project
3//
4// Licensed under the Apache License, Version 2.0 (the "License");
5// you may not use this file except in compliance with the License.
6// You may obtain a copy of the License at
7//
8// http://www.apache.org/licenses/LICENSE-2.0
9//
10// Unless required by applicable law or agreed to in writing, software
11// distributed under the License is distributed on an "AS IS" BASIS,
12// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13// See the License for the specific language governing permissions and
14// limitations under the License.
15//
16
17#define LOG_TAG "dual_mode_controller"
18
19#include "vendor_libs/test_vendor_lib/include/dual_mode_controller.h"
20
21#include "base/logging.h"
22#include "base/files/file_util.h"
23#include "base/json/json_reader.h"
24#include "base/values.h"
25#include "vendor_libs/test_vendor_lib/include/event_packet.h"
26#include "vendor_libs/test_vendor_lib/include/hci_transport.h"
27
28extern "C" {
29#include "stack/include/hcidefs.h"
30#include "osi/include/log.h"
31}  // extern "C"
32
33namespace {
34
35// Included in certain events to indicate success (specific to the event
36// context).
37const uint8_t kSuccessStatus = 0;
38
39// The default number encoded in event packets to indicate to the HCI how many
40// command packets it can send to the controller.
41const uint8_t kNumHciCommandPackets = 1;
42
43// The location of the config file loaded to populate controller attributes.
44const std::string kControllerPropertiesFile =
45    "/etc/bluetooth/controller_properties.json";
46
47// Inquiry modes for specifiying inquiry result formats.
48const uint8_t kStandardInquiry = 0x00;
49const uint8_t kRssiInquiry = 0x01;
50const uint8_t kExtendedOrRssiInquiry = 0x02;
51
52// The bd address of another (fake) device.
53const std::vector<uint8_t> kOtherDeviceBdAddress = {6, 5, 4, 3, 2, 1};
54
55// Fake inquiry response for a fake device.
56const std::vector<uint8_t> kPageScanRepetitionMode = {0};
57const std::vector<uint8_t> kPageScanPeriodMode = {0};
58const std::vector<uint8_t> kPageScanMode = {0};
59const std::vector<uint8_t> kClassOfDevice = {1, 2, 3};
60const std::vector<uint8_t> kClockOffset = {1, 2};
61
62void LogCommand(const char* command) {
63  LOG_INFO(LOG_TAG, "Controller performing command: %s", command);
64}
65
66// Functions used by JSONValueConverter to read stringified JSON into Properties
67// object.
68bool ParseUint8t(const base::StringPiece& value, uint8_t* field) {
69  *field = std::stoi(value.as_string());
70  return true;
71}
72
73bool ParseUint16t(const base::StringPiece& value, uint16_t* field) {
74  *field = std::stoi(value.as_string());
75  return true;
76}
77
78bool ParseUint8tVector(const base::StringPiece& value,
79                              std::vector<uint8_t>* field) {
80  for (char& c : value.as_string())
81    field->push_back(c - '0');
82  return true;
83}
84
85}  // namespace
86
87namespace test_vendor_lib {
88
89void DualModeController::SendCommandComplete(
90    uint16_t command_opcode,
91    const std::vector<uint8_t>& return_parameters) const {
92  std::unique_ptr<EventPacket> command_complete =
93      EventPacket::CreateCommandCompleteEvent(
94          kNumHciCommandPackets, command_opcode, return_parameters);
95  send_event_(std::move(command_complete));
96}
97
98void DualModeController::SendCommandCompleteSuccess(
99    uint16_t command_opcode) const {
100  SendCommandComplete(command_opcode, {kSuccessStatus});
101}
102
103void DualModeController::SendCommandStatus(uint8_t status,
104                                           uint16_t command_opcode) const {
105  std::unique_ptr<EventPacket> command_status =
106      EventPacket::CreateCommandStatusEvent(status, kNumHciCommandPackets,
107                                            command_opcode);
108  send_event_(std::move(command_status));
109}
110
111void DualModeController::SendCommandStatusSuccess(
112    uint16_t command_opcode) const {
113  SendCommandStatus(kSuccessStatus, command_opcode);
114}
115
116void DualModeController::SendInquiryResult() const {
117  std::unique_ptr<EventPacket> inquiry_result =
118      EventPacket::CreateInquiryResultEvent(
119          1, kOtherDeviceBdAddress, kPageScanRepetitionMode,
120          kPageScanPeriodMode, kPageScanMode, kClassOfDevice, kClockOffset);
121  send_event_(std::move(inquiry_result));
122}
123
124void DualModeController::SendExtendedInquiryResult(
125    const std::string& name, const std::string& address) const {
126  std::vector<uint8_t> rssi = {0};
127  std::vector<uint8_t> extended_inquiry_data = {name.length() + 1, 0x09};
128  std::copy(name.begin(), name.end(),
129            std::back_inserter(extended_inquiry_data));
130  std::vector<uint8_t> bd_address(address.begin(), address.end());
131  // TODO(dennischeng): Use constants for parameter sizes, here and elsewhere.
132  while (extended_inquiry_data.size() < 240) {
133    extended_inquiry_data.push_back(0);
134  }
135  std::unique_ptr<EventPacket> extended_inquiry_result =
136      EventPacket::CreateExtendedInquiryResultEvent(
137          bd_address, kPageScanRepetitionMode, kPageScanPeriodMode,
138          kClassOfDevice, kClockOffset, rssi, extended_inquiry_data);
139  send_event_(std::move(extended_inquiry_result));
140}
141
142DualModeController::DualModeController()
143    : state_(kStandby),
144      test_channel_state_(kNone),
145      properties_(kControllerPropertiesFile) {
146#define SET_HANDLER(opcode, method) \
147  active_hci_commands_[opcode] =    \
148      std::bind(&DualModeController::method, this, std::placeholders::_1);
149  SET_HANDLER(HCI_RESET, HciReset);
150  SET_HANDLER(HCI_READ_BUFFER_SIZE, HciReadBufferSize);
151  SET_HANDLER(HCI_HOST_BUFFER_SIZE, HciHostBufferSize);
152  SET_HANDLER(HCI_READ_LOCAL_VERSION_INFO, HciReadLocalVersionInformation);
153  SET_HANDLER(HCI_READ_BD_ADDR, HciReadBdAddr);
154  SET_HANDLER(HCI_READ_LOCAL_SUPPORTED_CMDS, HciReadLocalSupportedCommands);
155  SET_HANDLER(HCI_READ_LOCAL_EXT_FEATURES, HciReadLocalExtendedFeatures);
156  SET_HANDLER(HCI_WRITE_SIMPLE_PAIRING_MODE, HciWriteSimplePairingMode);
157  SET_HANDLER(HCI_WRITE_LE_HOST_SUPPORT, HciWriteLeHostSupport);
158  SET_HANDLER(HCI_SET_EVENT_MASK, HciSetEventMask);
159  SET_HANDLER(HCI_WRITE_INQUIRY_MODE, HciWriteInquiryMode);
160  SET_HANDLER(HCI_WRITE_PAGESCAN_TYPE, HciWritePageScanType);
161  SET_HANDLER(HCI_WRITE_INQSCAN_TYPE, HciWriteInquiryScanType);
162  SET_HANDLER(HCI_WRITE_CLASS_OF_DEVICE, HciWriteClassOfDevice);
163  SET_HANDLER(HCI_WRITE_PAGE_TOUT, HciWritePageTimeout);
164  SET_HANDLER(HCI_WRITE_DEF_POLICY_SETTINGS, HciWriteDefaultLinkPolicySettings);
165  SET_HANDLER(HCI_READ_LOCAL_NAME, HciReadLocalName);
166  SET_HANDLER(HCI_CHANGE_LOCAL_NAME, HciWriteLocalName);
167  SET_HANDLER(HCI_WRITE_EXT_INQ_RESPONSE, HciWriteExtendedInquiryResponse);
168  SET_HANDLER(HCI_WRITE_VOICE_SETTINGS, HciWriteVoiceSetting);
169  SET_HANDLER(HCI_WRITE_CURRENT_IAC_LAP, HciWriteCurrentIacLap);
170  SET_HANDLER(HCI_WRITE_INQUIRYSCAN_CFG, HciWriteInquiryScanActivity);
171  SET_HANDLER(HCI_WRITE_SCAN_ENABLE, HciWriteScanEnable);
172  SET_HANDLER(HCI_SET_EVENT_FILTER, HciSetEventFilter);
173  SET_HANDLER(HCI_INQUIRY, HciInquiry);
174  SET_HANDLER(HCI_INQUIRY_CANCEL, HciInquiryCancel);
175  SET_HANDLER(HCI_DELETE_STORED_LINK_KEY, HciDeleteStoredLinkKey);
176  SET_HANDLER(HCI_RMT_NAME_REQUEST, HciRemoteNameRequest);
177#undef SET_HANDLER
178
179#define SET_TEST_HANDLER(command_name, method)  \
180  active_test_channel_commands_[command_name] = \
181      std::bind(&DualModeController::method, this, std::placeholders::_1);
182  SET_TEST_HANDLER("CLEAR", TestChannelClear);
183  SET_TEST_HANDLER("CLEAR_EVENT_DELAY", TestChannelClearEventDelay);
184  SET_TEST_HANDLER("DISCOVER", TestChannelDiscover);
185  SET_TEST_HANDLER("SET_EVENT_DELAY", TestChannelSetEventDelay);
186  SET_TEST_HANDLER("TIMEOUT_ALL", TestChannelTimeoutAll);
187#undef SET_TEST_HANDLER
188}
189
190void DualModeController::RegisterHandlersWithHciTransport(
191    HciTransport& transport) {
192  transport.RegisterCommandHandler(std::bind(&DualModeController::HandleCommand,
193                                             this, std::placeholders::_1));
194}
195
196void DualModeController::RegisterHandlersWithTestChannelTransport(
197    TestChannelTransport& transport) {
198  transport.RegisterCommandHandler(
199      std::bind(&DualModeController::HandleTestChannelCommand, this,
200                std::placeholders::_1, std::placeholders::_2));
201}
202
203void DualModeController::HandleTestChannelCommand(
204    const std::string& name, const std::vector<std::string>& args) {
205  if (active_test_channel_commands_.count(name) == 0)
206    return;
207  active_test_channel_commands_[name](args);
208}
209
210void DualModeController::HandleCommand(
211    std::unique_ptr<CommandPacket> command_packet) {
212  uint16_t opcode = command_packet->GetOpcode();
213  LOG_INFO(LOG_TAG, "Command opcode: 0x%04X, OGF: 0x%04X, OCF: 0x%04X", opcode,
214           command_packet->GetOGF(), command_packet->GetOCF());
215
216  // The command hasn't been registered with the handler yet. There is nothing
217  // to do.
218  if (active_hci_commands_.count(opcode) == 0)
219    return;
220  else if (test_channel_state_ == kTimeoutAll)
221    return;
222  active_hci_commands_[opcode](command_packet->GetPayload());
223}
224
225void DualModeController::RegisterEventChannel(
226    std::function<void(std::unique_ptr<EventPacket>)> callback) {
227  send_event_ = callback;
228}
229
230void DualModeController::RegisterDelayedEventChannel(
231    std::function<void(std::unique_ptr<EventPacket>, base::TimeDelta)>
232        callback) {
233  send_delayed_event_ = callback;
234  SetEventDelay(0);
235}
236
237void DualModeController::SetEventDelay(int64_t delay) {
238  if (delay < 0)
239    delay = 0;
240  send_event_ = std::bind(send_delayed_event_, std::placeholders::_1,
241                          base::TimeDelta::FromMilliseconds(delay));
242}
243
244void DualModeController::TestChannelClear(
245    const std::vector<std::string>& args) {
246  LogCommand("TestChannel Clear");
247  test_channel_state_ = kNone;
248  SetEventDelay(0);
249}
250
251void DualModeController::TestChannelDiscover(
252    const std::vector<std::string>& args) {
253  LogCommand("TestChannel Discover");
254  for (size_t i = 0; i < args.size()-1; i+=2)
255    SendExtendedInquiryResult(args[i], args[i+1]);
256}
257
258void DualModeController::TestChannelTimeoutAll(
259    const std::vector<std::string>& args) {
260  LogCommand("TestChannel Timeout All");
261  test_channel_state_ = kTimeoutAll;
262}
263
264void DualModeController::TestChannelSetEventDelay(
265    const std::vector<std::string>& args) {
266  LogCommand("TestChannel Set Event Delay");
267  test_channel_state_ = kDelayedResponse;
268  SetEventDelay(std::stoi(args[0]));
269}
270
271void DualModeController::TestChannelClearEventDelay(
272    const std::vector<std::string>& args) {
273  LogCommand("TestChannel Clear Event Delay");
274  test_channel_state_ = kNone;
275  SetEventDelay(0);
276}
277
278void DualModeController::HciReset(const std::vector<uint8_t>& /* args */) {
279  LogCommand("Reset");
280  state_ = kStandby;
281  SendCommandCompleteSuccess(HCI_RESET);
282}
283
284void DualModeController::HciReadBufferSize(
285    const std::vector<uint8_t>& /* args */) {
286  LogCommand("Read Buffer Size");
287  SendCommandComplete(HCI_READ_BUFFER_SIZE, properties_.GetBufferSize());
288}
289
290void DualModeController::HciHostBufferSize(
291    const std::vector<uint8_t>& /* args */) {
292  LogCommand("Host Buffer Size");
293  SendCommandCompleteSuccess(HCI_HOST_BUFFER_SIZE);
294}
295
296void DualModeController::HciReadLocalVersionInformation(
297                 const std::vector<uint8_t>& /* args */) {
298  LogCommand("Read Local Version Information");
299  SendCommandComplete(HCI_READ_LOCAL_VERSION_INFO,
300                      properties_.GetLocalVersionInformation());
301}
302
303void DualModeController::HciReadBdAddr(const std::vector<uint8_t>& /* args */) {
304  LogCommand("Read Bd Addr");
305  std::vector<uint8_t> bd_address_with_status = properties_.GetBdAddress();
306  bd_address_with_status.insert(bd_address_with_status.begin(),
307                                kSuccessStatus);
308  SendCommandComplete(HCI_READ_BD_ADDR, bd_address_with_status);
309}
310
311void DualModeController::HciReadLocalSupportedCommands(
312    const std::vector<uint8_t>& /* args */) {
313  LogCommand("Read Local Supported Commands");
314  SendCommandComplete(HCI_READ_LOCAL_SUPPORTED_CMDS,
315                      properties_.GetLocalSupportedCommands());
316}
317
318void DualModeController::HciReadLocalExtendedFeatures(
319    const std::vector<uint8_t>& args) {
320  LogCommand("Read Local Extended Features");
321  SendCommandComplete(HCI_READ_LOCAL_EXT_FEATURES,
322                      properties_.GetLocalExtendedFeatures(args[0]));
323}
324
325void DualModeController::HciWriteSimplePairingMode(
326    const std::vector<uint8_t>& /* args */) {
327  LogCommand("Write Simple Pairing Mode");
328  SendCommandCompleteSuccess(HCI_WRITE_SIMPLE_PAIRING_MODE);
329}
330
331void DualModeController::HciWriteLeHostSupport(
332    const std::vector<uint8_t>& /* args */) {
333  LogCommand("Write Le Host Support");
334  SendCommandCompleteSuccess(HCI_WRITE_LE_HOST_SUPPORT);
335}
336
337void DualModeController::HciSetEventMask(
338    const std::vector<uint8_t>& /* args */) {
339  LogCommand("Set Event Mask");
340  SendCommandCompleteSuccess(HCI_SET_EVENT_MASK);
341}
342
343void DualModeController::HciWriteInquiryMode(const std::vector<uint8_t>& args) {
344  LogCommand("Write Inquiry Mode");
345  CHECK(args.size() == 1);
346  inquiry_mode_ = args[0];
347  SendCommandCompleteSuccess(HCI_WRITE_INQUIRY_MODE);
348}
349
350void DualModeController::HciWritePageScanType(
351    const std::vector<uint8_t>& /* args */) {
352  LogCommand("Write Page Scan Type");
353  SendCommandCompleteSuccess(HCI_WRITE_PAGESCAN_TYPE);
354}
355
356void DualModeController::HciWriteInquiryScanType(
357    const std::vector<uint8_t>& /* args */) {
358  LogCommand("Write Inquiry Scan Type");
359  SendCommandCompleteSuccess(HCI_WRITE_INQSCAN_TYPE);
360}
361
362void DualModeController::HciWriteClassOfDevice(
363    const std::vector<uint8_t>& /* args */) {
364  LogCommand("Write Class Of Device");
365  SendCommandCompleteSuccess(HCI_WRITE_CLASS_OF_DEVICE);
366}
367
368void DualModeController::HciWritePageTimeout(
369    const std::vector<uint8_t>& /* args */) {
370  LogCommand("Write Page Timeout");
371  SendCommandCompleteSuccess(HCI_WRITE_PAGE_TOUT);
372}
373
374void DualModeController::HciWriteDefaultLinkPolicySettings(
375    const std::vector<uint8_t>& /* args */) {
376  LogCommand("Write Default Link Policy Settings");
377  SendCommandCompleteSuccess(HCI_WRITE_DEF_POLICY_SETTINGS);
378}
379
380void DualModeController::HciReadLocalName(
381    const std::vector<uint8_t>& /* args */) {
382  LogCommand("Get Local Name");
383  SendCommandComplete(HCI_READ_LOCAL_NAME, properties_.GetLocalName());
384}
385
386void DualModeController::HciWriteLocalName(
387    const std::vector<uint8_t>& /* args */) {
388  LogCommand("Write Local Name");
389  SendCommandCompleteSuccess(HCI_CHANGE_LOCAL_NAME);
390}
391
392void DualModeController::HciWriteExtendedInquiryResponse(
393    const std::vector<uint8_t>& /* args */) {
394  LogCommand("Write Extended Inquiry Response");
395  SendCommandCompleteSuccess(HCI_WRITE_EXT_INQ_RESPONSE);
396}
397
398void DualModeController::HciWriteVoiceSetting(
399    const std::vector<uint8_t>& /* args */) {
400  LogCommand("Write Voice Setting");
401  SendCommandCompleteSuccess(HCI_WRITE_VOICE_SETTINGS);
402}
403
404void DualModeController::HciWriteCurrentIacLap(
405    const std::vector<uint8_t>& /* args */) {
406  LogCommand("Write Current IAC LAP");
407  SendCommandCompleteSuccess(HCI_WRITE_CURRENT_IAC_LAP);
408}
409
410void DualModeController::HciWriteInquiryScanActivity(
411    const std::vector<uint8_t>& /* args */) {
412  LogCommand("Write Inquiry Scan Activity");
413  SendCommandCompleteSuccess(HCI_WRITE_INQUIRYSCAN_CFG);
414}
415
416void DualModeController::HciWriteScanEnable(
417    const std::vector<uint8_t>& /* args */) {
418  LogCommand("Write Scan Enable");
419  SendCommandCompleteSuccess(HCI_WRITE_SCAN_ENABLE);
420}
421
422void DualModeController::HciSetEventFilter(
423    const std::vector<uint8_t>& /* args */) {
424  LogCommand("Set Event Filter");
425  SendCommandCompleteSuccess(HCI_SET_EVENT_FILTER);
426}
427
428void DualModeController::HciInquiry(const std::vector<uint8_t>& /* args */) {
429  LogCommand("Inquiry");
430  state_ = kInquiry;
431  SendCommandStatusSuccess(HCI_INQUIRY);
432  switch (inquiry_mode_) {
433    case (kStandardInquiry):
434      SendInquiryResult();
435      break;
436
437    case (kRssiInquiry):
438      LOG_INFO(LOG_TAG, "RSSI Inquiry Mode currently not supported.");
439      break;
440
441    case (kExtendedOrRssiInquiry):
442      SendExtendedInquiryResult("FooBar", "123456");
443      break;
444  }
445}
446
447void DualModeController::HciInquiryCancel(
448    const std::vector<uint8_t>& /* args */) {
449  LogCommand("Inquiry Cancel");
450  CHECK(state_ == kInquiry);
451  state_ = kStandby;
452  SendCommandCompleteSuccess(HCI_INQUIRY_CANCEL);
453}
454
455void DualModeController::HciDeleteStoredLinkKey(
456    const std::vector<uint8_t>& args) {
457  LogCommand("Delete Stored Link Key");
458  /* Check the last octect in |args|. If it is 0, delete only the link key for
459   * the given BD_ADDR. If is is 1, delete all stored link keys. */
460  SendCommandComplete(HCI_DELETE_STORED_LINK_KEY, {1});
461}
462
463void DualModeController::HciRemoteNameRequest(
464    const std::vector<uint8_t>& args) {
465  LogCommand("Remote Name Request");
466  SendCommandStatusSuccess(HCI_RMT_NAME_REQUEST);
467}
468
469DualModeController::Properties::Properties(const std::string& file_name)
470    : local_supported_commands_size_(64), local_name_size_(248) {
471  std::string properties_raw;
472  if (!base::ReadFileToString(base::FilePath(file_name), &properties_raw))
473    LOG_INFO(LOG_TAG, "Error reading controller properties from file.");
474
475  scoped_ptr<base::Value> properties_value_ptr =
476      base::JSONReader::Read(properties_raw);
477  if (properties_value_ptr.get() == nullptr)
478    LOG_INFO(LOG_TAG,
479             "Error controller properties may consist of ill-formed JSON.");
480
481  // Get the underlying base::Value object, which is of type
482  // base::Value::TYPE_DICTIONARY, and read it into member variables.
483  base::Value& properties_dictionary = *(properties_value_ptr.get());
484  base::JSONValueConverter<DualModeController::Properties> converter;
485
486  if (!converter.Convert(properties_dictionary, this))
487    LOG_INFO(LOG_TAG,
488             "Error converting JSON properties into Properties object.");
489}
490
491const std::vector<uint8_t> DualModeController::Properties::GetBufferSize() {
492  return std::vector<uint8_t>(
493      {kSuccessStatus, acl_data_packet_size_, acl_data_packet_size_ >> 8,
494       sco_data_packet_size_, num_acl_data_packets_, num_acl_data_packets_ >> 8,
495       num_sco_data_packets_, num_sco_data_packets_ >> 8});
496}
497
498const std::vector<uint8_t>
499DualModeController::Properties::GetLocalVersionInformation() {
500  return std::vector<uint8_t>({kSuccessStatus, version_, revision_,
501                               revision_ >> 8, lmp_pal_version_,
502                               manufacturer_name_, manufacturer_name_ >> 8,
503                               lmp_pal_subversion_, lmp_pal_subversion_ >> 8});
504}
505
506const std::vector<uint8_t> DualModeController::Properties::GetBdAddress() {
507  return bd_address_;
508}
509
510const std::vector<uint8_t>
511DualModeController::Properties::GetLocalExtendedFeatures(uint8_t page_number) {
512  return std::vector<uint8_t>({kSuccessStatus, page_number,
513                               maximum_page_number_, 0xFF, 0xFF, 0xFF, 0xFF,
514                               0xFF, 0xFF, 0xFF, 0xFF});
515}
516
517const std::vector<uint8_t>
518DualModeController::Properties::GetLocalSupportedCommands() {
519  std::vector<uint8_t> local_supported_commands;
520  local_supported_commands.push_back(kSuccessStatus);
521  for (uint8_t i = 0; i < local_supported_commands_size_; ++i)
522    local_supported_commands.push_back(0xFF);
523  return local_supported_commands;
524}
525
526const std::vector<uint8_t> DualModeController::Properties::GetLocalName() {
527  std::vector<uint8_t> local_name;
528  local_name.push_back(kSuccessStatus);
529  for (uint8_t i = 0; i < local_name_size_; ++i)
530    local_name.push_back(0xFF);
531  return local_name;
532}
533
534// static
535void DualModeController::Properties::RegisterJSONConverter(
536    base::JSONValueConverter<DualModeController::Properties>* converter) {
537  // TODO(dennischeng): Use RegisterIntField() here?
538#define REGISTER_UINT8_T(field_name, field) \
539  converter->RegisterCustomField<uint8_t>(  \
540      field_name, &DualModeController::Properties::field, &ParseUint8t);
541#define REGISTER_UINT16_T(field_name, field) \
542  converter->RegisterCustomField<uint16_t>(  \
543      field_name, &DualModeController::Properties::field, &ParseUint16t);
544  REGISTER_UINT16_T("AclDataPacketSize", acl_data_packet_size_);
545  REGISTER_UINT8_T("ScoDataPacketSize", sco_data_packet_size_);
546  REGISTER_UINT16_T("NumAclDataPackets", num_acl_data_packets_);
547  REGISTER_UINT16_T("NumScoDataPackets", num_sco_data_packets_);
548  REGISTER_UINT8_T("Version", version_);
549  REGISTER_UINT16_T("Revision", revision_);
550  REGISTER_UINT8_T("LmpPalVersion", lmp_pal_version_);
551  REGISTER_UINT16_T("ManufacturerName", manufacturer_name_);
552  REGISTER_UINT16_T("LmpPalSubversion", lmp_pal_subversion_);
553  REGISTER_UINT8_T("MaximumPageNumber", maximum_page_number_);
554  converter->RegisterCustomField<std::vector<uint8_t>>(
555      "BdAddress", &DualModeController::Properties::bd_address_,
556      &ParseUint8tVector);
557#undef REGISTER_UINT8_T
558#undef REGISTER_UINT16_T
559}
560
561}  // namespace test_vendor_lib
562