Yet another go at getting the Xbox One S controller working

It just connects and opens a SDP channel it then disconnects the SDP channel and I get a "Paring Faild: 05 (Authentication Failure)"

For some reason I never receive the "IO Capability Request" event
This commit is contained in:
Kristian Sloth Lauszus 2019-08-31 18:22:21 +02:00
parent 8d7265f92c
commit ad9360b865
4 changed files with 236 additions and 41 deletions

64
BTD.cpp
View file

@ -430,26 +430,34 @@ void BTD::HCI_event_task() {
D_PrintHex<uint8_t > (hcibuf[8 + i], 0x80);
}
#endif
#ifdef DEBUG_USB_HOST
if(hcibuf[6] == 0) { // Page 0
#ifdef DEBUG_USB_HOST
Notify(PSTR("\r\nDongle "), 0x80);
#endif
if(hcibuf[8 + 6] & (1U << 3)) {
simple_pairing_supported = true;
#ifdef DEBUG_USB_HOST
Notify(PSTR("supports"), 0x80);
#endif
} else {
simple_pairing_supported = false;
#ifdef DEBUG_USB_HOST
Notify(PSTR("does NOT support"), 0x80);
#endif
}
#ifdef DEBUG_USB_HOST
Notify(PSTR(" secure simple pairing (controller support)"), 0x80);
#endif
} else if(hcibuf[6] == 1) { // Page 1
#ifdef DEBUG_USB_HOST
Notify(PSTR("\r\nDongle "), 0x80);
if(hcibuf[8 + 0] & (1U << 0))
Notify(PSTR("supports"), 0x80);
else
Notify(PSTR("does NOT support"), 0x80);
Notify(PSTR(" secure simple pairing (host support)"), 0x80);
}
#endif
}
}
hci_set_flag(HCI_FLAG_LOCAL_EXTENDED_FEATURES);
@ -650,6 +658,10 @@ void BTD::HCI_event_task() {
Notify(PSTR("\r\nPairing successful with HID device"), 0x80);
#endif
connectToHIDDevice = true; // Used to indicate to the BTHID service, that it should connect to this device
} else {
#ifdef DEBUG_USB_HOST
Notify(PSTR("\r\nPairing was successful"), 0x80);
#endif
}
} else {
#ifdef DEBUG_USB_HOST
@ -744,6 +756,12 @@ void BTD::HCI_event_task() {
if(hcibuf[0] != 0x00) {
Notify(PSTR("\r\nUnmanaged HCI Event: "), 0x80);
D_PrintHex<uint8_t > (hcibuf[0], 0x80);
Notify(PSTR(", data: "), 0x80);
for(uint16_t i = 0; i < hcibuf[1]; i++) {
D_PrintHex<uint8_t > (hcibuf[2 + i], 0x80);
Notify(PSTR(" "), 0x80);
}
}
break;
#endif
@ -939,6 +957,12 @@ void BTD::HCI_task() {
case HCI_REMOTE_EXTENDED_FEATURES_STATE:
if(hci_check_flag(HCI_FLAG_REMOTE_EXTENDED_FEATURES)) {
/*hci_read_remote_version_information();
delay(1);
hci_change_connection_packet_type_command();
delay(1);
hci_write_link_policy_settings();
delay(1);*/
hci_authentication_request();
hci_state = HCI_SCANNING_STATE;
}
@ -1255,7 +1279,7 @@ void BTD::hci_connect() {
void BTD::hci_connect(uint8_t *bdaddr) {
hci_clear_flag(HCI_FLAG_CONNECT_COMPLETE | HCI_FLAG_CONNECT_EVENT);
hcibuf[0] = 0x05;
hcibuf[0] = 0x05; // HCI OCF = 5
hcibuf[1] = 0x01 << 2; // HCI OGF = 1
hcibuf[2] = 0x0D; // parameter Total Length = 13
hcibuf[3] = bdaddr[0]; // 6 octet bdaddr (LSB)
@ -1275,6 +1299,40 @@ void BTD::hci_connect(uint8_t *bdaddr) {
HCI_Command(hcibuf, 16);
}
void BTD::hci_read_remote_version_information() {
hcibuf[0] = 0x1D; // HCI OCF = 1D
hcibuf[1] = 0x01 << 2; // HCI OGF = 1
hcibuf[2] = 0x02; // parameter Total Length = 2
hcibuf[3] = (uint8_t)(hci_handle & 0xFF); //connection handle - low byte
hcibuf[4] = (uint8_t)((hci_handle >> 8) & 0x0F); //connection handle - high byte
HCI_Command(hcibuf, 5);
}
void BTD::hci_change_connection_packet_type_command() {
hcibuf[0] = 0x0F; // HCI OCF = 0F
hcibuf[1] = 0x01 << 2; // HCI OGF = 1
hcibuf[2] = 0x04; // parameter Total Length = 4
hcibuf[3] = (uint8_t)(hci_handle & 0xFF); //connection handle - low byte
hcibuf[4] = (uint8_t)((hci_handle >> 8) & 0x0F); //connection handle - high byte
hcibuf[5] = 0x18; // DM1 or DH1 may be used
hcibuf[6] = 0xCC; // DM3, DH3, DM5, DH5 may be used
HCI_Command(hcibuf, 7);
}
void BTD::hci_write_link_policy_settings() {
hcibuf[0] = 0x0D; // HCI OCF = 0D
hcibuf[1] = 0x02 << 2; // HCI OGF = 2
hcibuf[2] = 0x04; // parameter Total Length = 4
hcibuf[3] = (uint8_t)(hci_handle & 0xFF); //connection handle - low byte
hcibuf[4] = (uint8_t)((hci_handle >> 8) & 0x0F); //connection handle - high byte
hcibuf[5] = 0x0F; // Enable role switch, enable hold mode, enable sniff mode, enable park mode
hcibuf[6] = 0x00;
HCI_Command(hcibuf, 7);
}
void BTD::hci_pin_code_request_reply() {
hcibuf[0] = 0x0D; // HCI OCF = 0D
hcibuf[1] = 0x01 << 2; // HCI OGF = 1

11
BTD.h
View file

@ -196,8 +196,8 @@
#define SDP_SERVICE_SEARCH_RESPONSE 0x03
#define SDP_SERVICE_ATTRIBUTE_REQUEST 0x04
#define SDP_SERVICE_ATTRIBUTE_RESPONSE 0x05
#define SDP_SERVICE_SEARCH_ATTRIBUTE_REQUEST_PDU 0x06 // See the RFCOMM specs
#define SDP_SERVICE_SEARCH_ATTRIBUTE_RESPONSE_PDU 0x07 // See the RFCOMM specs
#define SDP_SERVICE_SEARCH_ATTRIBUTE_REQUEST 0x06 // See the RFCOMM specs
#define SDP_SERVICE_SEARCH_ATTRIBUTE_RESPONSE 0x07 // See the RFCOMM specs
#define PNP_INFORMATION_UUID 0x1200
#define SERIALPORT_UUID 0x1101 // See http://www.bluetooth.org/Technical/AssignedNumbers/service_discovery.htm
#define L2CAP_UUID 0x0100
@ -386,6 +386,13 @@ public:
void hci_inquiry_cancel();
/** Connect to last device communicated with. */
void hci_connect();
void hci_read_remote_version_information();
void hci_change_connection_packet_type_command();
void hci_write_link_policy_settings();
/**
* Connect to device.
* @param bdaddr Bluetooth address of the device.

175
BTHID.cpp
View file

@ -30,6 +30,8 @@ protocolMode(USB_HID_BOOT_PROTOCOL) {
pBtd->btdPin = pin;
/* Set device cid for the control and intterrupt channelse - LSB */
sdp_dcid[0] = 0x50; // 0x0050
sdp_dcid[1] = 0x00;
control_dcid[0] = 0x70; // 0x0070
control_dcid[1] = 0x00;
interrupt_dcid[0] = 0x71; // 0x0071
@ -59,6 +61,7 @@ void BTHID::disconnect() { // Use this void to disconnect the device
}
void BTHID::ACLData(uint8_t* l2capinbuf) {
/*
Notify(PSTR("\r\nL2CAP Data - Channel ID: "), 0x80);
D_PrintHex<uint8_t > (l2capinbuf[7], 0x80);
Notify(PSTR(" "), 0x80);
@ -69,6 +72,7 @@ void BTHID::ACLData(uint8_t* l2capinbuf) {
D_PrintHex<uint8_t > (l2capinbuf[i + 8], 0x80);
Notify(PSTR(" "), 0x80);
}
*/
if(!connected) {
if(l2capinbuf[8] == L2CAP_CMD_CONNECTION_REQUEST) {
@ -111,14 +115,25 @@ void BTHID::ACLData(uint8_t* l2capinbuf) {
#endif
} else if(l2capinbuf[8] == L2CAP_CMD_CONNECTION_RESPONSE) {
if(((l2capinbuf[16] | (l2capinbuf[17] << 8)) == 0x0000) && ((l2capinbuf[18] | (l2capinbuf[19] << 8)) == SUCCESSFUL)) { // Success
if(l2capinbuf[14] == control_dcid[0] && l2capinbuf[15] == control_dcid[1]) {
//Notify(PSTR("\r\nHID Control Connection Complete"), 0x80);
if(l2capinbuf[14] == sdp_dcid[0] && l2capinbuf[15] == sdp_dcid[1]) {
Notify(PSTR("\r\nSDP Connection Complete"), 0x80);
identifier = l2capinbuf[9];
sdp_scid[0] = l2capinbuf[12];
sdp_scid[1] = l2capinbuf[13];
#ifdef DEBUG_USB_HOST
Notify(PSTR("\r\nSend SDP Config Request"), 0x80);
#endif
identifier++;
pBtd->l2cap_config_request(hci_handle, identifier, sdp_scid);
} else if(l2capinbuf[14] == control_dcid[0] && l2capinbuf[15] == control_dcid[1]) {
Notify(PSTR("\r\nHID Control Connection Complete"), 0x80);
identifier = l2capinbuf[9];
control_scid[0] = l2capinbuf[12];
control_scid[1] = l2capinbuf[13];
l2cap_set_flag(L2CAP_FLAG_CONTROL_CONNECTED);
} else if(l2capinbuf[14] == interrupt_dcid[0] && l2capinbuf[15] == interrupt_dcid[1]) {
//Notify(PSTR("\r\nHID Interrupt Connection Complete"), 0x80);
Notify(PSTR("\r\nHID Interrupt Connection Complete"), 0x80);
identifier = l2capinbuf[9];
interrupt_scid[0] = l2capinbuf[12];
interrupt_scid[1] = l2capinbuf[13];
@ -157,28 +172,28 @@ void BTHID::ACLData(uint8_t* l2capinbuf) {
} else if(l2capinbuf[8] == L2CAP_CMD_CONFIG_RESPONSE) {
if((l2capinbuf[16] | (l2capinbuf[17] << 8)) == 0x0000) { // Success
if(l2capinbuf[12] == sdp_dcid[0] && l2capinbuf[13] == sdp_dcid[1]) {
//Notify(PSTR("\r\nSDP Configuration Complete"), 0x80);
Notify(PSTR("\r\nSDP Configuration Complete"), 0x80);
identifier = l2capinbuf[9];
l2cap_set_flag(L2CAP_FLAG_CONFIG_SDP_SUCCESS);
} else if(l2capinbuf[12] == control_dcid[0] && l2capinbuf[13] == control_dcid[1]) {
//Notify(PSTR("\r\nHID Control Configuration Complete"), 0x80);
Notify(PSTR("\r\nHID Control Configuration Complete"), 0x80);
identifier = l2capinbuf[9];
l2cap_set_flag(L2CAP_FLAG_CONFIG_CONTROL_SUCCESS);
} else if(l2capinbuf[12] == interrupt_dcid[0] && l2capinbuf[13] == interrupt_dcid[1]) {
//Notify(PSTR("\r\nHID Interrupt Configuration Complete"), 0x80);
Notify(PSTR("\r\nHID Interrupt Configuration Complete"), 0x80);
identifier = l2capinbuf[9];
l2cap_set_flag(L2CAP_FLAG_CONFIG_INTERRUPT_SUCCESS);
}
}
} else if(l2capinbuf[8] == L2CAP_CMD_CONFIG_REQUEST) {
if(l2capinbuf[12] == sdp_dcid[0] && l2capinbuf[13] == sdp_dcid[1]) {
//Notify(PSTR("\r\nSDP Configuration Request"), 0x80);
Notify(PSTR("\r\nSDP Configuration Request"), 0x80);
pBtd->l2cap_config_response(hci_handle, l2capinbuf[9], sdp_scid);
} else if(l2capinbuf[12] == control_dcid[0] && l2capinbuf[13] == control_dcid[1]) {
//Notify(PSTR("\r\nHID Control Configuration Request"), 0x80);
Notify(PSTR("\r\nHID Control Configuration Request"), 0x80);
pBtd->l2cap_config_response(hci_handle, l2capinbuf[9], control_scid);
} else if(l2capinbuf[12] == interrupt_dcid[0] && l2capinbuf[13] == interrupt_dcid[1]) {
//Notify(PSTR("\r\nHID Interrupt Configuration Request"), 0x80);
Notify(PSTR("\r\nHID Interrupt Configuration Request"), 0x80);
pBtd->l2cap_config_response(hci_handle, l2capinbuf[9], interrupt_scid);
}
} else if(l2capinbuf[8] == L2CAP_CMD_DISCONNECT_REQUEST) {
@ -271,6 +286,10 @@ void BTHID::ACLData(uint8_t* l2capinbuf) {
SDP_Command(l2capoutbuf, 14);
#endif
//pBtd->hci_authentication_request();
//identifier++;
//pBtd->l2cap_connection_request(hci_handle, identifier, sdp_dcid, SDP_PSM);
} else if(l2capinbuf[8] == SDP_SERVICE_ATTRIBUTE_REQUEST) {
Notify(PSTR("\r\nSDP_SERVICE_ATTRIBUTE_REQUEST"), 0x80);
@ -279,6 +298,7 @@ void BTHID::ACLData(uint8_t* l2capinbuf) {
l2capoutbuf[1] = l2capinbuf[9];//transactionIDHigh;
l2capoutbuf[2] = l2capinbuf[10];//transactionIDLow;
#if 1
l2capoutbuf[3] = 0x00; // MSB Parameter Length
l2capoutbuf[4] = 0x05; // LSB Parameter Length = 5
@ -292,8 +312,139 @@ void BTHID::ACLData(uint8_t* l2capinbuf) {
l2capoutbuf[9] = 0x00; // No continuation state
SDP_Command(l2capoutbuf, 10);
} else if(l2capinbuf[8] == SDP_SERVICE_SEARCH_ATTRIBUTE_REQUEST_PDU) {
Notify(PSTR("\r\nSDP_SERVICE_SEARCH_ATTRIBUTE_REQUEST_PDU"), 0x80);
#else
size_t i = 3;
l2capoutbuf[i++] = 0x00;
l2capoutbuf[i++] = 0x5a;
l2capoutbuf[i++] = 0x00;
l2capoutbuf[i++] = 0x57;
l2capoutbuf[i++] = 0x35;
l2capoutbuf[i++] = 0x55;
l2capoutbuf[i++] = 0x09;
l2capoutbuf[i++] = 0x00;
l2capoutbuf[i++] = 0x00;
l2capoutbuf[i++] = 0x0a;
l2capoutbuf[i++] = 0x00;
l2capoutbuf[i++] = 0x01;
l2capoutbuf[i++] = 0x00;
l2capoutbuf[i++] = 0x01;
l2capoutbuf[i++] = 0x09;
l2capoutbuf[i++] = 0x00;
l2capoutbuf[i++] = 0x01;
l2capoutbuf[i++] = 0x35;
l2capoutbuf[i++] = 0x03;
l2capoutbuf[i++] = 0x19;
l2capoutbuf[i++] = 0x12;
l2capoutbuf[i++] = 0x00;
l2capoutbuf[i++] = 0x09;
l2capoutbuf[i++] = 0x00;
l2capoutbuf[i++] = 0x05;
l2capoutbuf[i++] = 0x35;
l2capoutbuf[i++] = 0x03;
l2capoutbuf[i++] = 0x19;
l2capoutbuf[i++] = 0x10;
l2capoutbuf[i++] = 0x02;
l2capoutbuf[i++] = 0x09;
l2capoutbuf[i++] = 0x00;
l2capoutbuf[i++] = 0x06;
l2capoutbuf[i++] = 0x35;
l2capoutbuf[i++] = 0x09;
l2capoutbuf[i++] = 0x09;
l2capoutbuf[i++] = 0x65;
l2capoutbuf[i++] = 0x6e;
l2capoutbuf[i++] = 0x09;
l2capoutbuf[i++] = 0x00;
l2capoutbuf[i++] = 0x6a;
l2capoutbuf[i++] = 0x09;
l2capoutbuf[i++] = 0x01;
l2capoutbuf[i++] = 0x00;
l2capoutbuf[i++] = 0x09;
l2capoutbuf[i++] = 0x02;
l2capoutbuf[i++] = 0x00;
l2capoutbuf[i++] = 0x09;
l2capoutbuf[i++] = 0x01;
l2capoutbuf[i++] = 0x03;
l2capoutbuf[i++] = 0x09;
l2capoutbuf[i++] = 0x02;
l2capoutbuf[i++] = 0x01;
l2capoutbuf[i++] = 0x09;
l2capoutbuf[i++] = 0x00;
l2capoutbuf[i++] = 0x4c;
l2capoutbuf[i++] = 0x09;
l2capoutbuf[i++] = 0x02;
l2capoutbuf[i++] = 0x02;
l2capoutbuf[i++] = 0x09;
l2capoutbuf[i++] = 0x4a;
l2capoutbuf[i++] = 0x34;
l2capoutbuf[i++] = 0x09;
l2capoutbuf[i++] = 0x02;
l2capoutbuf[i++] = 0x03;
l2capoutbuf[i++] = 0x09;
l2capoutbuf[i++] = 0x10;
l2capoutbuf[i++] = 0x11;
l2capoutbuf[i++] = 0x09;
l2capoutbuf[i++] = 0x02;
l2capoutbuf[i++] = 0x04;
l2capoutbuf[i++] = 0x28;
l2capoutbuf[i++] = 0x01;
l2capoutbuf[i++] = 0x09;
l2capoutbuf[i++] = 0x02;
l2capoutbuf[i++] = 0x05;
l2capoutbuf[i++] = 0x09;
l2capoutbuf[i++] = 0x00;
l2capoutbuf[i++] = 0x01;
l2capoutbuf[i++] = 0x09;
l2capoutbuf[i++] = 0xa0;
l2capoutbuf[i++] = 0x00;
l2capoutbuf[i++] = 0x09;
l2capoutbuf[i++] = 0x16;
l2capoutbuf[i++] = 0xc4;
l2capoutbuf[i++] = 0x09;
l2capoutbuf[i++] = 0xaf;
l2capoutbuf[i++] = 0xff;
l2capoutbuf[i++] = 0x09;
l2capoutbuf[i++] = 0x00;
l2capoutbuf[i++] = 0x01;
l2capoutbuf[i++] = 0x00;
Serial.print("\nLENGTH: ");
Serial.println(i);
SDP_Command(l2capoutbuf, i);
#endif
/*
l2capoutbuf[0] = SDP_SERVICE_SEARCH_ATTRIBUTE_REQUEST;
l2capoutbuf[1] = 0x00; // TODO: Do not hardcode
l2capoutbuf[2] = 0x01;
l2capoutbuf[3] = 0x00; // MSB Parameter Length
l2capoutbuf[4] = 0x0F; // LSB Parameter Length = 15
i = 5;
l2capoutbuf[i++] = 0x35;
l2capoutbuf[i++] = 0x03;
l2capoutbuf[i++] = 0x19;
l2capoutbuf[i++] = 0x12;
l2capoutbuf[i++] = 0x00;
l2capoutbuf[i++] = 0xff;
l2capoutbuf[i++] = 0xff;
l2capoutbuf[i++] = 0x35;
l2capoutbuf[i++] = 0x05;
l2capoutbuf[i++] = 0x0a;
l2capoutbuf[i++] = 0x00;
l2capoutbuf[i++] = 0x00;
l2capoutbuf[i++] = 0xff;
l2capoutbuf[i++] = 0xff;
l2capoutbuf[i++] = 0x00;
Serial.print("\nLENGTH: ");
Serial.println(i);
SDP_Command(l2capoutbuf, i);
*/
} else if(l2capinbuf[8] == SDP_SERVICE_SEARCH_ATTRIBUTE_REQUEST) {
Notify(PSTR("\r\nSDP_SERVICE_SEARCH_ATTRIBUTE_REQUEST"), 0x80);
#ifdef EXTRADEBUG
Notify(PSTR("\r\nUUID: "), 0x80);
@ -570,7 +721,7 @@ void BTHID::SDP_Command(uint8_t* data, uint8_t nbytes) { // See page 223 in the
}
void BTHID::serviceNotSupported(uint8_t transactionIDHigh, uint8_t transactionIDLow) { // See page 235 in the Bluetooth specs
l2capoutbuf[0] = SDP_SERVICE_SEARCH_ATTRIBUTE_RESPONSE_PDU;
l2capoutbuf[0] = SDP_SERVICE_SEARCH_ATTRIBUTE_RESPONSE;
l2capoutbuf[1] = transactionIDHigh;
l2capoutbuf[2] = transactionIDLow;
l2capoutbuf[3] = 0x00; // MSB Parameter Length

27
SPP.cpp
View file

@ -189,7 +189,7 @@ void SPP::ACLData(uint8_t* l2capinbuf) {
}
#endif
} else if(l2capinbuf[6] == sdp_dcid[0] && l2capinbuf[7] == sdp_dcid[1]) { // SDP
if(l2capinbuf[8] == SDP_SERVICE_SEARCH_ATTRIBUTE_REQUEST_PDU) {
if(l2capinbuf[8] == SDP_SERVICE_SEARCH_ATTRIBUTE_REQUEST) {
if(((l2capinbuf[16] << 8 | l2capinbuf[17]) == SERIALPORT_UUID) || ((l2capinbuf[16] << 8 | l2capinbuf[17]) == 0x0000 && (l2capinbuf[18] << 8 | l2capinbuf[19]) == SERIALPORT_UUID)) { // Check if it's sending the full UUID, see: https://www.bluetooth.org/Technical/AssignedNumbers/service_discovery.htm, we will just check the first four bytes
if(firstMessage) {
serialPortResponse1(l2capinbuf[9], l2capinbuf[10]);
@ -531,29 +531,8 @@ void SPP::RFCOMM_task() {
/* SDP Commands */
/************************************************************/
void SPP::SDP_Command(uint8_t* data, uint8_t nbytes) { // See page 223 in the Bluetooth specs
pBtd->L2CAP_Command(hci_handle, data, nbytes, sdp_scid[0], sdp_scid[1]);
}
void SPP::serviceNotSupported(uint8_t transactionIDHigh, uint8_t transactionIDLow) { // See page 235 in the Bluetooth specs
l2capoutbuf[0] = SDP_SERVICE_SEARCH_ATTRIBUTE_RESPONSE_PDU;
l2capoutbuf[1] = transactionIDHigh;
l2capoutbuf[2] = transactionIDLow;
l2capoutbuf[3] = 0x00; // MSB Parameter Length
l2capoutbuf[4] = 0x05; // LSB Parameter Length = 5
l2capoutbuf[5] = 0x00; // MSB AttributeListsByteCount
l2capoutbuf[6] = 0x02; // LSB AttributeListsByteCount = 2
/* Attribute ID/Value Sequence: */
l2capoutbuf[7] = 0x35; // Data element sequence - length in next byte
l2capoutbuf[8] = 0x00; // Length = 0
l2capoutbuf[9] = 0x00; // No continuation state
SDP_Command(l2capoutbuf, 10);
}
void SPP::serialPortResponse1(uint8_t transactionIDHigh, uint8_t transactionIDLow) {
l2capoutbuf[0] = SDP_SERVICE_SEARCH_ATTRIBUTE_RESPONSE_PDU;
l2capoutbuf[0] = SDP_SERVICE_SEARCH_ATTRIBUTE_RESPONSE;
l2capoutbuf[1] = transactionIDHigh;
l2capoutbuf[2] = transactionIDLow;
l2capoutbuf[3] = 0x00; // MSB Parameter Length
@ -615,7 +594,7 @@ void SPP::serialPortResponse1(uint8_t transactionIDHigh, uint8_t transactionIDLo
}
void SPP::serialPortResponse2(uint8_t transactionIDHigh, uint8_t transactionIDLow) {
l2capoutbuf[0] = SDP_SERVICE_SEARCH_ATTRIBUTE_RESPONSE_PDU;
l2capoutbuf[0] = SDP_SERVICE_SEARCH_ATTRIBUTE_RESPONSE;
l2capoutbuf[1] = transactionIDHigh;
l2capoutbuf[2] = transactionIDLow;
l2capoutbuf[3] = 0x00; // MSB Parameter Length