Merge pull request #43 from kmark/master

Improved PS3 rumble support
This commit is contained in:
Kristian Sloth Lauszus 2013-03-30 08:00:17 -07:00
commit 67d245107b
56 changed files with 17499 additions and 17445 deletions

417
BTD.cpp

File diff suppressed because it is too large Load diff

35
BTD.h
View file

@ -178,16 +178,22 @@ public:
* @return 0 on success.
*/
virtual uint8_t Poll();
/**
* Get the device address.
* @return The device address.
*/
virtual uint8_t GetAddress() { return bAddress; };
virtual uint8_t GetAddress() {
return bAddress;
};
/**
* Used to check if the dongle has been initialized.
* @return True if it's ready.
*/
virtual bool isReady() { return bPollEnable; };
virtual bool isReady() {
return bPollEnable;
};
/**@}*/
/** @name UsbConfigXtracter implementation */
@ -204,18 +210,19 @@ public:
/** Disconnects both the L2CAP Channel and the HCI Connection for all Bluetooth services. */
void disconnect() {
for (uint8_t i=0; i<BTD_NUMSERVICES; i++)
if (btService[i])
for(uint8_t i = 0; i < BTD_NUMSERVICES; i++)
if(btService[i])
btService[i]->disconnect();
};
/**
* Register bluetooth dongle members/services.
* @param pService Pointer to BluetoothService class instance.
* @return The serice ID on succes or -1 on fail.
*/
int8_t registerServiceClass(BluetoothService *pService) {
for (uint8_t i=0; i<BTD_NUMSERVICES; i++) {
if (!btService[i]) {
for(uint8_t i = 0; i < BTD_NUMSERVICES; i++) {
if(!btService[i]) {
btService[i] = pService;
return i; // Return ID
}
@ -373,8 +380,12 @@ public:
* it should be at least 3 to work properly with the library.
*/
uint8_t hci_version;
/** Call this function to pair with a Wiimote */
void pairWithWiimote() { pairWithWii = true; hci_state = HCI_CHECK_WII_SERVICE; };
void pairWithWiimote() {
pairWithWii = true;
hci_state = HCI_CHECK_WII_SERVICE;
};
/** Used to only send the ACL data to the wiimote. */
bool connectToWii;
/** True if a Wiimote is connecting. */
@ -390,7 +401,9 @@ public:
* Read the poll interval taken from the endpoint descriptors.
* @return The poll interval in ms.
*/
uint8_t readPollInterval() { return pollInterval; };
uint8_t readPollInterval() {
return pollInterval;
};
protected:
/** Pointer to USB class instance. */
@ -435,9 +448,9 @@ private:
uint16_t hci_event_flag; // hci flags of received bluetooth events
uint8_t inquiry_counter;
uint8_t hcibuf[BULK_MAXPKTSIZE];//General purpose buffer for hci data
uint8_t l2capinbuf[BULK_MAXPKTSIZE];//General purpose buffer for l2cap in data
uint8_t l2capoutbuf[BULK_MAXPKTSIZE];//General purpose buffer for l2cap out data
uint8_t hcibuf[BULK_MAXPKTSIZE]; //General purpose buffer for hci data
uint8_t l2capinbuf[BULK_MAXPKTSIZE]; //General purpose buffer for l2cap in data
uint8_t l2capoutbuf[BULK_MAXPKTSIZE]; //General purpose buffer for l2cap out data
/* State machines */
void HCI_event_task(); // Poll the HCI event pipe

359
PS3BT.cpp
View file

@ -32,7 +32,7 @@ const uint8_t OUTPUT_REPORT_BUFFER[] PROGMEM = {
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
};
PS3BT::PS3BT(BTD *p, uint8_t btadr5, uint8_t btadr4, uint8_t btadr3, uint8_t btadr2, uint8_t btadr1, uint8_t btadr0):
PS3BT::PS3BT(BTD *p, uint8_t btadr5, uint8_t btadr4, uint8_t btadr3, uint8_t btadr2, uint8_t btadr1, uint8_t btadr0) :
pBtd(p) // pointer to USB class instance - mandatory
{
if (pBtd)
@ -45,49 +45,54 @@ pBtd(p) // pointer to USB class instance - mandatory
pBtd->my_bdaddr[1] = btadr1;
pBtd->my_bdaddr[0] = btadr0;
HIDBuffer[0] = 0x52;// HID BT Set_report (0x50) | Report Type (Output 0x02)
HIDBuffer[1] = 0x01;// Report ID
HIDBuffer[0] = 0x52; // HID BT Set_report (0x50) | Report Type (Output 0x02)
HIDBuffer[1] = 0x01; // Report ID
//Needed for PS3 Move Controller commands to work via bluetooth
HIDMoveBuffer[0] = 0xA2;// HID BT DATA_request (0xA0) | Report Type (Output 0x02)
HIDMoveBuffer[1] = 0x02;// Report ID
HIDMoveBuffer[0] = 0xA2; // HID BT DATA_request (0xA0) | Report Type (Output 0x02)
HIDMoveBuffer[1] = 0x02; // Report ID
/* Set device cid for the control and intterrupt channelse - LSB */
control_dcid[0] = 0x40;//0x0040
control_dcid[0] = 0x40; //0x0040
control_dcid[1] = 0x00;
interrupt_dcid[0] = 0x41;//0x0041
interrupt_dcid[0] = 0x41; //0x0041
interrupt_dcid[1] = 0x00;
Reset();
}
bool PS3BT::getButtonPress(Button b) {
return (ButtonState & pgm_read_dword(&BUTTONS[(uint8_t)b]));
}
bool PS3BT::getButtonClick(Button b) {
uint32_t button = pgm_read_dword(&BUTTONS[(uint8_t)b]);
bool click = (ButtonClickState & button);
ButtonClickState &= ~button; // clear "click" event
return click;
}
uint8_t PS3BT::getAnalogButton(Button a) {
if (l2capinbuf == NULL)
return 0;
return (uint8_t)(l2capinbuf[pgm_read_byte(&ANALOGBUTTONS[(uint8_t)a])]);
}
uint8_t PS3BT::getAnalogHat(AnalogHat a) {
if (l2capinbuf == NULL)
return 0;
return (uint8_t)(l2capinbuf[(uint8_t)a+15]);
return (uint8_t)(l2capinbuf[(uint8_t)a + 15]);
}
int16_t PS3BT::getSensor(Sensor a) {
if (l2capinbuf == NULL)
return 0;
if(PS3Connected) {
if (PS3Connected) {
if (a == aX || a == aY || a == aZ || a == gZ)
return ((l2capinbuf[(uint16_t)a] << 8) | l2capinbuf[(uint16_t)a + 1]);
else
return 0;
} else if(PS3MoveConnected) {
} else if (PS3MoveConnected) {
if (a == mXmove || a == mYmove) // These are all 12-bits long
return (((l2capinbuf[(uint16_t)a] & 0x0F) << 8) | (l2capinbuf[(uint16_t)a + 1]));
else if (a == mZmove || a == tempMove) // The tempearature is also 12 bits long
@ -97,77 +102,81 @@ int16_t PS3BT::getSensor(Sensor a) {
} else
return 0;
}
double PS3BT::getAngle(Angle a) {
double accXval;
double accYval;
double accZval;
if(PS3Connected) {
if (PS3Connected) {
// Data for the Kionix KXPC4 used in the DualShock 3
const double zeroG = 511.5; // 1.65/3.3*1023 (1,65V)
accXval = -((double)getSensor(aX)-zeroG);
accYval = -((double)getSensor(aY)-zeroG);
accZval = -((double)getSensor(aZ)-zeroG);
} else if(PS3MoveConnected) {
accXval = -((double)getSensor(aX) - zeroG);
accYval = -((double)getSensor(aY) - zeroG);
accZval = -((double)getSensor(aZ) - zeroG);
} else if (PS3MoveConnected) {
// It's a Kionix KXSC4 inside the Motion controller
const uint16_t zeroG = 0x8000;
accXval = -(int16_t)(getSensor(aXmove)-zeroG);
accYval = (int16_t)(getSensor(aYmove)-zeroG);
accZval = (int16_t)(getSensor(aZmove)-zeroG);
accXval = -(int16_t)(getSensor(aXmove) - zeroG);
accYval = (int16_t)(getSensor(aYmove) - zeroG);
accZval = (int16_t)(getSensor(aZmove) - zeroG);
}
// Convert to 360 degrees resolution
// atan2 outputs the value of -π to π (radians)
// We are then converting it to 0 to 2π and then to degrees
if (a == Pitch) {
double angle = (atan2(accYval,accZval)+PI)*RAD_TO_DEG;
double angle = (atan2(accYval, accZval) + PI) * RAD_TO_DEG;
return angle;
} else {
double angle = (atan2(accXval,accZval)+PI)*RAD_TO_DEG;
double angle = (atan2(accXval, accZval) + PI) * RAD_TO_DEG;
return angle;
}
}
double PS3BT::get9DOFValues(Sensor a) { // Thanks to Manfred Piendl
if(!PS3MoveConnected)
if (!PS3MoveConnected)
return 0;
int16_t value = getSensor(a);
if (a == mXmove || a == mYmove || a == mZmove) {
if (value > 2047)
value -= 0x1000;
return (double)value/3.2; // unit: muT = 10^(-6) Tesla
return (double)value / 3.2; // unit: muT = 10^(-6) Tesla
} else if (a == aXmove || a == aYmove || a == aZmove) {
if (value < 0)
value += 0x8000;
else
value -= 0x8000;
return (double)value/442.0; // unit: m/(s^2)
return (double)value / 442.0; // unit: m/(s^2)
} else if (a == gXmove || a == gYmove || a == gZmove) {
if (value < 0)
value += 0x8000;
else
value -= 0x8000;
if (a == gXmove)
return (double)value/11.6; // unit: deg/s
return (double)value / 11.6; // unit: deg/s
else if (a == gYmove)
return (double)value/11.2; // unit: deg/s
return (double)value / 11.2; // unit: deg/s
else // gZmove
return (double)value/9.6; // unit: deg/s
return (double)value / 9.6; // unit: deg/s
} else
return 0;
}
String PS3BT::getTemperature() {
if(PS3MoveConnected) {
if (PS3MoveConnected) {
int16_t input = getSensor(tempMove);
String output = String(input/100);
String output = String(input / 100);
output += ".";
if(input%100 < 10)
if (input % 100 < 10)
output += "0";
output += String(input%100);
output += String(input % 100);
return output;
}
}
bool PS3BT::getStatus(Status c) {
if (l2capinbuf == NULL)
return false;
@ -175,55 +184,56 @@ bool PS3BT::getStatus(Status c) {
return true;
return false;
}
String PS3BT::getStatusString() {
if (PS3Connected || PS3NavigationConnected) {
char statusOutput[100];
strcpy(statusOutput,"ConnectionStatus: ");
strcpy(statusOutput, "ConnectionStatus: ");
if (getStatus(Plugged)) strcat(statusOutput,"Plugged");
else if (getStatus(Unplugged)) strcat(statusOutput,"Unplugged");
else strcat(statusOutput,"Error");
if (getStatus(Plugged)) strcat(statusOutput, "Plugged");
else if (getStatus(Unplugged)) strcat(statusOutput, "Unplugged");
else strcat(statusOutput, "Error");
strcat(statusOutput," - PowerRating: ");
if (getStatus(Charging)) strcat(statusOutput,"Charging");
else if (getStatus(NotCharging)) strcat(statusOutput,"Not Charging");
else if (getStatus(Shutdown)) strcat(statusOutput,"Shutdown");
else if (getStatus(Dying)) strcat(statusOutput,"Dying");
else if (getStatus(Low)) strcat(statusOutput,"Low");
else if (getStatus(High)) strcat(statusOutput,"High");
else if (getStatus(Full)) strcat(statusOutput,"Full");
else strcat(statusOutput,"Error");
strcat(statusOutput, " - PowerRating: ");
if (getStatus(Charging)) strcat(statusOutput, "Charging");
else if (getStatus(NotCharging)) strcat(statusOutput, "Not Charging");
else if (getStatus(Shutdown)) strcat(statusOutput, "Shutdown");
else if (getStatus(Dying)) strcat(statusOutput, "Dying");
else if (getStatus(Low)) strcat(statusOutput, "Low");
else if (getStatus(High)) strcat(statusOutput, "High");
else if (getStatus(Full)) strcat(statusOutput, "Full");
else strcat(statusOutput, "Error");
strcat(statusOutput," - WirelessStatus: ");
strcat(statusOutput, " - WirelessStatus: ");
if (getStatus(CableRumble)) strcat(statusOutput,"Cable - Rumble is on");
else if (getStatus(Cable)) strcat(statusOutput,"Cable - Rumble is off");
else if (getStatus(BluetoothRumble)) strcat(statusOutput,"Bluetooth - Rumble is on");
else if (getStatus(Bluetooth)) strcat(statusOutput,"Bluetooth - Rumble is off");
else strcat(statusOutput,"Error");
if (getStatus(CableRumble)) strcat(statusOutput, "Cable - Rumble is on");
else if (getStatus(Cable)) strcat(statusOutput, "Cable - Rumble is off");
else if (getStatus(BluetoothRumble)) strcat(statusOutput, "Bluetooth - Rumble is on");
else if (getStatus(Bluetooth)) strcat(statusOutput, "Bluetooth - Rumble is off");
else strcat(statusOutput, "Error");
return statusOutput;
}
else if(PS3MoveConnected) {
} else if (PS3MoveConnected) {
char statusOutput[50];
strcpy(statusOutput,"PowerRating: ");
strcpy(statusOutput, "PowerRating: ");
if (getStatus(MoveCharging)) strcat(statusOutput,"Charging");
else if (getStatus(MoveNotCharging)) strcat(statusOutput,"Not Charging");
else if (getStatus(MoveShutdown)) strcat(statusOutput,"Shutdown");
else if (getStatus(MoveDying)) strcat(statusOutput,"Dying");
else if (getStatus(MoveLow)) strcat(statusOutput,"Low");
else if (getStatus(MoveHigh)) strcat(statusOutput,"High");
else if (getStatus(MoveFull)) strcat(statusOutput,"Full");
else strcat(statusOutput,"Error");
if (getStatus(MoveCharging)) strcat(statusOutput, "Charging");
else if (getStatus(MoveNotCharging)) strcat(statusOutput, "Not Charging");
else if (getStatus(MoveShutdown)) strcat(statusOutput, "Shutdown");
else if (getStatus(MoveDying)) strcat(statusOutput, "Dying");
else if (getStatus(MoveLow)) strcat(statusOutput, "Low");
else if (getStatus(MoveHigh)) strcat(statusOutput, "High");
else if (getStatus(MoveFull)) strcat(statusOutput, "Full");
else strcat(statusOutput, "Error");
return statusOutput;
}
}
void PS3BT::Reset() {
PS3Connected = false;
PS3MoveConnected = false;
@ -239,126 +249,116 @@ void PS3BT::Reset() {
void PS3BT::disconnect() { // Use this void to disconnect any of the controllers
//First the HID interrupt channel has to be disconencted, then the HID control channel and finally the HCI connection
pBtd->l2cap_disconnection_request(hci_handle,0x0A, interrupt_scid, interrupt_dcid);
pBtd->l2cap_disconnection_request(hci_handle, 0x0A, interrupt_scid, interrupt_dcid);
Reset();
l2cap_state = L2CAP_INTERRUPT_DISCONNECT;
}
void PS3BT::ACLData(uint8_t* ACLData) {
if(!pBtd->l2capConnectionClaimed && !PS3Connected && !PS3MoveConnected && !PS3NavigationConnected && !activeConnection && !pBtd->connectToWii && !pBtd->incomingWii && !pBtd->pairWithWii) {
if (!pBtd->l2capConnectionClaimed && !PS3Connected && !PS3MoveConnected && !PS3NavigationConnected && !activeConnection && !pBtd->connectToWii && !pBtd->incomingWii && !pBtd->pairWithWii) {
if (ACLData[8] == L2CAP_CMD_CONNECTION_REQUEST) {
if((ACLData[12] | (ACLData[13] << 8)) == HID_CTRL_PSM) {
if ((ACLData[12] | (ACLData[13] << 8)) == HID_CTRL_PSM) {
pBtd->l2capConnectionClaimed = true; // Claim that the incoming connection belongs to this service
activeConnection = true;
hci_handle = pBtd->hci_handle; // Store the HCI Handle for the connection
l2cap_state = L2CAP_WAIT;
for(uint8_t i = 0; i < 30; i++)
for (uint8_t i = 0; i < 30; i++)
remote_name[i] = pBtd->remote_name[i]; // Store the remote name for the connection
#ifdef DEBUG
if(pBtd->hci_version < 3) { // Check the HCI Version of the Bluetooth dongle
Notify(PSTR("\r\nYour dongle may not support reading the analog buttons, sensors and status\r\nYour HCI Version is: "));
if (pBtd->hci_version < 3) { // Check the HCI Version of the Bluetooth dongle
Notify(PSTR("\r\nYour dongle may not support reading the analog buttons, sensors and status\r\nYour HCI Version is: "), 0x80);
Serial.print(pBtd->hci_version);
Notify(PSTR("\r\nBut should be at least 3\r\nThis means that it doesn't support Bluetooth Version 2.0+EDR"));
Notify(PSTR("\r\nBut should be at least 3\r\nThis means that it doesn't support Bluetooth Version 2.0+EDR"), 0x80);
}
#endif
}
}
}
if (((ACLData[0] | (ACLData[1] << 8)) == (hci_handle | 0x2000))) { //acl_handle_ok
for(uint8_t i = 0; i < BULK_MAXPKTSIZE; i++)
for (uint8_t i = 0; i < BULK_MAXPKTSIZE; i++)
l2capinbuf[i] = ACLData[i];
if ((l2capinbuf[6] | (l2capinbuf[7] << 8)) == 0x0001) { //l2cap_control - Channel ID for ACL-U
if (l2capinbuf[8] == L2CAP_CMD_COMMAND_REJECT) {
#ifdef DEBUG
Notify(PSTR("\r\nL2CAP Command Rejected - Reason: "));
PrintHex<uint8_t>(l2capinbuf[13]);
Notify(PSTR("\r\nL2CAP Command Rejected - Reason: "), 0x80);
PrintHex<uint8_t > (l2capinbuf[13], 0x80);
Serial.print(" ");
PrintHex<uint8_t>(l2capinbuf[12]);
PrintHex<uint8_t > (l2capinbuf[12], 0x80);
Serial.print(" Data: ");
PrintHex<uint8_t>(l2capinbuf[17]);
PrintHex<uint8_t > (l2capinbuf[17], 0x80);
Serial.print(" ");
PrintHex<uint8_t>(l2capinbuf[16]);
PrintHex<uint8_t > (l2capinbuf[16], 0x80);
Serial.print(" ");
PrintHex<uint8_t>(l2capinbuf[15]);
PrintHex<uint8_t > (l2capinbuf[15], 0x80);
Serial.print(" ");
PrintHex<uint8_t>(l2capinbuf[14]);
PrintHex<uint8_t > (l2capinbuf[14], 0x80);
#endif
}
else if (l2capinbuf[8] == L2CAP_CMD_CONNECTION_REQUEST) {
} else if (l2capinbuf[8] == L2CAP_CMD_CONNECTION_REQUEST) {
#ifdef EXTRADEBUG
Notify(PSTR("\r\nL2CAP Connection Request - PSM: "));
PrintHex<uint8_t>(l2capinbuf[13]);
Notify(PSTR(" "));
PrintHex<uint8_t>(l2capinbuf[12]);
Notify(PSTR(" SCID: "));
PrintHex<uint8_t>(l2capinbuf[15]);
Notify(PSTR(" "));
PrintHex<uint8_t>(l2capinbuf[14]);
Notify(PSTR(" Identifier: "));
PrintHex<uint8_t>(l2capinbuf[9]);
Notify(PSTR("\r\nL2CAP Connection Request - PSM: "), 0x80);
PrintHex<uint8_t > (l2capinbuf[13], 0x80);
Notify(PSTR(" "), 0x80);
PrintHex<uint8_t > (l2capinbuf[12], 0x80);
Notify(PSTR(" SCID: "), 0x80);
PrintHex<uint8_t > (l2capinbuf[15], 0x80);
Notify(PSTR(" "), 0x80);
PrintHex<uint8_t > (l2capinbuf[14], 0x80);
Notify(PSTR(" Identifier: "), 0x80);
PrintHex<uint8_t > (l2capinbuf[9], 0x80);
#endif
if ((l2capinbuf[12] | (l2capinbuf[13] << 8)) == HID_CTRL_PSM) {
identifier = l2capinbuf[9];
control_scid[0] = l2capinbuf[14];
control_scid[1] = l2capinbuf[15];
l2cap_event_flag |= L2CAP_FLAG_CONNECTION_CONTROL_REQUEST;
}
else if ((l2capinbuf[12] | (l2capinbuf[13] << 8)) == HID_INTR_PSM) {
} else if ((l2capinbuf[12] | (l2capinbuf[13] << 8)) == HID_INTR_PSM) {
identifier = l2capinbuf[9];
interrupt_scid[0] = l2capinbuf[14];
interrupt_scid[1] = l2capinbuf[15];
l2cap_event_flag |= L2CAP_FLAG_CONNECTION_INTERRUPT_REQUEST;
}
}
else if (l2capinbuf[8] == L2CAP_CMD_CONFIG_RESPONSE) {
} else if (l2capinbuf[8] == L2CAP_CMD_CONFIG_RESPONSE) {
if ((l2capinbuf[16] | (l2capinbuf[17] << 8)) == 0x0000) { // Success
if (l2capinbuf[12] == control_dcid[0] && l2capinbuf[13] == control_dcid[1]) {
//Serial.print("\r\nHID Control Configuration Complete");
l2cap_event_flag |= L2CAP_FLAG_CONFIG_CONTROL_SUCCESS;
}
else if (l2capinbuf[12] == interrupt_dcid[0] && l2capinbuf[13] == interrupt_dcid[1]) {
} else if (l2capinbuf[12] == interrupt_dcid[0] && l2capinbuf[13] == interrupt_dcid[1]) {
//Serial.print("\r\nHID Interrupt Configuration Complete");
l2cap_event_flag |= L2CAP_FLAG_CONFIG_INTERRUPT_SUCCESS;
}
}
}
else if (l2capinbuf[8] == L2CAP_CMD_CONFIG_REQUEST) {
} else if (l2capinbuf[8] == L2CAP_CMD_CONFIG_REQUEST) {
if (l2capinbuf[12] == control_dcid[0] && l2capinbuf[13] == control_dcid[1]) {
//Serial.print("\r\nHID Control Configuration Request");
identifier = l2capinbuf[9];
l2cap_event_flag |= L2CAP_FLAG_CONFIG_CONTROL_REQUEST;
}
else if (l2capinbuf[12] == interrupt_dcid[0] && l2capinbuf[13] == interrupt_dcid[1]) {
} else if (l2capinbuf[12] == interrupt_dcid[0] && l2capinbuf[13] == interrupt_dcid[1]) {
//Serial.print("\r\nHID Interrupt Configuration Request");
identifier = l2capinbuf[9];
l2cap_event_flag |= L2CAP_FLAG_CONFIG_INTERRUPT_REQUEST;
}
}
else if (l2capinbuf[8] == L2CAP_CMD_DISCONNECT_REQUEST) {
} else if (l2capinbuf[8] == L2CAP_CMD_DISCONNECT_REQUEST) {
if (l2capinbuf[12] == control_dcid[0] && l2capinbuf[13] == control_dcid[1]) {
#ifdef DEBUG
Notify(PSTR("\r\nDisconnect Request: Control Channel"));
Notify(PSTR("\r\nDisconnect Request: Control Channel"), 0x80);
#endif
identifier = l2capinbuf[9];
pBtd->l2cap_disconnection_response(hci_handle,identifier,control_dcid,control_scid);
pBtd->l2cap_disconnection_response(hci_handle, identifier, control_dcid, control_scid);
Reset();
}
else if (l2capinbuf[12] == interrupt_dcid[0] && l2capinbuf[13] == interrupt_dcid[1]) {
} else if (l2capinbuf[12] == interrupt_dcid[0] && l2capinbuf[13] == interrupt_dcid[1]) {
#ifdef DEBUG
Notify(PSTR("\r\nDisconnect Request: Interrupt Channel"));
Notify(PSTR("\r\nDisconnect Request: Interrupt Channel"), 0x80);
#endif
identifier = l2capinbuf[9];
pBtd->l2cap_disconnection_response(hci_handle,identifier,interrupt_dcid,interrupt_scid);
pBtd->l2cap_disconnection_response(hci_handle, identifier, interrupt_dcid, interrupt_scid);
Reset();
}
}
else if (l2capinbuf[8] == L2CAP_CMD_DISCONNECT_RESPONSE) {
} else if (l2capinbuf[8] == L2CAP_CMD_DISCONNECT_RESPONSE) {
if (l2capinbuf[12] == control_scid[0] && l2capinbuf[13] == control_scid[1]) {
//Serial.print("\r\nDisconnect Response: Control Channel");
identifier = l2capinbuf[9];
l2cap_event_flag |= L2CAP_FLAG_DISCONNECT_CONTROL_RESPONSE;
}
else if (l2capinbuf[12] == interrupt_scid[0] && l2capinbuf[13] == interrupt_scid[1]) {
} else if (l2capinbuf[12] == interrupt_scid[0] && l2capinbuf[13] == interrupt_scid[1]) {
//Serial.print("\r\nDisconnect Response: Interrupt Channel");
identifier = l2capinbuf[9];
l2cap_event_flag |= L2CAP_FLAG_DISCONNECT_INTERRUPT_RESPONSE;
@ -366,31 +366,31 @@ void PS3BT::ACLData(uint8_t* ACLData) {
}
#ifdef EXTRADEBUG
else {
Notify(PSTR("\r\nL2CAP Unknown Signaling Command: "));
PrintHex<uint8_t>(l2capinbuf[8]);
Notify(PSTR("\r\nL2CAP Unknown Signaling Command: "), 0x80);
PrintHex<uint8_t > (l2capinbuf[8], 0x80);
}
#endif
} else if (l2capinbuf[6] == interrupt_dcid[0] && l2capinbuf[7] == interrupt_dcid[1]) { // l2cap_interrupt
//Serial.print("\r\nL2CAP Interrupt");
if(PS3Connected || PS3MoveConnected || PS3NavigationConnected) {
if (PS3Connected || PS3MoveConnected || PS3NavigationConnected) {
/* Read Report */
if(l2capinbuf[8] == 0xA1) { // HID_THDR_DATA_INPUT
if(PS3Connected || PS3NavigationConnected)
if (l2capinbuf[8] == 0xA1) { // HID_THDR_DATA_INPUT
if (PS3Connected || PS3NavigationConnected)
ButtonState = (uint32_t)(l2capinbuf[11] | ((uint16_t)l2capinbuf[12] << 8) | ((uint32_t)l2capinbuf[13] << 16));
else if(PS3MoveConnected)
else if (PS3MoveConnected)
ButtonState = (uint32_t)(l2capinbuf[10] | ((uint16_t)l2capinbuf[11] << 8) | ((uint32_t)l2capinbuf[12] << 16));
//Notify(PSTR("\r\nButtonState");
//PrintHex<uint32_t>(ButtonState);
//Notify(PSTR("\r\nButtonState", 0x80);
//PrintHex<uint32_t>(ButtonState, 0x80);
if(ButtonState != OldButtonState) {
if (ButtonState != OldButtonState) {
ButtonClickState = ButtonState & ~OldButtonState; // Update click state variable
OldButtonState = ButtonState;
}
#ifdef PRINTREPORT // Uncomment "#define PRINTREPORT" to print the report send by the PS3 Controllers
for(uint8_t i = 10; i < 58;i++) {
PrintHex<uint8_t>(l2capinbuf[i]);
for (uint8_t i = 10; i < 58; i++) {
PrintHex<uint8_t > (l2capinbuf[i], 0x80);
Serial.print(" ");
}
Serial.println();
@ -401,28 +401,29 @@ void PS3BT::ACLData(uint8_t* ACLData) {
L2CAP_task();
}
}
void PS3BT::L2CAP_task() {
switch (l2cap_state) {
case L2CAP_WAIT:
if (l2cap_connection_request_control_flag) {
#ifdef DEBUG
Notify(PSTR("\r\nHID Control Incoming Connection Request"));
Notify(PSTR("\r\nHID Control Incoming Connection Request"), 0x80);
#endif
pBtd->l2cap_connection_response(hci_handle,identifier, control_dcid, control_scid, PENDING);
pBtd->l2cap_connection_response(hci_handle, identifier, control_dcid, control_scid, PENDING);
delay(1);
pBtd->l2cap_connection_response(hci_handle,identifier, control_dcid, control_scid, SUCCESSFUL);
pBtd->l2cap_connection_response(hci_handle, identifier, control_dcid, control_scid, SUCCESSFUL);
identifier++;
delay(1);
pBtd->l2cap_config_request(hci_handle,identifier, control_scid);
pBtd->l2cap_config_request(hci_handle, identifier, control_scid);
l2cap_state = L2CAP_CONTROL_REQUEST;
}
break;
case L2CAP_CONTROL_REQUEST:
if (l2cap_config_request_control_flag) {
#ifdef DEBUG
Notify(PSTR("\r\nHID Control Configuration Request"));
Notify(PSTR("\r\nHID Control Configuration Request"), 0x80);
#endif
pBtd->l2cap_config_response(hci_handle,identifier, control_scid);
pBtd->l2cap_config_response(hci_handle, identifier, control_scid);
l2cap_state = L2CAP_CONTROL_SUCCESS;
}
break;
@ -430,7 +431,7 @@ void PS3BT::L2CAP_task() {
case L2CAP_CONTROL_SUCCESS:
if (l2cap_config_success_control_flag) {
#ifdef DEBUG
Notify(PSTR("\r\nHID Control Successfully Configured"));
Notify(PSTR("\r\nHID Control Successfully Configured"), 0x80);
#endif
l2cap_state = L2CAP_INTERRUPT_SETUP;
}
@ -438,14 +439,14 @@ void PS3BT::L2CAP_task() {
case L2CAP_INTERRUPT_SETUP:
if (l2cap_connection_request_interrupt_flag) {
#ifdef DEBUG
Notify(PSTR("\r\nHID Interrupt Incoming Connection Request"));
Notify(PSTR("\r\nHID Interrupt Incoming Connection Request"), 0x80);
#endif
pBtd->l2cap_connection_response(hci_handle,identifier, interrupt_dcid, interrupt_scid, PENDING);
pBtd->l2cap_connection_response(hci_handle, identifier, interrupt_dcid, interrupt_scid, PENDING);
delay(1);
pBtd->l2cap_connection_response(hci_handle,identifier, interrupt_dcid, interrupt_scid, SUCCESSFUL);
pBtd->l2cap_connection_response(hci_handle, identifier, interrupt_dcid, interrupt_scid, SUCCESSFUL);
identifier++;
delay(1);
pBtd->l2cap_config_request(hci_handle,identifier, interrupt_scid);
pBtd->l2cap_config_request(hci_handle, identifier, interrupt_scid);
l2cap_state = L2CAP_INTERRUPT_REQUEST;
}
@ -453,18 +454,18 @@ void PS3BT::L2CAP_task() {
case L2CAP_INTERRUPT_REQUEST:
if (l2cap_config_request_interrupt_flag) {
#ifdef DEBUG
Notify(PSTR("\r\nHID Interrupt Configuration Request"));
Notify(PSTR("\r\nHID Interrupt Configuration Request"), 0x80);
#endif
pBtd->l2cap_config_response(hci_handle,identifier, interrupt_scid);
pBtd->l2cap_config_response(hci_handle, identifier, interrupt_scid);
l2cap_state = L2CAP_INTERRUPT_SUCCESS;
}
break;
case L2CAP_INTERRUPT_SUCCESS:
if (l2cap_config_success_interrupt_flag) {
#ifdef DEBUG
Notify(PSTR("\r\nHID Interrupt Successfully Configured"));
Notify(PSTR("\r\nHID Interrupt Successfully Configured"), 0x80);
#endif
if(remote_name[0] == 'M') { // First letter in Motion Controller ('M')
if (remote_name[0] == 'M') { // First letter in Motion Controller ('M')
for (uint8_t i = 0; i < BULK_MAXPKTSIZE; i++) // Reset l2cap in buffer as it sometimes read it as a button has been pressed
l2capinbuf[i] = 0;
ButtonState = 0;
@ -482,7 +483,7 @@ void PS3BT::L2CAP_task() {
case L2CAP_INTERRUPT_DISCONNECT:
if (l2cap_disconnect_response_interrupt_flag) {
#ifdef DEBUG
Notify(PSTR("\r\nDisconnected Interrupt Channel"));
Notify(PSTR("\r\nDisconnected Interrupt Channel"), 0x80);
#endif
identifier++;
pBtd->l2cap_disconnection_request(hci_handle, identifier, control_scid, control_dcid);
@ -493,7 +494,7 @@ void PS3BT::L2CAP_task() {
case L2CAP_CONTROL_DISCONNECT:
if (l2cap_disconnect_response_control_flag) {
#ifdef DEBUG
Notify(PSTR("\r\nDisconnected Control Channel"));
Notify(PSTR("\r\nDisconnected Control Channel"), 0x80);
#endif
pBtd->hci_disconnect(hci_handle);
hci_handle = -1; // Reset handle
@ -503,10 +504,11 @@ void PS3BT::L2CAP_task() {
break;
}
}
void PS3BT::Run() {
switch (l2cap_state) {
case L2CAP_HID_ENABLE_SIXAXIS:
if(millis() - timer > 1000) { // loop 1 second before sending the command
if (millis() - timer > 1000) { // loop 1 second before sending the command
for (uint8_t i = 0; i < BULK_MAXPKTSIZE; i++) // Reset l2cap in buffer as it sometimes read it as a button has been pressed
l2capinbuf[i] = 0;
ButtonState = 0;
@ -521,24 +523,24 @@ void PS3BT::Run() {
break;
case L2CAP_HID_PS3_LED:
if(millis() - timer > 1000) { // loop 1 second before sending the command
if (millis() - timer > 1000) { // loop 1 second before sending the command
if (remote_name[0] == 'P') { // First letter in PLAYSTATION(R)3 Controller ('P')
setLedOn(LED1);
#ifdef DEBUG
Notify(PSTR("\r\nDualshock 3 Controller Enabled\r\n"));
Notify(PSTR("\r\nDualshock 3 Controller Enabled\r\n"), 0x80);
#endif
PS3Connected = true;
} else if (remote_name[0] == 'N') { // First letter in Navigation Controller ('N')
setLedOn(LED1); // This just turns LED constantly on, on the Navigation controller
#ifdef DEBUG
Notify(PSTR("\r\nNavigation Controller Enabled\r\n"));
Notify(PSTR("\r\nNavigation Controller Enabled\r\n"), 0x80);
#endif
PS3NavigationConnected = true;
} else if(remote_name[0] == 'M') { // First letter in Motion Controller ('M')
} else if (remote_name[0] == 'M') { // First letter in Motion Controller ('M')
moveSetBulb(Red);
timerBulbRumble = millis();
#ifdef DEBUG
Notify(PSTR("\r\nMotion Controller Enabled\r\n"));
Notify(PSTR("\r\nMotion Controller Enabled\r\n"), 0x80);
#endif
PS3MoveConnected = true;
}
@ -549,7 +551,7 @@ void PS3BT::Run() {
case L2CAP_DONE:
if (PS3MoveConnected) { //The Bulb and rumble values, has to be send at aproximatly every 5th second for it to stay on
if (millis() - timerBulbRumble > 4000) { //Send at least every 4th second
HIDMove_Command(HIDMoveBuffer, HID_BUFFERSIZE);//The Bulb and rumble values, has to be written again and again, for it to stay turned on
HIDMove_Command(HIDMoveBuffer, HID_BUFFERSIZE); //The Bulb and rumble values, has to be written again and again, for it to stay turned on
timerBulbRumble = millis();
}
}
@ -562,64 +564,69 @@ void PS3BT::Run() {
/************************************************************/
//Playstation Sixaxis Dualshock and Navigation Controller commands
void PS3BT::HID_Command(uint8_t* data, uint8_t nbytes) {
if (millis() - timerHID <= 250)// Check if is has been more than 250ms since last command
delay((uint32_t)(250 - (millis() - timerHID)));//There have to be a delay between commands
pBtd->L2CAP_Command(hci_handle,data,nbytes,control_scid[0],control_scid[1]); // Both the Navigation and Dualshock controller sends data via the control channel
delay((uint32_t)(250 - (millis() - timerHID))); //There have to be a delay between commands
pBtd->L2CAP_Command(hci_handle, data, nbytes, control_scid[0], control_scid[1]); // Both the Navigation and Dualshock controller sends data via the control channel
timerHID = millis();
}
void PS3BT::setAllOff() {
for (uint8_t i = 0; i < OUTPUT_REPORT_BUFFER_SIZE; i++)
HIDBuffer[i + 2] = pgm_read_byte(&OUTPUT_REPORT_BUFFER[i]);//First two bytes reserved for report type and ID
HIDBuffer[i + 2] = pgm_read_byte(&OUTPUT_REPORT_BUFFER[i]); //First two bytes reserved for report type and ID
HID_Command(HIDBuffer, HID_BUFFERSIZE);
}
void PS3BT::setRumbleOff() {
HIDBuffer[3] = 0x00;
HIDBuffer[4] = 0x00;//low mode off
HIDBuffer[4] = 0x00; //low mode off
HIDBuffer[5] = 0x00;
HIDBuffer[6] = 0x00;//high mode off
HIDBuffer[6] = 0x00; //high mode off
HID_Command(HIDBuffer, HID_BUFFERSIZE);
}
void PS3BT::setRumbleOn(Rumble mode) {
/* Still not totally sure how it works, maybe something like this instead?
* 3 - duration_right
* 4 - power_right
* 5 - duration_left
* 6 - power_left
*/
if ((mode & 0x30) > 0) {
HIDBuffer[3] = 0xfe;
HIDBuffer[5] = 0xfe;
if ((mode & 0x30) > 0x00) {
uint8_t power[2] = { 0xff, 0x00 }; // Defaults to RumbleLow
if (mode == RumbleHigh) {
HIDBuffer[4] = 0;//low mode off
HIDBuffer[6] = 0xff;//high mode on
power[0] = 0x00;
power[1] = 0xff;
}
else {
HIDBuffer[4] = 0xff;//low mode on
HIDBuffer[6] = 0;//high mode off
}
HID_Command(HIDBuffer, HID_BUFFERSIZE);
setRumbleOn(0xfe, power[0], 0xfe, power[1]);
}
}
void PS3BT::setRumbleOn(uint8_t rightDuration, uint8_t rightPower, uint8_t leftDuration, uint8_t leftPower) {
HIDBuffer[3] = rightDuration;
HIDBuffer[4] = rightPower;
HIDBuffer[5] = leftDuration;
HIDBuffer[6] = leftPower;
HID_Command(HIDBuffer, HID_BUFFERSIZE);
}
void PS3BT::setLedOff(LED a) {
HIDBuffer[11] &= ~((uint8_t)((pgm_read_byte(&LEDS[(uint8_t)a]) & 0x0f) << 1));
HID_Command(HIDBuffer, HID_BUFFERSIZE);
}
void PS3BT::setLedOn(LED a) {
HIDBuffer[11] |= (uint8_t)((pgm_read_byte(&LEDS[(uint8_t)a]) & 0x0f) << 1);
HID_Command(HIDBuffer, HID_BUFFERSIZE);
}
void PS3BT::setLedToggle(LED a) {
HIDBuffer[11] ^= (uint8_t)((pgm_read_byte(&LEDS[(uint8_t)a]) & 0x0f) << 1);
HID_Command(HIDBuffer, HID_BUFFERSIZE);
}
void PS3BT::enable_sixaxis() { //Command used to enable the Dualshock 3 and Navigation controller to send data via USB
uint8_t cmd_buf[6];
cmd_buf[0] = 0x53;// HID BT Set_report (0x50) | Report Type (Feature 0x03)
cmd_buf[1] = 0xF4;// Report ID
cmd_buf[2] = 0x42;// Special PS3 Controller enable commands
cmd_buf[0] = 0x53; // HID BT Set_report (0x50) | Report Type (Feature 0x03)
cmd_buf[1] = 0xF4; // Report ID
cmd_buf[2] = 0x42; // Special PS3 Controller enable commands
cmd_buf[3] = 0x03;
cmd_buf[4] = 0x00;
cmd_buf[5] = 0x00;
@ -628,12 +635,14 @@ void PS3BT::enable_sixaxis() { //Command used to enable the Dualshock 3 and Navi
}
//Playstation Move Controller commands
void PS3BT::HIDMove_Command(uint8_t* data,uint8_t nbytes) {
void PS3BT::HIDMove_Command(uint8_t* data, uint8_t nbytes) {
if (millis() - timerHID <= 250)// Check if is has been less than 200ms since last command
delay((uint32_t)(250 - (millis() - timerHID)));//There have to be a delay between commands
pBtd->L2CAP_Command(hci_handle,data,nbytes,interrupt_scid[0],interrupt_scid[1]); // The Move controller sends it's data via the intterrupt channel
delay((uint32_t)(250 - (millis() - timerHID))); //There have to be a delay between commands
pBtd->L2CAP_Command(hci_handle, data, nbytes, interrupt_scid[0], interrupt_scid[1]); // The Move controller sends it's data via the intterrupt channel
timerHID = millis();
}
void PS3BT::moveSetBulb(uint8_t r, uint8_t g, uint8_t b) { //Use this to set the Color using RGB values
//set the Bulb's values into the write buffer
HIDMoveBuffer[3] = r;
@ -642,13 +651,15 @@ void PS3BT::moveSetBulb(uint8_t r, uint8_t g, uint8_t b) { //Use this to set the
HIDMove_Command(HIDMoveBuffer, HID_BUFFERSIZE);
}
void PS3BT::moveSetBulb(Colors color) { //Use this to set the Color using the predefined colors in enum
moveSetBulb((uint8_t)(color >> 16),(uint8_t)(color >> 8),(uint8_t)(color));
moveSetBulb((uint8_t)(color >> 16), (uint8_t)(color >> 8), (uint8_t)(color));
}
void PS3BT::moveSetRumble(uint8_t rumble) {
#ifdef DEBUG
if(rumble < 64 && rumble != 0) // The rumble value has to at least 64, or approximately 25% (64/255*100)
Notify(PSTR("\r\nThe rumble value has to at least 64, or approximately 25%"));
if (rumble < 64 && rumble != 0) // The rumble value has to at least 64, or approximately 25% (64/255*100)
Notify(PSTR("\r\nThe rumble value has to at least 64, or approximately 25%"), 0x80);
#endif
//set the rumble value into the write buffer
HIDMoveBuffer[7] = rumble;

12
PS3BT.h
View file

@ -72,7 +72,7 @@ public:
* Pass your dongles Bluetooth address into the constructor,
* This will set BTD#my_bdaddr, so you don't have to plug in the dongle before pairing with your controller.
*/
PS3BT(BTD *pBtd, uint8_t btadr5=0, uint8_t btadr4=0, uint8_t btadr3=0, uint8_t btadr2=0, uint8_t btadr1=0, uint8_t btadr0=0);
PS3BT(BTD *pBtd, uint8_t btadr5 = 0, uint8_t btadr4 = 0, uint8_t btadr3 = 0, uint8_t btadr2 = 0, uint8_t btadr1 = 0, uint8_t btadr0 = 0);
/** @name BluetoothService implementation */
/**
@ -163,6 +163,14 @@ public:
* @param mode Either ::RumbleHigh or ::RumbleLow.
*/
void setRumbleOn(Rumble mode);
/**
* Turn on ::Rumble using custom duration and power.
* @param rightDuration The duration of the right/low rumble effect.
* @param rightPower The intensity of the right/low rumble effect.
* @param leftDuration The duration of the left/high rumble effect.
* @param leftPower The intensity of the left/high rumble effect.
*/
void setRumbleOn(uint8_t rightDuration, uint8_t rightPower, uint8_t leftDuration, uint8_t leftPower);
/**
* Turn the specific ::LED off.
* @param a The ::LED to turn off.
@ -225,7 +233,7 @@ private:
uint32_t ButtonClickState;
uint32_t timerHID; // Timer used see if there has to be a delay before a new HID command
uint32_t timerBulbRumble;// used to continuously set PS3 Move controller Bulb and rumble values
uint32_t timerBulbRumble; // used to continuously set PS3 Move controller Bulb and rumble values
uint8_t l2capinbuf[BULK_MAXPKTSIZE]; // General purpose buffer for L2CAP in data
uint8_t HIDBuffer[HID_BUFFERSIZE]; // Used to store HID commands

View file

@ -76,7 +76,7 @@ const uint8_t ANALOGBUTTONS[] PROGMEM = {
24, // RIGHT_ANALOG
25, // DOWN_ANALOG
26, // LEFT_ANALOG
0,0,0,0, // Skip SELECT, L3, R3 and START
0, 0, 0, 0, // Skip SELECT, L3, R3 and START
27, // L2_ANALOG
28, // R2_ANALOG
@ -86,7 +86,7 @@ const uint8_t ANALOGBUTTONS[] PROGMEM = {
32, // CIRCLE_ANALOG
33, // CROSS_ANALOG
34, // SQUARE_ANALOG
0,0, // Skip PS and MOVE
0, 0, // Skip PS and MOVE
// Playstation Move Controller
15 // T_ANALOG - Both at byte 14 (last reading) and byte 15 (current reading)
@ -153,11 +153,13 @@ enum Sensor {
/** Magnetometer y-axis */
mYmove = 50,
};
/** Used to get the angle calculated using the accelerometer. */
enum Angle {
Pitch = 0x01,
Roll = 0x02,
};
enum Status {
// Note that the location is shiftet 9 when it's connected via USB
// Byte location | bit location
@ -180,11 +182,12 @@ enum Status {
MoveHigh = (21 << 8) | 0x04,
MoveFull = (21 << 8) | 0x05,
CableRumble = (40 << 8) | 0x10,//Opperating by USB and rumble is turned on
Cable = (40 << 8) | 0x12,//Opperating by USB and rumble is turned off
BluetoothRumble = (40 << 8) | 0x14,//Opperating by bluetooth and rumble is turned on
Bluetooth = (40 << 8) | 0x16,//Opperating by bluetooth and rumble is turned off
CableRumble = (40 << 8) | 0x10, //Opperating by USB and rumble is turned on
Cable = (40 << 8) | 0x12, //Opperating by USB and rumble is turned off
BluetoothRumble = (40 << 8) | 0x14, //Opperating by bluetooth and rumble is turned on
Bluetooth = (40 << 8) | 0x16, //Opperating by bluetooth and rumble is turned off
};
enum Rumble {
RumbleHigh = 0x10,
RumbleLow = 0x20,

View file

@ -38,12 +38,12 @@ const uint8_t MOVE_REPORT_BUFFER[] PROGMEM = {
0x00 // Rumble
};
PS3USB::PS3USB(USB *p, uint8_t btadr5, uint8_t btadr4, uint8_t btadr3, uint8_t btadr2, uint8_t btadr1, uint8_t btadr0):
PS3USB::PS3USB(USB *p, uint8_t btadr5, uint8_t btadr4, uint8_t btadr3, uint8_t btadr2, uint8_t btadr1, uint8_t btadr0) :
pUsb(p), // pointer to USB class instance - mandatory
bAddress(0), // device address - mandatory
bPollEnable(false) // don't start polling before dongle is connected
{
for(uint8_t i=0; i<PS3_MAX_ENDPOINTS; i++) {
for (uint8_t i = 0; i < PS3_MAX_ENDPOINTS; i++) {
epInfo[i].epAddr = 0;
epInfo[i].maxPktSize = (i) ? 0 : 8;
epInfo[i].epAttribs = 0;
@ -62,7 +62,7 @@ bPollEnable(false) // don't start polling before dongle is connected
}
uint8_t PS3USB::Init(uint8_t parent, uint8_t port, bool lowspeed) {
uint8_t buf[sizeof(USB_DEVICE_DESCRIPTOR)];
uint8_t buf[sizeof (USB_DEVICE_DESCRIPTOR)];
uint8_t rcode;
UsbDevice *p = NULL;
EpInfo *oldep_ptr = NULL;
@ -72,12 +72,12 @@ uint8_t PS3USB::Init(uint8_t parent, uint8_t port, bool lowspeed) {
// get memory address of USB device address pool
AddressPool &addrPool = pUsb->GetAddressPool();
#ifdef EXTRADEBUG
Notify(PSTR("\r\nPS3USB Init"));
Notify(PSTR("\r\nPS3USB Init"), 0x80);
#endif
// check if address has already been assigned to an instance
if (bAddress) {
#ifdef DEBUG
Notify(PSTR("\r\nAddress in use"));
Notify(PSTR("\r\nAddress in use"), 0x80);
#endif
return USB_ERROR_CLASS_INSTANCE_ALREADY_IN_USE;
}
@ -87,14 +87,14 @@ uint8_t PS3USB::Init(uint8_t parent, uint8_t port, bool lowspeed) {
if (!p) {
#ifdef DEBUG
Notify(PSTR("\r\nAddress not found"));
Notify(PSTR("\r\nAddress not found"), 0x80);
#endif
return USB_ERROR_ADDRESS_NOT_FOUND_IN_POOL;
}
if (!p->epinfo) {
#ifdef DEBUG
Notify(PSTR("\r\nepinfo is null"));
Notify(PSTR("\r\nepinfo is null"), 0x80);
#endif
return USB_ERROR_EPINFO_IS_NULL;
}
@ -108,17 +108,17 @@ uint8_t PS3USB::Init(uint8_t parent, uint8_t port, bool lowspeed) {
p->lowspeed = lowspeed;
// Get device descriptor
rcode = pUsb->getDevDescr(0, 0, sizeof(USB_DEVICE_DESCRIPTOR), (uint8_t*)buf);// Get device descriptor - addr, ep, nbytes, data
rcode = pUsb->getDevDescr(0, 0, sizeof (USB_DEVICE_DESCRIPTOR), (uint8_t*)buf); // Get device descriptor - addr, ep, nbytes, data
// Restore p->epinfo
p->epinfo = oldep_ptr;
if(rcode)
if (rcode)
goto FailGetDevDescr;
VID = ((USB_DEVICE_DESCRIPTOR*)buf)->idVendor;
PID = ((USB_DEVICE_DESCRIPTOR*)buf)->idProduct;
if(VID != PS3_VID || (PID != PS3_PID && PID != PS3NAVIGATION_PID && PID != PS3MOVE_PID))
if (VID != PS3_VID || (PID != PS3_PID && PID != PS3NAVIGATION_PID && PID != PS3MOVE_PID))
goto FailUnknownDevice;
// Allocate new address according to device class
@ -131,20 +131,20 @@ uint8_t PS3USB::Init(uint8_t parent, uint8_t port, bool lowspeed) {
epInfo[0].maxPktSize = (uint8_t)((USB_DEVICE_DESCRIPTOR*)buf)->bMaxPacketSize0;
// Assign new address to the device
rcode = pUsb->setAddr( 0, 0, bAddress );
rcode = pUsb->setAddr(0, 0, bAddress);
if (rcode) {
p->lowspeed = false;
addrPool.FreeAddress(bAddress);
bAddress = 0;
#ifdef DEBUG
Notify(PSTR("\r\nsetAddr: "));
Notify(PSTR("\r\nsetAddr: "), 0x80);
#endif
PrintHex<uint8_t>(rcode);
PrintHex<uint8_t > (rcode, 0x80);
return rcode;
}
#ifdef EXTRADEBUG
Notify(PSTR("\r\nAddr: "));
PrintHex<uint8_t>(bAddress);
Notify(PSTR("\r\nAddr: "), 0x80);
PrintHex<uint8_t > (bAddress, 0x80);
#endif
p->lowspeed = false;
@ -180,24 +180,24 @@ uint8_t PS3USB::Init(uint8_t parent, uint8_t port, bool lowspeed) {
epInfo[ PS3_INPUT_PIPE ].bmRcvToggle = bmRCVTOG0;
rcode = pUsb->setEpInfoEntry(bAddress, 3, epInfo);
if( rcode )
if (rcode)
goto FailSetDevTblEntry;
delay(200);//Give time for address change
delay(200); //Give time for address change
rcode = pUsb->setConf(bAddress, epInfo[ PS3_CONTROL_PIPE ].epAddr, 1);
if( rcode )
if (rcode)
goto FailSetConf;
if(PID == PS3_PID || PID == PS3NAVIGATION_PID) {
if(PID == PS3_PID) {
if (PID == PS3_PID || PID == PS3NAVIGATION_PID) {
if (PID == PS3_PID) {
#ifdef DEBUG
Notify(PSTR("\r\nDualshock 3 Controller Connected"));
Notify(PSTR("\r\nDualshock 3 Controller Connected"), 0x80);
#endif
PS3Connected = true;
} else { // must be a navigation controller
#ifdef DEBUG
Notify(PSTR("\r\nNavigation Controller Connected"));
Notify(PSTR("\r\nNavigation Controller Connected"), 0x80);
#endif
PS3NavigationConnected = true;
}
@ -212,10 +212,9 @@ uint8_t PS3USB::Init(uint8_t parent, uint8_t port, bool lowspeed) {
for (uint8_t i = 6; i < 10; i++)
readBuf[i] = 0x7F; // Set the analog joystick values to center position
}
else { // must be a Motion controller
} else { // must be a Motion controller
#ifdef DEBUG
Notify(PSTR("\r\nMotion Controller Connected"));
Notify(PSTR("\r\nMotion Controller Connected"), 0x80);
#endif
PS3MoveConnected = true;
setMoveBdaddr(my_bdaddr); // Set internal bluetooth address
@ -227,39 +226,39 @@ uint8_t PS3USB::Init(uint8_t parent, uint8_t port, bool lowspeed) {
}
bPollEnable = true;
Notify(PSTR("\r\n"));
Notify(PSTR("\r\n"), 0x80);
timer = millis();
return 0; // successful configuration
/* diagnostic messages */
FailGetDevDescr:
#ifdef DEBUG
Notify(PSTR("\r\ngetDevDescr:"));
Notify(PSTR("\r\ngetDevDescr:"), 0x80);
#endif
goto Fail;
FailSetDevTblEntry:
#ifdef DEBUG
Notify(PSTR("\r\nsetDevTblEn:"));
Notify(PSTR("\r\nsetDevTblEn:"), 0x80);
#endif
goto Fail;
FailSetConf:
#ifdef DEBUG
Notify(PSTR("\r\nsetConf:"));
Notify(PSTR("\r\nsetConf:"), 0x80);
#endif
goto Fail;
FailUnknownDevice:
#ifdef DEBUG
Notify(PSTR("\r\nUnknown Device Connected - VID: "));
PrintHex<uint16_t>(VID);
Notify(PSTR(" PID: "));
PrintHex<uint16_t>(PID);
Notify(PSTR("\r\nUnknown Device Connected - VID: "), 0x80);
PrintHex<uint16_t > (VID, 0x80);
Notify(PSTR(" PID: "), 0x80);
PrintHex<uint16_t > (PID, 0x80);
#endif
rcode = USB_DEV_CONFIG_ERROR_DEVICE_NOT_SUPPORTED;
goto Fail;
Fail:
#ifdef DEBUG
Notify(PSTR("\r\nPS3 Init Failed, error code: "));
Serial.print(rcode,HEX);
Notify(PSTR("\r\nPS3 Init Failed, error code: "), 0x80);
Serial.print(rcode, HEX);
#endif
Release();
return rcode;
@ -275,21 +274,21 @@ uint8_t PS3USB::Release() {
bPollEnable = false;
return 0;
}
uint8_t PS3USB::Poll() {
if (!bPollEnable)
return 0;
if(PS3Connected || PS3NavigationConnected) {
if (PS3Connected || PS3NavigationConnected) {
uint16_t BUFFER_SIZE = EP_MAXPKTSIZE;
pUsb->inTransfer(bAddress, epInfo[ PS3_INPUT_PIPE ].epAddr, &BUFFER_SIZE, readBuf); // input on endpoint 1
if(millis() - timer > 100) { // Loop 100ms before processing data
if (millis() - timer > 100) { // Loop 100ms before processing data
readReport();
#ifdef PRINTREPORT
printReport(); // Uncomment "#define PRINTREPORT" to print the report send by the PS3 Controllers
#endif
}
}
else if(PS3MoveConnected) { // One can only set the color of the bulb, set the rumble, set and get the bluetooth address and calibrate the magnetometer via USB
} else if (PS3MoveConnected) { // One can only set the color of the bulb, set the rumble, set and get the bluetooth address and calibrate the magnetometer via USB
if (millis() - timer > 4000) // Send at least every 4th second
{
Move_Command(writeBuf, MOVE_REPORT_BUFFER_SIZE); // The Bulb and rumble values, has to be written again and again, for it to stay turned on
@ -305,10 +304,10 @@ void PS3USB::readReport() {
ButtonState = (uint32_t)(readBuf[2] | ((uint16_t)readBuf[3] << 8) | ((uint32_t)readBuf[4] << 16));
//Notify(PSTR("\r\nButtonState");
//PrintHex<uint32_t>(ButtonState);
//Notify(PSTR("\r\nButtonState", 0x80);
//PrintHex<uint32_t>(ButtonState, 0x80);
if(ButtonState != OldButtonState) {
if (ButtonState != OldButtonState) {
ButtonClickState = ButtonState & ~OldButtonState; // Update click state variable
OldButtonState = ButtonState;
}
@ -318,8 +317,8 @@ void PS3USB::printReport() { //Uncomment "#define PRINTREPORT" to print the repo
#ifdef PRINTREPORT
if (readBuf == NULL)
return;
for(uint8_t i = 0; i < PS3_REPORT_BUFFER_SIZE;i++) {
PrintHex<uint8_t>(readBuf[i]);
for (uint8_t i = 0; i < PS3_REPORT_BUFFER_SIZE; i++) {
PrintHex<uint8_t > (readBuf[i], 0x80);
Serial.print(" ");
}
Serial.println();
@ -329,88 +328,95 @@ void PS3USB::printReport() { //Uncomment "#define PRINTREPORT" to print the repo
bool PS3USB::getButtonPress(Button b) {
return (ButtonState & pgm_read_dword(&BUTTONS[(uint8_t)b]));
}
bool PS3USB::getButtonClick(Button b) {
uint32_t button = pgm_read_dword(&BUTTONS[(uint8_t)b]);
bool click = (ButtonClickState & button);
ButtonClickState &= ~button; // clear "click" event
return click;
}
uint8_t PS3USB::getAnalogButton(Button a) {
if (readBuf == NULL)
return 0;
return (uint8_t)(readBuf[(pgm_read_byte(&ANALOGBUTTONS[(uint8_t)a]))-9]);
return (uint8_t)(readBuf[(pgm_read_byte(&ANALOGBUTTONS[(uint8_t)a])) - 9]);
}
uint8_t PS3USB::getAnalogHat(AnalogHat a) {
if (readBuf == NULL)
return 0;
return (uint8_t)(readBuf[((uint8_t)a+6)]);
return (uint8_t)(readBuf[((uint8_t)a + 6)]);
}
uint16_t PS3USB::getSensor(Sensor a) {
if (readBuf == NULL)
return 0;
return ((readBuf[((uint16_t)a)-9] << 8) | readBuf[((uint16_t)a + 1)-9]);
return ((readBuf[((uint16_t)a) - 9] << 8) | readBuf[((uint16_t)a + 1) - 9]);
}
double PS3USB::getAngle(Angle a) {
if(PS3Connected) {
if (PS3Connected) {
double accXval;
double accYval;
double accZval;
// Data for the Kionix KXPC4 used in the DualShock 3
const double zeroG = 511.5; // 1.65/3.3*1023 (1,65V)
accXval = -((double)getSensor(aX)-zeroG);
accYval = -((double)getSensor(aY)-zeroG);
accZval = -((double)getSensor(aZ)-zeroG);
accXval = -((double)getSensor(aX) - zeroG);
accYval = -((double)getSensor(aY) - zeroG);
accZval = -((double)getSensor(aZ) - zeroG);
// Convert to 360 degrees resolution
// atan2 outputs the value of -π to π (radians)
// We are then converting it to 0 to 2π and then to degrees
if (a == Pitch) {
double angle = (atan2(accYval,accZval)+PI)*RAD_TO_DEG;
double angle = (atan2(accYval, accZval) + PI) * RAD_TO_DEG;
return angle;
} else {
double angle = (atan2(accXval,accZval)+PI)*RAD_TO_DEG;
double angle = (atan2(accXval, accZval) + PI) * RAD_TO_DEG;
return angle;
}
} else
return 0;
}
bool PS3USB::getStatus(Status c) {
if (readBuf == NULL)
return false;
if (readBuf[((uint16_t)c >> 8)-9] == ((uint8_t)c & 0xff))
if (readBuf[((uint16_t)c >> 8) - 9] == ((uint8_t)c & 0xff))
return true;
return false;
}
String PS3USB::getStatusString() {
if (PS3Connected || PS3NavigationConnected) {
char statusOutput[100];
strcpy(statusOutput,"ConnectionStatus: ");
strcpy(statusOutput, "ConnectionStatus: ");
if (getStatus(Plugged)) strcat(statusOutput,"Plugged");
else if (getStatus(Unplugged)) strcat(statusOutput,"Unplugged");
else strcat(statusOutput,"Error");
if (getStatus(Plugged)) strcat(statusOutput, "Plugged");
else if (getStatus(Unplugged)) strcat(statusOutput, "Unplugged");
else strcat(statusOutput, "Error");
strcat(statusOutput," - PowerRating: ");
strcat(statusOutput, " - PowerRating: ");
if (getStatus(Charging)) strcat(statusOutput,"Charging");
else if (getStatus(NotCharging)) strcat(statusOutput,"Not Charging");
else if (getStatus(Shutdown)) strcat(statusOutput,"Shutdown");
else if (getStatus(Dying)) strcat(statusOutput,"Dying");
else if (getStatus(Low)) strcat(statusOutput,"Low");
else if (getStatus(High)) strcat(statusOutput,"High");
else if (getStatus(Full)) strcat(statusOutput,"Full");
else strcat(statusOutput,"Error");
if (getStatus(Charging)) strcat(statusOutput, "Charging");
else if (getStatus(NotCharging)) strcat(statusOutput, "Not Charging");
else if (getStatus(Shutdown)) strcat(statusOutput, "Shutdown");
else if (getStatus(Dying)) strcat(statusOutput, "Dying");
else if (getStatus(Low)) strcat(statusOutput, "Low");
else if (getStatus(High)) strcat(statusOutput, "High");
else if (getStatus(Full)) strcat(statusOutput, "Full");
else strcat(statusOutput, "Error");
strcat(statusOutput," - WirelessStatus: ");
strcat(statusOutput, " - WirelessStatus: ");
if (getStatus(CableRumble)) strcat(statusOutput,"Cable - Rumble is on");
else if (getStatus(Cable)) strcat(statusOutput,"Cable - Rumble is off");
else if (getStatus(BluetoothRumble)) strcat(statusOutput,"Bluetooth - Rumble is on");
else if (getStatus(Bluetooth)) strcat(statusOutput,"Bluetooth - Rumble is off");
else strcat(statusOutput,"Error");
if (getStatus(CableRumble)) strcat(statusOutput, "Cable - Rumble is on");
else if (getStatus(Cable)) strcat(statusOutput, "Cable - Rumble is off");
else if (getStatus(BluetoothRumble)) strcat(statusOutput, "Bluetooth - Rumble is on");
else if (getStatus(Bluetooth)) strcat(statusOutput, "Bluetooth - Rumble is off");
else strcat(statusOutput, "Error");
return statusOutput;
}
@ -419,84 +425,89 @@ String PS3USB::getStatusString() {
/* Playstation Sixaxis Dualshock and Navigation Controller commands */
void PS3USB::PS3_Command(uint8_t* data, uint16_t nbytes) {
//bmRequest = Host to device (0x00) | Class (0x20) | Interface (0x01) = 0x21, bRequest = Set Report (0x09), Report ID (0x01), Report Type (Output 0x02), interface (0x00), datalength, datalength, data)
pUsb->ctrlReq(bAddress,epInfo[PS3_CONTROL_PIPE].epAddr, bmREQ_HID_OUT, HID_REQUEST_SET_REPORT, 0x01, 0x02, 0x00, nbytes, nbytes, data, NULL);
pUsb->ctrlReq(bAddress, epInfo[PS3_CONTROL_PIPE].epAddr, bmREQ_HID_OUT, HID_REQUEST_SET_REPORT, 0x01, 0x02, 0x00, nbytes, nbytes, data, NULL);
}
void PS3USB::setAllOff() {
for (uint8_t i = 0; i < PS3_REPORT_BUFFER_SIZE; i++)
writeBuf[i] = pgm_read_byte(&PS3_REPORT_BUFFER[i]); // Reset buffer
PS3_Command(writeBuf, PS3_REPORT_BUFFER_SIZE);
}
void PS3USB::setRumbleOff() {
writeBuf[1] = 0x00;
writeBuf[2] = 0x00;//low mode off
writeBuf[2] = 0x00; //low mode off
writeBuf[3] = 0x00;
writeBuf[4] = 0x00;//high mode off
writeBuf[4] = 0x00; //high mode off
PS3_Command(writeBuf, PS3_REPORT_BUFFER_SIZE);
}
void PS3USB::setRumbleOn(Rumble mode) {
/* Still not totally sure how it works, maybe something like this instead?
* 3 - duration_right
* 4 - power_right
* 5 - duration_left
* 6 - power_left
*/
if ((mode & 0x30) > 0) {
writeBuf[1] = 0xfe;
writeBuf[3] = 0xfe;
if ((mode & 0x30) > 0x00) {
uint8_t power[2] = { 0xff, 0x00 }; // Defaults to RumbleLow
if (mode == RumbleHigh) {
writeBuf[2] = 0;//low mode off
writeBuf[4] = 0xff;//high mode on
power[0] = 0x00;
power[1] = 0xff;
}
else {
writeBuf[2] = 0xff;//low mode on
writeBuf[4] = 0;//high mode off
}
PS3_Command(writeBuf, PS3_REPORT_BUFFER_SIZE);
setRumbleOn(0xfe, power[0], 0xfe, power[1]);
}
}
void PS3USB::setRumbleOn(uint8_t rightDuration, uint8_t rightPower, uint8_t leftDuration, uint8_t leftPower) {
writeBuf[1] = rightDuration;
writeBuf[2] = rightPower;
writeBuf[3] = leftDuration;
writeBuf[4] = leftPower;
PS3_Command(writeBuf, PS3_REPORT_BUFFER_SIZE);
}
void PS3USB::setLedOff(LED a) {
writeBuf[9] &= ~((uint8_t)((pgm_read_byte(&LEDS[(uint8_t)a]) & 0x0f) << 1));
PS3_Command(writeBuf, PS3_REPORT_BUFFER_SIZE);
}
void PS3USB::setLedOn(LED a) {
writeBuf[9] |= (uint8_t)((pgm_read_byte(&LEDS[(uint8_t)a]) & 0x0f) << 1);
PS3_Command(writeBuf, PS3_REPORT_BUFFER_SIZE);
}
void PS3USB::setLedToggle(LED a) {
writeBuf[9] ^= (uint8_t)((pgm_read_byte(&LEDS[(uint8_t)a]) & 0x0f) << 1);
PS3_Command(writeBuf, PS3_REPORT_BUFFER_SIZE);
}
void PS3USB::setBdaddr(uint8_t* BDADDR) {
/* Set the internal bluetooth address */
uint8_t buf[8];
buf[0] = 0x01;
buf[1] = 0x00;
for (uint8_t i = 0; i < 6; i++)
buf[i+2] = BDADDR[5 - i];//Copy into buffer, has to be written reversed
buf[i + 2] = BDADDR[5 - i]; //Copy into buffer, has to be written reversed
//bmRequest = Host to device (0x00) | Class (0x20) | Interface (0x01) = 0x21, bRequest = Set Report (0x09), Report ID (0xF5), Report Type (Feature 0x03), interface (0x00), datalength, datalength, data)
pUsb->ctrlReq(bAddress,epInfo[PS3_CONTROL_PIPE].epAddr, bmREQ_HID_OUT, HID_REQUEST_SET_REPORT, 0xF5, 0x03, 0x00, 8, 8, buf, NULL);
pUsb->ctrlReq(bAddress, epInfo[PS3_CONTROL_PIPE].epAddr, bmREQ_HID_OUT, HID_REQUEST_SET_REPORT, 0xF5, 0x03, 0x00, 8, 8, buf, NULL);
#ifdef DEBUG
Notify(PSTR("\r\nBluetooth Address was set to: "));
for(int8_t i = 5; i > 0; i--) {
PrintHex<uint8_t>(my_bdaddr[i]);
Notify(PSTR("\r\nBluetooth Address was set to: "), 0x80);
for (int8_t i = 5; i > 0; i--) {
PrintHex<uint8_t > (my_bdaddr[i], 0x80);
Serial.print(":");
}
PrintHex<uint8_t>(my_bdaddr[0]);
PrintHex<uint8_t > (my_bdaddr[0], 0x80);
#endif
return;
}
void PS3USB::enable_sixaxis() { //Command used to enable the Dualshock 3 and Navigation controller to send data via USB
uint8_t cmd_buf[4];
cmd_buf[0] = 0x42;// Special PS3 Controller enable commands
cmd_buf[0] = 0x42; // Special PS3 Controller enable commands
cmd_buf[1] = 0x0c;
cmd_buf[2] = 0x00;
cmd_buf[3] = 0x00;
//bmRequest = Host to device (0x00) | Class (0x20) | Interface (0x01) = 0x21, bRequest = Set Report (0x09), Report ID (0xF4), Report Type (Feature 0x03), interface (0x00), datalength, datalength, data)
pUsb->ctrlReq(bAddress,epInfo[PS3_CONTROL_PIPE].epAddr, bmREQ_HID_OUT, HID_REQUEST_SET_REPORT, 0xF4, 0x03, 0x00, 4, 4, cmd_buf, NULL);
pUsb->ctrlReq(bAddress, epInfo[PS3_CONTROL_PIPE].epAddr, bmREQ_HID_OUT, HID_REQUEST_SET_REPORT, 0xF4, 0x03, 0x00, 4, 4, cmd_buf, NULL);
}
/* Playstation Move Controller commands */
@ -512,19 +523,22 @@ void PS3USB::moveSetBulb(uint8_t r, uint8_t g, uint8_t b) { //Use this to set th
Move_Command(writeBuf, MOVE_REPORT_BUFFER_SIZE);
}
void PS3USB::moveSetBulb(Colors color) { //Use this to set the Color using the predefined colors in "enums.h"
moveSetBulb((uint8_t)(color >> 16),(uint8_t)(color >> 8),(uint8_t)(color));
moveSetBulb((uint8_t)(color >> 16), (uint8_t)(color >> 8), (uint8_t)(color));
}
void PS3USB::moveSetRumble(uint8_t rumble) {
#ifdef DEBUG
if(rumble < 64 && rumble != 0) // The rumble value has to at least 64, or approximately 25% (64/255*100)
Notify(PSTR("\r\nThe rumble value has to at least 64, or approximately 25%"));
if (rumble < 64 && rumble != 0) // The rumble value has to at least 64, or approximately 25% (64/255*100)
Notify(PSTR("\r\nThe rumble value has to at least 64, or approximately 25%"), 0x80);
#endif
//set the rumble value into the write buffer
writeBuf[6] = rumble;
Move_Command(writeBuf, MOVE_REPORT_BUFFER_SIZE);
}
void PS3USB::setMoveBdaddr(uint8_t* BDADDR) {
/* Set the internal bluetooth address */
uint8_t buf[11];
@ -538,14 +552,14 @@ void PS3USB::setMoveBdaddr(uint8_t* BDADDR) {
buf[i + 1] = BDADDR[i];
//bmRequest = Host to device (0x00) | Class (0x20) | Interface (0x01) = 0x21, bRequest = Set Report (0x09), Report ID (0x05), Report Type (Feature 0x03), interface (0x00), datalength, datalength, data)
pUsb->ctrlReq(bAddress,epInfo[PS3_CONTROL_PIPE].epAddr, bmREQ_HID_OUT, HID_REQUEST_SET_REPORT, 0x05, 0x03, 0x00,11,11, buf, NULL);
pUsb->ctrlReq(bAddress, epInfo[PS3_CONTROL_PIPE].epAddr, bmREQ_HID_OUT, HID_REQUEST_SET_REPORT, 0x05, 0x03, 0x00, 11, 11, buf, NULL);
#ifdef DEBUG
Notify(PSTR("\r\nBluetooth Address was set to: "));
for(int8_t i = 5; i > 0; i--) {
PrintHex<uint8_t>(my_bdaddr[i]);
Notify(PSTR("\r\nBluetooth Address was set to: "), 0x80);
for (int8_t i = 5; i > 0; i--) {
PrintHex<uint8_t > (my_bdaddr[i], 0x80);
Serial.print(":");
}
PrintHex<uint8_t>(my_bdaddr[0]);
PrintHex<uint8_t > (my_bdaddr[0], 0x80);
#endif
return;
}

View file

@ -70,7 +70,7 @@ public:
* Pass your dongles Bluetooth address into the constructor,
* so you are able to pair the controller with a Bluetooth dongle.
*/
PS3USB(USB *pUsb, uint8_t btadr5=0, uint8_t btadr4=0, uint8_t btadr3=0, uint8_t btadr2=0, uint8_t btadr1=0, uint8_t btadr0=0);
PS3USB(USB *pUsb, uint8_t btadr5 = 0, uint8_t btadr4 = 0, uint8_t btadr3 = 0, uint8_t btadr2 = 0, uint8_t btadr1 = 0, uint8_t btadr0 = 0);
/** @name USBDeviceConfig implementation */
/**
@ -91,16 +91,22 @@ public:
* @return 0 on success.
*/
virtual uint8_t Poll();
/**
* Get the device address.
* @return The device address.
*/
virtual uint8_t GetAddress() { return bAddress; };
virtual uint8_t GetAddress() {
return bAddress;
};
/**
* Used to check if the controller has been initialized.
* @return True if it's ready.
*/
virtual bool isReady() { return bPollEnable; };
virtual bool isReady() {
return bPollEnable;
};
/**@}*/
/**
@ -176,6 +182,14 @@ public:
* @param mode Either ::RumbleHigh or ::RumbleLow.
*/
void setRumbleOn(Rumble mode);
/**
* Turn on ::Rumble using custom duration and power.
* @param rightDuration The duration of the right/low rumble effect.
* @param rightPower The intensity of the right/low rumble effect.
* @param leftDuration The duration of the left/high rumble effect.
* @param leftPower The intensity of the left/high rumble effect.
*/
void setRumbleOn(uint8_t rightDuration, uint8_t rightPower, uint8_t leftDuration, uint8_t leftPower);
/**
* Turn the specific ::LED off.
* @param a The ::LED to turn off.

531
SPP.cpp
View file

@ -23,7 +23,7 @@
/*
* CRC (reversed crc) lookup table as calculated by the table generator in ETSI TS 101 369 V6.3.0.
*/
const uint8_t rfcomm_crc_table[256] PROGMEM = { /* reversed, 8-bit, poly=0x07 */
const uint8_t rfcomm_crc_table[256] PROGMEM = {/* reversed, 8-bit, poly=0x07 */
0x00, 0x91, 0xE3, 0x72, 0x07, 0x96, 0xE4, 0x75, 0x0E, 0x9F, 0xED, 0x7C, 0x09, 0x98, 0xEA, 0x7B,
0x1C, 0x8D, 0xFF, 0x6E, 0x1B, 0x8A, 0xF8, 0x69, 0x12, 0x83, 0xF1, 0x60, 0x15, 0x84, 0xF6, 0x67,
0x38, 0xA9, 0xDB, 0x4A, 0x3F, 0xAE, 0xDC, 0x4D, 0x36, 0xA7, 0xD5, 0x44, 0x31, 0xA0, 0xD2, 0x43,
@ -42,7 +42,7 @@ const uint8_t rfcomm_crc_table[256] PROGMEM = { /* reversed, 8-bit, poly=0x07 */
0xB4, 0x25, 0x57, 0xC6, 0xB3, 0x22, 0x50, 0xC1, 0xBA, 0x2B, 0x59, 0xC8, 0xBD, 0x2C, 0x5E, 0xCF
};
SPP::SPP(BTD *p, const char* name, const char* pin):
SPP::SPP(BTD *p, const char* name, const char* pin) :
pBtd(p) // Pointer to BTD class instance - mandatory
{
if (pBtd)
@ -59,6 +59,7 @@ pBtd(p) // Pointer to BTD class instance - mandatory
Reset();
}
void SPP::Reset() {
connected = false;
RFCOMMConnected = false;
@ -67,25 +68,27 @@ void SPP::Reset() {
l2cap_rfcomm_state = L2CAP_RFCOMM_WAIT;
l2cap_event_flag = 0;
}
void SPP::disconnect(){
void SPP::disconnect() {
connected = false;
// First the two L2CAP channels has to be disconencted and then the HCI connection
if(RFCOMMConnected)
pBtd->l2cap_disconnection_request(hci_handle,0x0A, rfcomm_scid, rfcomm_dcid);
if(RFCOMMConnected && SDPConnected)
if (RFCOMMConnected)
pBtd->l2cap_disconnection_request(hci_handle, 0x0A, rfcomm_scid, rfcomm_dcid);
if (RFCOMMConnected && SDPConnected)
delay(1); // Add delay between commands
if(SDPConnected)
pBtd->l2cap_disconnection_request(hci_handle,0x0B, sdp_scid, sdp_dcid);
if (SDPConnected)
pBtd->l2cap_disconnection_request(hci_handle, 0x0B, sdp_scid, sdp_dcid);
l2cap_sdp_state = L2CAP_DISCONNECT_RESPONSE;
}
void SPP::ACLData(uint8_t* l2capinbuf) {
if(!connected) {
if (!connected) {
if (l2capinbuf[8] == L2CAP_CMD_CONNECTION_REQUEST) {
if((l2capinbuf[12] | (l2capinbuf[13] << 8)) == SDP_PSM && !pBtd->sdpConnectionClaimed) {
if ((l2capinbuf[12] | (l2capinbuf[13] << 8)) == SDP_PSM && !pBtd->sdpConnectionClaimed) {
pBtd->sdpConnectionClaimed = true;
hci_handle = pBtd->hci_handle; // Store the HCI Handle for the connection
l2cap_sdp_state = L2CAP_SDP_WAIT; // Reset state
} else if((l2capinbuf[12] | (l2capinbuf[13] << 8)) == RFCOMM_PSM && !pBtd->rfcommConnectionClaimed) {
} else if ((l2capinbuf[12] | (l2capinbuf[13] << 8)) == RFCOMM_PSM && !pBtd->rfcommConnectionClaimed) {
pBtd->rfcommConnectionClaimed = true;
hci_handle = pBtd->hci_handle; // Store the HCI Handle for the connection
l2cap_rfcomm_state = L2CAP_RFCOMM_WAIT; // Reset state
@ -96,31 +99,31 @@ void SPP::ACLData(uint8_t* l2capinbuf) {
if ((l2capinbuf[6] | (l2capinbuf[7] << 8)) == 0x0001) { //l2cap_control - Channel ID for ACL-U
if (l2capinbuf[8] == L2CAP_CMD_COMMAND_REJECT) {
#ifdef DEBUG
Notify(PSTR("\r\nL2CAP Command Rejected - Reason: "));
PrintHex<uint8_t>(l2capinbuf[13]);
Notify(PSTR(" "));
PrintHex<uint8_t>(l2capinbuf[12]);
Notify(PSTR(" Data: "));
PrintHex<uint8_t>(l2capinbuf[17]);
Notify(PSTR(" "));
PrintHex<uint8_t>(l2capinbuf[16]);
Notify(PSTR(" "));
PrintHex<uint8_t>(l2capinbuf[15]);
Notify(PSTR(" "));
PrintHex<uint8_t>(l2capinbuf[14]);
Notify(PSTR("\r\nL2CAP Command Rejected - Reason: "), 0x80);
PrintHex<uint8_t > (l2capinbuf[13], 0x80);
Notify(PSTR(" "), 0x80);
PrintHex<uint8_t > (l2capinbuf[12], 0x80);
Notify(PSTR(" Data: "), 0x80);
PrintHex<uint8_t > (l2capinbuf[17], 0x80);
Notify(PSTR(" "), 0x80);
PrintHex<uint8_t > (l2capinbuf[16], 0x80);
Notify(PSTR(" "), 0x80);
PrintHex<uint8_t > (l2capinbuf[15], 0x80);
Notify(PSTR(" "), 0x80);
PrintHex<uint8_t > (l2capinbuf[14], 0x80);
#endif
} else if (l2capinbuf[8] == L2CAP_CMD_CONNECTION_REQUEST) {
#ifdef EXTRADEBUG
Notify(PSTR("\r\nL2CAP Connection Request - PSM: "));
PrintHex<uint8_t>(l2capinbuf[13]);
Notify(PSTR(" "));
PrintHex<uint8_t>(l2capinbuf[12]);
Notify(PSTR(" SCID: "));
PrintHex<uint8_t>(l2capinbuf[15]);
Notify(PSTR(" "));
PrintHex<uint8_t>(l2capinbuf[14]);
Notify(PSTR(" Identifier: "));
PrintHex<uint8_t>(l2capinbuf[9]);
Notify(PSTR("\r\nL2CAP Connection Request - PSM: "), 0x80);
PrintHex<uint8_t > (l2capinbuf[13], 0x80);
Notify(PSTR(" "), 0x80);
PrintHex<uint8_t > (l2capinbuf[12], 0x80);
Notify(PSTR(" SCID: "), 0x80);
PrintHex<uint8_t > (l2capinbuf[15], 0x80);
Notify(PSTR(" "), 0x80);
PrintHex<uint8_t > (l2capinbuf[14], 0x80);
Notify(PSTR(" Identifier: "), 0x80);
PrintHex<uint8_t > (l2capinbuf[9], 0x80);
#endif
if ((l2capinbuf[12] | (l2capinbuf[13] << 8)) == SDP_PSM) { // It doesn't matter if it receives another reqeust, since it waits for the channel to disconnect in the L2CAP_SDP_DONE state, and the l2cap_event_flag will be cleared if so
identifier = l2capinbuf[9];
@ -138,8 +141,7 @@ void SPP::ACLData(uint8_t* l2capinbuf) {
if (l2capinbuf[12] == sdp_dcid[0] && l2capinbuf[13] == sdp_dcid[1]) {
//Serial.print("\r\nSDP Configuration Complete");
l2cap_event_flag |= L2CAP_FLAG_CONFIG_SDP_SUCCESS;
}
else if (l2capinbuf[12] == rfcomm_dcid[0] && l2capinbuf[13] == rfcomm_dcid[1]) {
} else if (l2capinbuf[12] == rfcomm_dcid[0] && l2capinbuf[13] == rfcomm_dcid[1]) {
//Serial.print("\r\nRFCOMM Configuration Complete");
l2cap_event_flag |= L2CAP_FLAG_CONFIG_RFCOMM_SUCCESS;
}
@ -149,19 +151,18 @@ void SPP::ACLData(uint8_t* l2capinbuf) {
//Serial.print("\r\nSDP Configuration Request");
identifier = l2capinbuf[9];
l2cap_event_flag |= L2CAP_FLAG_CONFIG_SDP_REQUEST;
}
else if (l2capinbuf[12] == rfcomm_dcid[0] && l2capinbuf[13] == rfcomm_dcid[1]) {
} else if (l2capinbuf[12] == rfcomm_dcid[0] && l2capinbuf[13] == rfcomm_dcid[1]) {
//Serial.print("\r\nRFCOMM Configuration Request");
identifier = l2capinbuf[9];
l2cap_event_flag |= L2CAP_FLAG_CONFIG_RFCOMM_REQUEST;
}
} else if (l2capinbuf[8] == L2CAP_CMD_DISCONNECT_REQUEST) {
if (l2capinbuf[12] == sdp_dcid[0] && l2capinbuf[13] == sdp_dcid[1]) {
//Notify(PSTR("\r\nDisconnect Request: SDP Channel"));
//Notify(PSTR("\r\nDisconnect Request: SDP Channel"), 0x80);
identifier = l2capinbuf[9];
l2cap_event_flag |= L2CAP_FLAG_DISCONNECT_SDP_REQUEST;
} else if (l2capinbuf[12] == rfcomm_dcid[0] && l2capinbuf[13] == rfcomm_dcid[1]) {
//Notify(PSTR("\r\nDisconnect Request: RFCOMM Channel"));
//Notify(PSTR("\r\nDisconnect Request: RFCOMM Channel"), 0x80);
identifier = l2capinbuf[9];
l2cap_event_flag |= L2CAP_FLAG_DISCONNECT_RFCOMM_REQUEST;
}
@ -177,19 +178,19 @@ void SPP::ACLData(uint8_t* l2capinbuf) {
}
} else if (l2capinbuf[8] == L2CAP_CMD_INFORMATION_REQUEST) {
#ifdef DEBUG
Notify(PSTR("\r\nInformation request"));
Notify(PSTR("\r\nInformation request"), 0x80);
#endif
identifier = l2capinbuf[9];
pBtd->l2cap_information_response(hci_handle,identifier,l2capinbuf[12],l2capinbuf[13]);
pBtd->l2cap_information_response(hci_handle, identifier, l2capinbuf[12], l2capinbuf[13]);
}
#ifdef EXTRADEBUG
else {
Notify(PSTR("\r\nL2CAP Unknown Signaling Command: "));
PrintHex<uint8_t>(l2capinbuf[8]);
Notify(PSTR("\r\nL2CAP Unknown Signaling Command: "), 0x80);
PrintHex<uint8_t > (l2capinbuf[8], 0x80);
}
#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_PDU) {
/*
Serial.print("\r\nUUID: 0x");
Serial.print(l2capinbuf[16],HEX);
@ -197,23 +198,23 @@ void SPP::ACLData(uint8_t* l2capinbuf) {
Serial.print(l2capinbuf[17],HEX);
*/
if ((l2capinbuf[16] << 8 | l2capinbuf[17]) == SERIALPORT_UUID) {
if(firstMessage) {
serialPortResponse1(l2capinbuf[9],l2capinbuf[10]);
if (firstMessage) {
serialPortResponse1(l2capinbuf[9], l2capinbuf[10]);
firstMessage = false;
} else {
serialPortResponse2(l2capinbuf[9],l2capinbuf[10]); // Serialport continuation state
serialPortResponse2(l2capinbuf[9], l2capinbuf[10]); // Serialport continuation state
firstMessage = true;
}
} else if ((l2capinbuf[16] << 8 | l2capinbuf[17]) == L2CAP_UUID) {
if(firstMessage) {
l2capResponse1(l2capinbuf[9],l2capinbuf[10]);
if (firstMessage) {
l2capResponse1(l2capinbuf[9], l2capinbuf[10]);
firstMessage = false;
} else {
l2capResponse2(l2capinbuf[9],l2capinbuf[10]); // L2CAP continuation state
l2capResponse2(l2capinbuf[9], l2capinbuf[10]); // L2CAP continuation state
firstMessage = true;
}
} else
serviceNotSupported(l2capinbuf[9],l2capinbuf[10]); // The service is not supported
serviceNotSupported(l2capinbuf[9], l2capinbuf[10]); // The service is not supported
}
} else if (l2capinbuf[6] == rfcomm_dcid[0] && l2capinbuf[7] == rfcomm_dcid[1]) { // RFCOMM
rfcommChannel = l2capinbuf[8] & 0xF8;
@ -222,54 +223,54 @@ void SPP::ACLData(uint8_t* l2capinbuf) {
rfcommChannelType = l2capinbuf[9] & 0xEF;
rfcommPfBit = l2capinbuf[9] & 0x10;
if(rfcommChannel>>3 != 0x00)
if (rfcommChannel >> 3 != 0x00)
rfcommChannelConnection = rfcommChannel;
#ifdef EXTRADEBUG
Notify(PSTR("\r\nRFCOMM Channel: "));
Serial.print(rfcommChannel>>3,HEX);
Notify(PSTR(" Direction: "));
Serial.print(rfcommDirection>>2,HEX);
Notify(PSTR(" CommandResponse: "));
Serial.print(rfcommCommandResponse>>1,HEX);
Notify(PSTR(" ChannelType: "));
Serial.print(rfcommChannelType,HEX);
Notify(PSTR(" PF_BIT: "));
Serial.print(rfcommPfBit,HEX);
Notify(PSTR("\r\nRFCOMM Channel: "), 0x80);
Serial.print(rfcommChannel >> 3, HEX);
Notify(PSTR(" Direction: "), 0x80);
Serial.print(rfcommDirection >> 2, HEX);
Notify(PSTR(" CommandResponse: "), 0x80);
Serial.print(rfcommCommandResponse >> 1, HEX);
Notify(PSTR(" ChannelType: "), 0x80);
Serial.print(rfcommChannelType, HEX);
Notify(PSTR(" PF_BIT: "), 0x80);
Serial.print(rfcommPfBit, HEX);
#endif
if (rfcommChannelType == RFCOMM_DISC) {
#ifdef DEBUG
Notify(PSTR("\r\nReceived Disconnect RFCOMM Command on channel: "));
Serial.print(rfcommChannel>>3,HEX);
Notify(PSTR("\r\nReceived Disconnect RFCOMM Command on channel: "), 0x80);
Serial.print(rfcommChannel >> 3, HEX);
#endif
connected = false;
sendRfcomm(rfcommChannel,rfcommDirection,rfcommCommandResponse,RFCOMM_UA,rfcommPfBit,rfcommbuf,0x00); // UA Command
sendRfcomm(rfcommChannel, rfcommDirection, rfcommCommandResponse, RFCOMM_UA, rfcommPfBit, rfcommbuf, 0x00); // UA Command
}
if(connected) {
if (connected) {
/* Read the incoming message */
if(rfcommChannelType == RFCOMM_UIH && rfcommChannel == rfcommChannelConnection) {
if (rfcommChannelType == RFCOMM_UIH && rfcommChannel == rfcommChannelConnection) {
uint8_t length = l2capinbuf[10] >> 1; // Get length
uint8_t offset = l2capinbuf[4]-length-4; // See if there is credit
if(rfcommAvailable + length <= sizeof(rfcommDataBuffer)) { // Don't add data to buffer if it would be full
for(uint8_t i = 0; i < length; i++)
rfcommDataBuffer[rfcommAvailable+i] = l2capinbuf[11+i+offset];
uint8_t offset = l2capinbuf[4] - length - 4; // See if there is credit
if (rfcommAvailable + length <= sizeof (rfcommDataBuffer)) { // Don't add data to buffer if it would be full
for (uint8_t i = 0; i < length; i++)
rfcommDataBuffer[rfcommAvailable + i] = l2capinbuf[11 + i + offset];
rfcommAvailable += length;
}
#ifdef EXTRADEBUG
Notify(PSTR("\r\nRFCOMM Data Available: "));
Notify(PSTR("\r\nRFCOMM Data Available: "), 0x80);
Serial.print(rfcommAvailable);
if (offset) {
Notify(PSTR(" - Credit: 0x"));
Serial.print(l2capinbuf[11],HEX);
Notify(PSTR(" - Credit: 0x"), 0x80);
Serial.print(l2capinbuf[11], HEX);
}
#endif
#ifdef PRINTREPORT // Uncomment "#define PRINTREPORT" to print the report send to the Arduino via Bluetooth
for(uint8_t i = 0; i < length; i++)
Serial.write(l2capinbuf[i+11+offset]);
for (uint8_t i = 0; i < length; i++)
Serial.write(l2capinbuf[i + 11 + offset]);
#endif
} else if (rfcommChannelType == RFCOMM_UIH && l2capinbuf[11] == BT_RFCOMM_RPN_CMD) { // UIH Remote Port Negotiation Command
#ifdef DEBUG
Notify(PSTR("\r\nReceived UIH Remote Port Negotiation Command"));
Notify(PSTR("\r\nReceived UIH Remote Port Negotiation Command"), 0x80);
#endif
rfcommbuf[0] = BT_RFCOMM_RPN_RSP; // Command
rfcommbuf[1] = l2capinbuf[12]; // Length and shiftet like so: length << 1 | 1
@ -281,26 +282,26 @@ void SPP::ACLData(uint8_t* l2capinbuf) {
rfcommbuf[7] = l2capinbuf[18]; // Max Fram Size MSB
rfcommbuf[8] = l2capinbuf[19]; // MaxRatransm.
rfcommbuf[9] = l2capinbuf[20]; // Number of Frames
sendRfcomm(rfcommChannel,rfcommDirection,0,RFCOMM_UIH,rfcommPfBit,rfcommbuf,0x0A); // UIH Remote Port Negotiation Response
} else if(rfcommChannelType == RFCOMM_UIH && l2capinbuf[11] == BT_RFCOMM_MSC_CMD) { // UIH Modem Status Command
sendRfcomm(rfcommChannel, rfcommDirection, 0, RFCOMM_UIH, rfcommPfBit, rfcommbuf, 0x0A); // UIH Remote Port Negotiation Response
} else if (rfcommChannelType == RFCOMM_UIH && l2capinbuf[11] == BT_RFCOMM_MSC_CMD) { // UIH Modem Status Command
#ifdef DEBUG
Notify(PSTR("\r\nSend UIH Modem Status Response"));
Notify(PSTR("\r\nSend UIH Modem Status Response"), 0x80);
#endif
rfcommbuf[0] = BT_RFCOMM_MSC_RSP; // UIH Modem Status Response
rfcommbuf[1] = 2 << 1 | 1; // Length and shiftet like so: length << 1 | 1
rfcommbuf[2] = l2capinbuf[13]; // Channel: (1 << 0) | (1 << 1) | (0 << 2) | (channel << 3)
rfcommbuf[3] = l2capinbuf[14];
sendRfcomm(rfcommChannel,rfcommDirection,0,RFCOMM_UIH,rfcommPfBit,rfcommbuf,0x04);
sendRfcomm(rfcommChannel, rfcommDirection, 0, RFCOMM_UIH, rfcommPfBit, rfcommbuf, 0x04);
}
} else {
if(rfcommChannelType == RFCOMM_SABM) { // SABM Command - this is sent twice: once for channel 0 and then for the channel to establish
if (rfcommChannelType == RFCOMM_SABM) { // SABM Command - this is sent twice: once for channel 0 and then for the channel to establish
#ifdef DEBUG
Notify(PSTR("\r\nReceived SABM Command"));
Notify(PSTR("\r\nReceived SABM Command"), 0x80);
#endif
sendRfcomm(rfcommChannel,rfcommDirection,rfcommCommandResponse,RFCOMM_UA,rfcommPfBit,rfcommbuf,0x00); // UA Command
} else if(rfcommChannelType == RFCOMM_UIH && l2capinbuf[11] == BT_RFCOMM_PN_CMD) { // UIH Parameter Negotiation Command
sendRfcomm(rfcommChannel, rfcommDirection, rfcommCommandResponse, RFCOMM_UA, rfcommPfBit, rfcommbuf, 0x00); // UA Command
} else if (rfcommChannelType == RFCOMM_UIH && l2capinbuf[11] == BT_RFCOMM_PN_CMD) { // UIH Parameter Negotiation Command
#ifdef DEBUG
Notify(PSTR("\r\nReceived UIH Parameter Negotiation Command"));
Notify(PSTR("\r\nReceived UIH Parameter Negotiation Command"), 0x80);
#endif
rfcommbuf[0] = BT_RFCOMM_PN_RSP; // UIH Parameter Negotiation Response
rfcommbuf[1] = l2capinbuf[12]; // Length and shiftet like so: length << 1 | 1
@ -308,48 +309,48 @@ void SPP::ACLData(uint8_t* l2capinbuf) {
rfcommbuf[3] = 0xE0; // Pre difined for Bluetooth, see 5.5.3 of TS 07.10 Adaption for RFCOMM
rfcommbuf[4] = 0x00; // Priority
rfcommbuf[5] = 0x00; // Timer
rfcommbuf[6] = BULK_MAXPKTSIZE-14; // Max Fram Size LSB - set to the size of received data (50)
rfcommbuf[6] = BULK_MAXPKTSIZE - 14; // Max Fram Size LSB - set to the size of received data (50)
rfcommbuf[7] = 0x00; // Max Fram Size MSB
rfcommbuf[8] = 0x00; // MaxRatransm.
rfcommbuf[9] = 0x00; // Number of Frames
sendRfcomm(rfcommChannel,rfcommDirection,0,RFCOMM_UIH,rfcommPfBit,rfcommbuf,0x0A);
} else if(rfcommChannelType == RFCOMM_UIH && l2capinbuf[11] == BT_RFCOMM_MSC_CMD) { // UIH Modem Status Command
sendRfcomm(rfcommChannel, rfcommDirection, 0, RFCOMM_UIH, rfcommPfBit, rfcommbuf, 0x0A);
} else if (rfcommChannelType == RFCOMM_UIH && l2capinbuf[11] == BT_RFCOMM_MSC_CMD) { // UIH Modem Status Command
#ifdef DEBUG
Notify(PSTR("\r\nSend UIH Modem Status Response"));
Notify(PSTR("\r\nSend UIH Modem Status Response"), 0x80);
#endif
rfcommbuf[0] = BT_RFCOMM_MSC_RSP; // UIH Modem Status Response
rfcommbuf[1] = 2 << 1 | 1; // Length and shiftet like so: length << 1 | 1
rfcommbuf[2] = l2capinbuf[13]; // Channel: (1 << 0) | (1 << 1) | (0 << 2) | (channel << 3)
rfcommbuf[3] = l2capinbuf[14];
sendRfcomm(rfcommChannel,rfcommDirection,0,RFCOMM_UIH,rfcommPfBit,rfcommbuf,0x04);
sendRfcomm(rfcommChannel, rfcommDirection, 0, RFCOMM_UIH, rfcommPfBit, rfcommbuf, 0x04);
delay(1);
#ifdef DEBUG
Notify(PSTR("\r\nSend UIH Modem Status Command"));
Notify(PSTR("\r\nSend UIH Modem Status Command"), 0x80);
#endif
rfcommbuf[0] = BT_RFCOMM_MSC_CMD; // UIH Modem Status Command
rfcommbuf[1] = 2 << 1 | 1; // Length and shiftet like so: length << 1 | 1
rfcommbuf[2] = l2capinbuf[13]; // Channel: (1 << 0) | (1 << 1) | (0 << 2) | (channel << 3)
rfcommbuf[3] = 0x8D; // Can receive frames (YES), Ready to Communicate (YES), Ready to Receive (YES), Incomig Call (NO), Data is Value (YES)
sendRfcomm(rfcommChannel,rfcommDirection,0,RFCOMM_UIH,rfcommPfBit,rfcommbuf,0x04);
} else if(rfcommChannelType == RFCOMM_UIH && l2capinbuf[11] == BT_RFCOMM_MSC_RSP) { // UIH Modem Status Response
if(!creditSent) {
sendRfcomm(rfcommChannel, rfcommDirection, 0, RFCOMM_UIH, rfcommPfBit, rfcommbuf, 0x04);
} else if (rfcommChannelType == RFCOMM_UIH && l2capinbuf[11] == BT_RFCOMM_MSC_RSP) { // UIH Modem Status Response
if (!creditSent) {
#ifdef DEBUG
Notify(PSTR("\r\nSend UIH Command with credit"));
Notify(PSTR("\r\nSend UIH Command with credit"), 0x80);
#endif
sendRfcommCredit(rfcommChannelConnection,rfcommDirection,0,RFCOMM_UIH,0x10,sizeof(rfcommDataBuffer)); // Send credit
sendRfcommCredit(rfcommChannelConnection, rfcommDirection, 0, RFCOMM_UIH, 0x10, sizeof (rfcommDataBuffer)); // Send credit
creditSent = true;
timer = millis();
waitForLastCommand = true;
}
} else if(rfcommChannelType == RFCOMM_UIH && l2capinbuf[10] == 0x01) { // UIH Command with credit
} else if (rfcommChannelType == RFCOMM_UIH && l2capinbuf[10] == 0x01) { // UIH Command with credit
#ifdef DEBUG
Notify(PSTR("\r\nReceived UIH Command with credit"));
Notify(PSTR("\r\nReceived UIH Command with credit"), 0x80);
#endif
} else if(rfcommChannelType == RFCOMM_UIH && l2capinbuf[11] == BT_RFCOMM_RPN_CMD) { // UIH Remote Port Negotiation Command
} else if (rfcommChannelType == RFCOMM_UIH && l2capinbuf[11] == BT_RFCOMM_RPN_CMD) { // UIH Remote Port Negotiation Command
#ifdef DEBUG
Notify(PSTR("\r\nReceived UIH Remote Port Negotiation Command"));
Notify(PSTR("\r\nReceived UIH Remote Port Negotiation Command"), 0x80);
#endif
rfcommbuf[0] = BT_RFCOMM_RPN_RSP; // Command
rfcommbuf[1] = l2capinbuf[12]; // Length and shiftet like so: length << 1 | 1
@ -361,61 +362,62 @@ void SPP::ACLData(uint8_t* l2capinbuf) {
rfcommbuf[7] = l2capinbuf[18]; // Max Fram Size MSB
rfcommbuf[8] = l2capinbuf[19]; // MaxRatransm.
rfcommbuf[9] = l2capinbuf[20]; // Number of Frames
sendRfcomm(rfcommChannel,rfcommDirection,0,RFCOMM_UIH,rfcommPfBit,rfcommbuf,0x0A); // UIH Remote Port Negotiation Response
sendRfcomm(rfcommChannel, rfcommDirection, 0, RFCOMM_UIH, rfcommPfBit, rfcommbuf, 0x0A); // UIH Remote Port Negotiation Response
#ifdef DEBUG
Notify(PSTR("\r\nRFCOMM Connection is now established\r\n"));
Notify(PSTR("\r\nRFCOMM Connection is now established\r\n"), 0x80);
#endif
waitForLastCommand = false;
creditSent = false;
connected = true; // The RFCOMM channel is now established
}
#ifdef DEBUG
else if(rfcommChannelType != RFCOMM_DISC) {
Notify(PSTR("\r\nUnsupported RFCOMM Data - ChannelType: "));
PrintHex<uint8_t>(rfcommChannelType);
Notify(PSTR(" Command: "));
PrintHex<uint8_t>(l2capinbuf[11]);
else if (rfcommChannelType != RFCOMM_DISC) {
Notify(PSTR("\r\nUnsupported RFCOMM Data - ChannelType: "), 0x80);
PrintHex<uint8_t > (rfcommChannelType, 0x80);
Notify(PSTR(" Command: "), 0x80);
PrintHex<uint8_t > (l2capinbuf[11], 0x80);
}
#endif
}
}
#ifdef EXTRADEBUG
else {
Notify(PSTR("\r\nUnsupported L2CAP Data - Channel ID: "));
PrintHex<uint8_t>(l2capinbuf[7]);
Notify(PSTR(" "));
PrintHex<uint8_t>(l2capinbuf[6]);
Notify(PSTR("\r\nUnsupported L2CAP Data - Channel ID: "), 0x80);
PrintHex<uint8_t > (l2capinbuf[7], 0x80);
Notify(PSTR(" "), 0x80);
PrintHex<uint8_t > (l2capinbuf[6], 0x80);
}
#endif
SDP_task();
RFCOMM_task();
}
}
void SPP::Run() {
if(waitForLastCommand && (millis() - timer) > 100) { // We will only wait 100ms and see if the UIH Remote Port Negotiation Command is send, as some deviced don't send it
if (waitForLastCommand && (millis() - timer) > 100) { // We will only wait 100ms and see if the UIH Remote Port Negotiation Command is send, as some deviced don't send it
#ifdef DEBUG
Notify(PSTR("\r\nRFCOMM Connection is now established - Automatic\r\n"));
Notify(PSTR("\r\nRFCOMM Connection is now established - Automatic\r\n"), 0x80);
#endif
creditSent = false;
waitForLastCommand = false;
connected = true; // The RFCOMM channel is now established
}
}
void SPP::SDP_task() {
switch (l2cap_sdp_state)
{
switch (l2cap_sdp_state) {
case L2CAP_SDP_WAIT:
if (l2cap_connection_request_sdp_flag) {
l2cap_event_flag &= ~L2CAP_FLAG_CONNECTION_SDP_REQUEST; // Clear flag
#ifdef DEBUG
Notify(PSTR("\r\nSDP Incoming Connection Request"));
Notify(PSTR("\r\nSDP Incoming Connection Request"), 0x80);
#endif
pBtd->l2cap_connection_response(hci_handle,identifier, sdp_dcid, sdp_scid, PENDING);
pBtd->l2cap_connection_response(hci_handle, identifier, sdp_dcid, sdp_scid, PENDING);
delay(1);
pBtd->l2cap_connection_response(hci_handle,identifier, sdp_dcid, sdp_scid, SUCCESSFUL);
pBtd->l2cap_connection_response(hci_handle, identifier, sdp_dcid, sdp_scid, SUCCESSFUL);
identifier++;
delay(1);
pBtd->l2cap_config_request(hci_handle,identifier, sdp_scid);
pBtd->l2cap_config_request(hci_handle, identifier, sdp_scid);
l2cap_sdp_state = L2CAP_SDP_REQUEST;
}
break;
@ -423,9 +425,9 @@ void SPP::SDP_task() {
if (l2cap_config_request_sdp_flag) {
l2cap_event_flag &= ~L2CAP_FLAG_CONFIG_SDP_REQUEST; // Clear flag
#ifdef DEBUG
Notify(PSTR("\r\nSDP Configuration Request"));
Notify(PSTR("\r\nSDP Configuration Request"), 0x80);
#endif
pBtd->l2cap_config_response(hci_handle,identifier, sdp_scid);
pBtd->l2cap_config_response(hci_handle, identifier, sdp_scid);
l2cap_sdp_state = L2CAP_SDP_SUCCESS;
}
break;
@ -433,7 +435,7 @@ void SPP::SDP_task() {
if (l2cap_config_success_sdp_flag) {
l2cap_event_flag &= ~L2CAP_FLAG_CONFIG_SDP_SUCCESS; // Clear flag
#ifdef DEBUG
Notify(PSTR("\r\nSDP Successfully Configured"));
Notify(PSTR("\r\nSDP Successfully Configured"), 0x80);
#endif
firstMessage = true; // Reset bool
SDPConnected = true;
@ -441,21 +443,21 @@ void SPP::SDP_task() {
}
break;
case L2CAP_SDP_DONE:
if(l2cap_disconnect_request_sdp_flag) {
if (l2cap_disconnect_request_sdp_flag) {
l2cap_event_flag &= ~L2CAP_FLAG_DISCONNECT_SDP_REQUEST; // Clear flag
SDPConnected = false;
#ifdef DEBUG
Notify(PSTR("\r\nDisconnected SDP Channel"));
Notify(PSTR("\r\nDisconnected SDP Channel"), 0x80);
#endif
pBtd->l2cap_disconnection_response(hci_handle,identifier,sdp_dcid,sdp_scid);
pBtd->l2cap_disconnection_response(hci_handle, identifier, sdp_dcid, sdp_scid);
l2cap_sdp_state = L2CAP_SDP_WAIT;
} else if(l2cap_connection_request_sdp_flag)
} else if (l2cap_connection_request_sdp_flag)
l2cap_rfcomm_state = L2CAP_SDP_WAIT;
break;
case L2CAP_DISCONNECT_RESPONSE: // This is for both disconnection response from the RFCOMM and SDP channel if they were connected
if (l2cap_disconnect_response_flag) {
#ifdef DEBUG
Notify(PSTR("\r\nDisconnected L2CAP Connection"));
Notify(PSTR("\r\nDisconnected L2CAP Connection"), 0x80);
#endif
RFCOMMConnected = false;
SDPConnected = false;
@ -468,22 +470,21 @@ void SPP::SDP_task() {
break;
}
}
void SPP::RFCOMM_task()
{
switch (l2cap_rfcomm_state)
{
void SPP::RFCOMM_task() {
switch (l2cap_rfcomm_state) {
case L2CAP_RFCOMM_WAIT:
if(l2cap_connection_request_rfcomm_flag) {
if (l2cap_connection_request_rfcomm_flag) {
l2cap_event_flag &= ~L2CAP_FLAG_CONNECTION_RFCOMM_REQUEST; // Clear flag
#ifdef DEBUG
Notify(PSTR("\r\nRFCOMM Incoming Connection Request"));
Notify(PSTR("\r\nRFCOMM Incoming Connection Request"), 0x80);
#endif
pBtd->l2cap_connection_response(hci_handle,identifier, rfcomm_dcid, rfcomm_scid, PENDING);
pBtd->l2cap_connection_response(hci_handle, identifier, rfcomm_dcid, rfcomm_scid, PENDING);
delay(1);
pBtd->l2cap_connection_response(hci_handle,identifier, rfcomm_dcid, rfcomm_scid, SUCCESSFUL);
pBtd->l2cap_connection_response(hci_handle, identifier, rfcomm_dcid, rfcomm_scid, SUCCESSFUL);
identifier++;
delay(1);
pBtd->l2cap_config_request(hci_handle,identifier, rfcomm_scid);
pBtd->l2cap_config_request(hci_handle, identifier, rfcomm_scid);
l2cap_rfcomm_state = L2CAP_RFCOMM_REQUEST;
}
break;
@ -491,9 +492,9 @@ void SPP::RFCOMM_task()
if (l2cap_config_request_rfcomm_flag) {
l2cap_event_flag &= ~L2CAP_FLAG_CONFIG_RFCOMM_REQUEST; // Clear flag
#ifdef DEBUG
Notify(PSTR("\r\nRFCOMM Configuration Request"));
Notify(PSTR("\r\nRFCOMM Configuration Request"), 0x80);
#endif
pBtd->l2cap_config_response(hci_handle,identifier, rfcomm_scid);
pBtd->l2cap_config_response(hci_handle, identifier, rfcomm_scid);
l2cap_rfcomm_state = L2CAP_RFCOMM_SUCCESS;
}
break;
@ -501,7 +502,7 @@ void SPP::RFCOMM_task()
if (l2cap_config_success_rfcomm_flag) {
l2cap_event_flag &= ~L2CAP_FLAG_CONFIG_RFCOMM_SUCCESS; // Clear flag
#ifdef DEBUG
Notify(PSTR("\r\nRFCOMM Successfully Configured"));
Notify(PSTR("\r\nRFCOMM Successfully Configured"), 0x80);
#endif
rfcommAvailable = 0; // Reset number of bytes available
bytesRead = 0; // Reset number of bytes received
@ -510,26 +511,28 @@ void SPP::RFCOMM_task()
}
break;
case L2CAP_RFCOMM_DONE:
if(l2cap_disconnect_request_rfcomm_flag) {
if (l2cap_disconnect_request_rfcomm_flag) {
l2cap_event_flag &= ~L2CAP_FLAG_DISCONNECT_RFCOMM_REQUEST; // Clear flag
RFCOMMConnected = false;
connected = false;
#ifdef DEBUG
Notify(PSTR("\r\nDisconnected RFCOMM Channel"));
Notify(PSTR("\r\nDisconnected RFCOMM Channel"), 0x80);
#endif
pBtd->l2cap_disconnection_response(hci_handle,identifier,rfcomm_dcid,rfcomm_scid);
pBtd->l2cap_disconnection_response(hci_handle, identifier, rfcomm_dcid, rfcomm_scid);
l2cap_rfcomm_state = L2CAP_RFCOMM_WAIT;
} else if(l2cap_connection_request_rfcomm_flag)
} else if (l2cap_connection_request_rfcomm_flag)
l2cap_rfcomm_state = L2CAP_RFCOMM_WAIT;
break;
}
}
/************************************************************/
/* 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]);
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;
@ -544,8 +547,9 @@ void SPP::serviceNotSupported(uint8_t transactionIDHigh, uint8_t transactionIDLo
l2capoutbuf[8] = 0x00;
l2capoutbuf[9] = 0x00;
SDP_Command(l2capoutbuf,10);
SDP_Command(l2capoutbuf, 10);
}
void SPP::serialPortResponse1(uint8_t transactionIDHigh, uint8_t transactionIDLow) {
l2capoutbuf[0] = SDP_SERVICE_SEARCH_ATTRIBUTE_RESPONSE_PDU;
l2capoutbuf[1] = transactionIDHigh;
@ -601,8 +605,9 @@ void SPP::serialPortResponse1(uint8_t transactionIDHigh, uint8_t transactionIDLo
l2capoutbuf[46] = 0x00; // 25 (0x19) more bytes to come
l2capoutbuf[47] = 0x19;
SDP_Command(l2capoutbuf,48);
SDP_Command(l2capoutbuf, 48);
}
void SPP::serialPortResponse2(uint8_t transactionIDHigh, uint8_t transactionIDLow) {
l2capoutbuf[0] = SDP_SERVICE_SEARCH_ATTRIBUTE_RESPONSE_PDU;
l2capoutbuf[1] = transactionIDHigh;
@ -642,19 +647,22 @@ void SPP::serialPortResponse2(uint8_t transactionIDHigh, uint8_t transactionIDLo
l2capoutbuf[31] = 'P';
l2capoutbuf[32] = 0x00; // No more data
SDP_Command(l2capoutbuf,33);
SDP_Command(l2capoutbuf, 33);
}
void SPP::l2capResponse1(uint8_t transactionIDHigh, uint8_t transactionIDLow) {
serialPortResponse1(transactionIDHigh,transactionIDLow); // These has to send all the supported functions, since it only supports virtual serialport it just sends the message again
serialPortResponse1(transactionIDHigh, transactionIDLow); // These has to send all the supported functions, since it only supports virtual serialport it just sends the message again
}
void SPP::l2capResponse2(uint8_t transactionIDHigh, uint8_t transactionIDLow) {
serialPortResponse2(transactionIDHigh,transactionIDLow); // Same data as serialPortResponse2
serialPortResponse2(transactionIDHigh, transactionIDLow); // Same data as serialPortResponse2
}
/************************************************************/
/* RFCOMM Commands */
/************************************************************/
void SPP::RFCOMM_Command(uint8_t* data, uint8_t nbytes) {
pBtd->L2CAP_Command(hci_handle,data,nbytes,rfcomm_scid[0],rfcomm_scid[1]);
pBtd->L2CAP_Command(hci_handle, data, nbytes, rfcomm_scid[0], rfcomm_scid[1]);
}
void SPP::sendRfcomm(uint8_t channel, uint8_t direction, uint8_t CR, uint8_t channelType, uint8_t pfBit, uint8_t* data, uint8_t length) {
@ -662,17 +670,17 @@ void SPP::sendRfcomm(uint8_t channel, uint8_t direction, uint8_t CR, uint8_t cha
l2capoutbuf[1] = channelType | pfBit; // RFCOMM Control
l2capoutbuf[2] = length << 1 | 0x01; // Length and format (allways 0x01 bytes format)
uint8_t i = 0;
for(; i < length; i++)
l2capoutbuf[i+3] = data[i];
l2capoutbuf[i+3] = calcFcs(l2capoutbuf);
for (; i < length; i++)
l2capoutbuf[i + 3] = data[i];
l2capoutbuf[i + 3] = calcFcs(l2capoutbuf);
#ifdef EXTRADEBUG
Notify(PSTR(" - RFCOMM Data: "));
for(i = 0; i < length+4; i++) {
Serial.print(l2capoutbuf[i],HEX);
Notify(PSTR(" "));
Notify(PSTR(" - RFCOMM Data: "), 0x80);
for (i = 0; i < length + 4; i++) {
Serial.print(l2capoutbuf[i], HEX);
Notify(PSTR(" "), 0x80);
}
#endif
RFCOMM_Command(l2capoutbuf,length+4);
RFCOMM_Command(l2capoutbuf, length + 4);
}
void SPP::sendRfcommCredit(uint8_t channel, uint8_t direction, uint8_t CR, uint8_t channelType, uint8_t pfBit, uint8_t credit) {
@ -682,23 +690,23 @@ void SPP::sendRfcommCredit(uint8_t channel, uint8_t direction, uint8_t CR, uint8
l2capoutbuf[3] = credit; // Credit
l2capoutbuf[4] = calcFcs(l2capoutbuf);
#ifdef EXTRADEBUG
Notify(PSTR(" - RFCOMM Credit Data: "));
for(uint8_t i = 0; i < 5; i++) {
Serial.print(l2capoutbuf[i],HEX);
Notify(PSTR(" "));
Notify(PSTR(" - RFCOMM Credit Data: "), 0x80);
for (uint8_t i = 0; i < 5; i++) {
Serial.print(l2capoutbuf[i], HEX);
Notify(PSTR(" "), 0x80);
}
#endif
RFCOMM_Command(l2capoutbuf,5);
RFCOMM_Command(l2capoutbuf, 5);
}
/* CRC on 2 bytes */
uint8_t SPP::__crc(uint8_t* data) {
return(pgm_read_byte(&rfcomm_crc_table[pgm_read_byte(&rfcomm_crc_table[0xff ^ data[0]]) ^ data[1]]));
return (pgm_read_byte(&rfcomm_crc_table[pgm_read_byte(&rfcomm_crc_table[0xff ^ data[0]]) ^ data[1]]));
}
/* Calculate FCS - we never actually check if the host sends correct FCS to the Arduino */
uint8_t SPP::calcFcs(uint8_t *data) {
if((data[1] & 0xEF) == RFCOMM_UIH)
if ((data[1] & 0xEF) == RFCOMM_UIH)
return (0xff - __crc(data)); // FCS on 2 bytes
else
return (0xff - pgm_read_byte(&rfcomm_crc_table[__crc(data) ^ data[2]])); // FCS on 3 bytes
@ -706,143 +714,159 @@ uint8_t SPP::calcFcs(uint8_t *data) {
/* Serial commands */
void SPP::print(const String &str) {
if(!connected)
if (!connected)
return;
uint8_t length = str.length();
if(length > (sizeof(l2capoutbuf)-4))
length = sizeof(l2capoutbuf)-4;
l2capoutbuf[0] = rfcommChannelConnection | 0 | 0 | extendAddress;; // RFCOMM Address
if (length > (sizeof (l2capoutbuf) - 4))
length = sizeof (l2capoutbuf) - 4;
l2capoutbuf[0] = rfcommChannelConnection | 0 | 0 | extendAddress;
; // RFCOMM Address
l2capoutbuf[1] = RFCOMM_UIH; // RFCOMM Control
l2capoutbuf[2] = length << 1 | 1; // Length
uint8_t i = 0;
for(; i < length; i++)
l2capoutbuf[i+3] = str[i];
l2capoutbuf[i+3] = calcFcs(l2capoutbuf);
for (; i < length; i++)
l2capoutbuf[i + 3] = str[i];
l2capoutbuf[i + 3] = calcFcs(l2capoutbuf);
RFCOMM_Command(l2capoutbuf,length+4);
RFCOMM_Command(l2capoutbuf, length + 4);
}
void SPP::print(const char* str) {
if(!connected)
if (!connected)
return;
uint8_t length = strlen(str);
if(length > (sizeof(l2capoutbuf)-4))
length = sizeof(l2capoutbuf)-4;
l2capoutbuf[0] = rfcommChannelConnection | 0 | 0 | extendAddress;; // RFCOMM Address
if (length > (sizeof (l2capoutbuf) - 4))
length = sizeof (l2capoutbuf) - 4;
l2capoutbuf[0] = rfcommChannelConnection | 0 | 0 | extendAddress;
; // RFCOMM Address
l2capoutbuf[1] = RFCOMM_UIH; // RFCOMM Control
l2capoutbuf[2] = length << 1 | 1; // Length
uint8_t i = 0;
for(; i < length; i++)
l2capoutbuf[i+3] = str[i];
l2capoutbuf[i+3] = calcFcs(l2capoutbuf);
for (; i < length; i++)
l2capoutbuf[i + 3] = str[i];
l2capoutbuf[i + 3] = calcFcs(l2capoutbuf);
RFCOMM_Command(l2capoutbuf,length+4);
RFCOMM_Command(l2capoutbuf, length + 4);
}
void SPP::print(uint8_t* array, uint8_t length) {
if(!connected)
if (!connected)
return;
if(length > (sizeof(l2capoutbuf)-4))
length = sizeof(l2capoutbuf)-4;
l2capoutbuf[0] = rfcommChannelConnection | 0 | 0 | extendAddress;; // RFCOMM Address
if (length > (sizeof (l2capoutbuf) - 4))
length = sizeof (l2capoutbuf) - 4;
l2capoutbuf[0] = rfcommChannelConnection | 0 | 0 | extendAddress;
; // RFCOMM Address
l2capoutbuf[1] = RFCOMM_UIH; // RFCOMM Control
l2capoutbuf[2] = length << 1 | 1; // Length
uint8_t i = 0;
for(; i < length; i++)
l2capoutbuf[i+3] = array[i];
l2capoutbuf[i+3] = calcFcs(l2capoutbuf);
for (; i < length; i++)
l2capoutbuf[i + 3] = array[i];
l2capoutbuf[i + 3] = calcFcs(l2capoutbuf);
RFCOMM_Command(l2capoutbuf,length+4);
RFCOMM_Command(l2capoutbuf, length + 4);
}
void SPP::println(const String &str) {
String output = str + "\r\n";
print(output);
}
void SPP::println(const char* str) {
char output[strlen(str)+3];
strcpy(output,str);
strcat(output,"\r\n");
char output[strlen(str) + 3];
strcpy(output, str);
strcat(output, "\r\n");
print(output);
}
void SPP::println(uint8_t data) {
uint8_t buf[3] = {data, '\r', '\n'};
print(buf,3);
print(buf, 3);
}
void SPP::println(uint8_t* array, uint8_t length) {
uint8_t buf[length+2];
memcpy(buf,array,length);
uint8_t buf[length + 2];
memcpy(buf, array, length);
buf[length] = '\r';
buf[length+1] = '\n';
print(buf,length+2);
buf[length + 1] = '\n';
print(buf, length + 2);
}
void SPP::printFlashString(const __FlashStringHelper *ifsh, bool newline) {
const char PROGMEM *p = (const char PROGMEM *)ifsh;
uint8_t size = 0;
while (1) { // Calculate the size of the string
uint8_t c = pgm_read_byte(p+size);
uint8_t c = pgm_read_byte(p + size);
if (c == 0)
break;
size++;
}
uint8_t buf[size+2]; // Add two extra in case it needs to print a newline and carriage return
uint8_t buf[size + 2]; // Add two extra in case it needs to print a newline and carriage return
for(uint8_t i = 0; i < size; i++)
for (uint8_t i = 0; i < size; i++)
buf[i] = pgm_read_byte(p++);
if(newline) {
if (newline) {
buf[size] = '\r';
buf[size+1] = '\n';
print(buf,size+2);
buf[size + 1] = '\n';
print(buf, size + 2);
} else
print(buf,size);
print(buf, size);
}
void SPP::println(void) {
uint8_t buf[2] = {'\r','\n'};
print(buf,2);
uint8_t buf[2] = {'\r', '\n'};
print(buf, 2);
}
/* These must be used to print numbers */
void SPP::printNumber(uint32_t n) {
char output[11];
intToString(n,output);
intToString(n, output);
print(output);
}
void SPP::printNumberln(uint32_t n) {
char output[13];
intToString(n,output);
strcat(output,"\r\n");
intToString(n, output);
strcat(output, "\r\n");
print(output);
}
void SPP::printNumber(int32_t n) {
char output[12];
intToString(n,output);
intToString(n, output);
print(output);
}
void SPP::printNumberln(int32_t n) {
char output[14];
intToString(n,output);
strcat(output,"\r\n");
intToString(n, output);
strcat(output, "\r\n");
print(output);
}
void SPP::intToString(int32_t input, char* output) {
if(input < 0) {
if (input < 0) {
char buf[11];
intToString((uint32_t)(input*-1),buf);
strcpy(output,"-");
strcat(output,buf);
intToString((uint32_t)(input*-1), buf);
strcpy(output, "-");
strcat(output, buf);
} else
intToString((uint32_t)input,output);
intToString((uint32_t)input, output);
}
void SPP::intToString(uint32_t input, char* output) {
uint32_t temp = input;
uint8_t digits = 0;
while(temp) {
while (temp) {
temp /= 10;
digits++;
}
if(digits == 0)
strcpy(output,"0");
if (digits == 0)
strcpy(output, "0");
else {
for(uint8_t i = 1; i <= digits; i++) {
output[digits-i] = input%10 + '0'; // Get number and convert to ASCII Character
for (uint8_t i = 1; i <= digits; i++) {
output[digits - i] = input % 10 + '0'; // Get number and convert to ASCII Character
input /= 10;
}
output[digits] = '\0'; // Add null character
@ -850,61 +874,62 @@ void SPP::intToString(uint32_t input, char* output) {
}
void SPP::printNumber(double n, uint8_t digits) {
char output[13+digits];
doubleToString(n,output,digits);
char output[13 + digits];
doubleToString(n, output, digits);
print(output);
}
void SPP::printNumberln(double n, uint8_t digits) {
char output[15+digits];
doubleToString(n,output,digits);
strcat(output,"\r\n");
char output[15 + digits];
doubleToString(n, output, digits);
strcat(output, "\r\n");
print(output);
}
void SPP::doubleToString(double input, char* output, uint8_t digits) {
char buffer[13+digits];
if(input < 0) {
strcpy(output,"-");
char buffer[13 + digits];
if (input < 0) {
strcpy(output, "-");
input = -input;
}
else
strcpy(output,"");
} else
strcpy(output, "");
// Round correctly
double rounding = 0.5;
for (uint8_t i=0; i<digits; i++)
for (uint8_t i = 0; i < digits; i++)
rounding /= 10.0;
input += rounding;
uint32_t intpart = (uint32_t)input;
intToString(intpart,buffer); // Convert to string
strcat(output,buffer);
strcat(output,".");
double fractpart = (input-(double)intpart);
fractpart *= pow(10,digits);
for(uint8_t i=1;i<digits;i++) { // Put zeros in front of number
if(fractpart < pow(10,digits-i)) {
strcat(output,"0");
intToString(intpart, buffer); // Convert to string
strcat(output, buffer);
strcat(output, ".");
double fractpart = (input - (double)intpart);
fractpart *= pow(10, digits);
for (uint8_t i = 1; i < digits; i++) { // Put zeros in front of number
if (fractpart < pow(10, digits - i)) {
strcat(output, "0");
}
}
intToString((uint32_t)fractpart,buffer); // Convert to string
strcat(output,buffer);
intToString((uint32_t)fractpart, buffer); // Convert to string
strcat(output, buffer);
}
uint8_t SPP::read() {
if(rfcommAvailable == 0) // Don't read if there is nothing in the buffer
if (rfcommAvailable == 0) // Don't read if there is nothing in the buffer
return 0;
uint8_t output = rfcommDataBuffer[0];
for(uint8_t i = 1; i < rfcommAvailable; i++)
rfcommDataBuffer[i-1] = rfcommDataBuffer[i]; // Shift the buffer one left
for (uint8_t i = 1; i < rfcommAvailable; i++)
rfcommDataBuffer[i - 1] = rfcommDataBuffer[i]; // Shift the buffer one left
rfcommAvailable--;
bytesRead++;
if(bytesRead > (sizeof(rfcommDataBuffer)-5)) { // We will send the command just before it runs out of credit
if (bytesRead > (sizeof (rfcommDataBuffer) - 5)) { // We will send the command just before it runs out of credit
bytesRead = 0;
sendRfcommCredit(rfcommChannelConnection,rfcommDirection,0,RFCOMM_UIH,0x10,sizeof(rfcommDataBuffer)); // Send more credit
sendRfcommCredit(rfcommChannelConnection, rfcommDirection, 0, RFCOMM_UIH, 0x10, sizeof (rfcommDataBuffer)); // Send more credit
#ifdef EXTRADEBUG
Notify(PSTR("\r\nSent "));
Serial.print(sizeof(rfcommDataBuffer));
Notify(PSTR(" more credit"));
Notify(PSTR("\r\nSent "), 0x80);
Serial.print(sizeof (rfcommDataBuffer));
Notify(PSTR(" more credit"), 0x80);
#endif
}
return output;

62
SPP.h
View file

@ -87,7 +87,7 @@
#define BT_RFCOMM_RLS_CMD 0x53
#define BT_RFCOMM_RLS_RSP 0x51
#define BT_RFCOMM_NSC_RSP 0x11
*/
*/
/** This BluetoothService class implements the Serial Port Protocol (SPP). */
class SPP : public BluetoothService {
@ -144,7 +144,9 @@ public:
* Used to send single bytes.
* @param data Data to send.
*/
void print(uint8_t data) { print(&data,1); };
void print(uint8_t data) {
print(&data, 1);
};
/**
* Same as print(uint8_t data), but will include newline and carriage return.
* @param data Data to send.
@ -169,12 +171,17 @@ public:
* Use "SerialBT.print(F("String"));" to print a string stored in flash.
* @param ifsh String to send - see: http://playground.arduino.cc/Learning/Memory.
*/
void print(const __FlashStringHelper *ifsh) { printFlashString(ifsh,false); };
void print(const __FlashStringHelper *ifsh) {
printFlashString(ifsh, false);
};
/**
* Same as print(const __FlashStringHelper *ifsh), but will include newline and carriage return.
* @param ifsh String to send - see: http://playground.arduino.cc/Learning/Memory.
*/
void println(const __FlashStringHelper *ifsh) { printFlashString(ifsh,true); };
void println(const __FlashStringHelper *ifsh) {
printFlashString(ifsh, true);
};
/**
* Helper function to print a string stored in flash.
* @param ifsh String stored in flash you want to print.
@ -190,43 +197,65 @@ public:
* Used to print unsigned integers.
* @param n Unsigned integer to send.
*/
void printNumber(uint8_t n) { printNumber((uint32_t)n); };
void printNumber(uint8_t n) {
printNumber((uint32_t) n);
};
/**
* Same as printNumber(uint8_t n), but will include newline and carriage return.
* @param n Unsigned integer to send.
*/
void printNumberln(uint8_t n) { printNumberln((uint32_t)n); };
void printNumberln(uint8_t n) {
printNumberln((uint32_t) n);
};
/**
* Used to print signed integers.
* @param n Signed integer to send.
*/
void printNumber(int8_t n) { printNumber((int32_t)n); };
void printNumber(int8_t n) {
printNumber((int32_t) n);
};
/**
* Same as printNumber(int8_t n), but will include newline and carriage return.
* @param n Signed integer to send.
*/
void printNumberln(int8_t n) { printNumberln((int32_t)n); };
void printNumberln(int8_t n) {
printNumberln((int32_t) n);
};
/**
* Used to print unsigned integers.
* @param n Unsigned integer to send.
*/
void printNumber(uint16_t n) { printNumber((uint32_t)n); };
void printNumber(uint16_t n) {
printNumber((uint32_t) n);
};
/**
* Same as printNumber(uint16_t n), but will include newline and carriage return.
* @param n Unsigned integer to send.
*/
void printNumberln(uint16_t n) { printNumberln((uint32_t)n); };
void printNumberln(uint16_t n) {
printNumberln((uint32_t) n);
};
/**
* Used to print signed integers.
* @param n Signed integer to send.
*/
void printNumber(int16_t n) { printNumber((int32_t)n); };
void printNumber(int16_t n) {
printNumber((int32_t) n);
};
/**
* Same as printNumber(int16_t n), but will include newline and carriage return.
* @param n Signed integer to send.
*/
void printNumberln(int16_t n) { printNumberln((int32_t)n); };
void printNumberln(int16_t n) {
printNumberln((int32_t) n);
};
/**
* Used to print unsigned integers.
@ -287,14 +316,19 @@ public:
* Get number of bytes waiting to be read.
* @return Return the number of bytes ready to be read.
*/
uint8_t available() { return rfcommAvailable; };
uint8_t available() {
return rfcommAvailable;
};
/**
* Used to read the buffer.
* @return Return the byte. Will return 0 if no byte is available.
*/
uint8_t read();
/** Discard all the bytes in the buffer. */
void flush() { rfcommAvailable = 0; };
void flush() {
rfcommAvailable = 0;
};
/**@}*/
private:

362
Usb.cpp
View file

@ -13,7 +13,7 @@ Contact information
Circuits At Home, LTD
Web : http://www.circuitsathome.com
e-mail : support@circuitsathome.com
*/
*/
/* USB functions */
#include "avrpins.h"
@ -31,31 +31,26 @@ static uint8_t usb_error = 0;
static uint8_t usb_task_state;
/* constructor */
USB::USB () : bmHubPre(0)
{
USB::USB() : bmHubPre(0) {
usb_task_state = USB_DETACHED_SUBSTATE_INITIALIZE; //set up state machine
init();
}
/* Initialize data structures */
void USB::init()
{
void USB::init() {
devConfigIndex = 0;
bmHubPre = 0;
}
uint8_t USB::getUsbTaskState( void )
{
return( usb_task_state );
uint8_t USB::getUsbTaskState(void) {
return ( usb_task_state);
}
void USB::setUsbTaskState( uint8_t state )
{
void USB::setUsbTaskState(uint8_t state) {
usb_task_state = state;
}
EpInfo* USB::getEpInfoEntry( uint8_t addr, uint8_t ep )
{
EpInfo* USB::getEpInfoEntry(uint8_t addr, uint8_t ep) {
UsbDevice *p = addrPool.GetUsbDevicePtr(addr);
if (!p || !p->epinfo)
@ -63,20 +58,19 @@ EpInfo* USB::getEpInfoEntry( uint8_t addr, uint8_t ep )
EpInfo *pep = p->epinfo;
for (uint8_t i=0; i<p->epcount; i++)
{
for (uint8_t i = 0; i < p->epcount; i++) {
if ((pep)->epAddr == ep)
return pep;
pep ++;
pep++;
}
return NULL;
}
/* set device table entry */
/* each device is different and has different number of endpoints. This function plugs endpoint record structure, defined in application, to devtable */
uint8_t USB::setEpInfoEntry( uint8_t addr, uint8_t epcount, EpInfo* eprecord_ptr )
{
uint8_t USB::setEpInfoEntry(uint8_t addr, uint8_t epcount, EpInfo* eprecord_ptr) {
if (!eprecord_ptr)
return USB_ERROR_INVALID_ARGUMENT;
@ -92,8 +86,7 @@ uint8_t USB::setEpInfoEntry( uint8_t addr, uint8_t epcount, EpInfo* eprecord_ptr
return 0;
}
uint8_t USB::SetAddress(uint8_t addr, uint8_t ep, EpInfo **ppep, uint16_t &nak_limit)
{
uint8_t USB::SetAddress(uint8_t addr, uint8_t ep, EpInfo **ppep, uint16_t &nak_limit) {
UsbDevice *p = addrPool.GetUsbDevicePtr(addr);
if (!p)
@ -107,22 +100,21 @@ uint8_t USB::SetAddress(uint8_t addr, uint8_t ep, EpInfo **ppep, uint16_t &nak_l
if (!*ppep)
return USB_ERROR_EP_NOT_FOUND_IN_TBL;
nak_limit = (0x0001UL << ( ( (*ppep)->bmNakPower > USB_NAK_MAX_POWER ) ? USB_NAK_MAX_POWER : (*ppep)->bmNakPower) );
nak_limit = (0x0001UL << (((*ppep)->bmNakPower > USB_NAK_MAX_POWER) ? USB_NAK_MAX_POWER : (*ppep)->bmNakPower));
nak_limit--;
/*
/*
USBTRACE2("\r\nAddress: ", addr);
USBTRACE2(" EP: ", ep);
USBTRACE2(" NAK Power: ",(*ppep)->bmNakPower);
USBTRACE2(" NAK Limit: ", nak_limit);
USBTRACE("\r\n");
*/
regWr( rPERADDR, addr ); //set peripheral address
*/
regWr(rPERADDR, addr); //set peripheral address
uint8_t mode = regRd( rMODE );
uint8_t mode = regRd(rMODE);
// Set bmLOWSPEED and bmHUBPRE in case of low-speed device, reset them otherwise
regWr( rMODE, (p->lowspeed) ? mode | bmLOWSPEED | bmHubPre : mode & ~(bmHUBPRE | bmLOWSPEED));
regWr(rMODE, (p->lowspeed) ? mode | bmLOWSPEED | bmHubPre : mode & ~(bmHUBPRE | bmLOWSPEED));
return 0;
}
@ -131,11 +123,11 @@ uint8_t USB::SetAddress(uint8_t addr, uint8_t ep, EpInfo **ppep, uint16_t &nak_l
/* depending on request. Actual requests are defined as inlines */
/* return codes: */
/* 00 = success */
/* 01-0f = non-zero HRSLT */
uint8_t USB::ctrlReq( uint8_t addr, uint8_t ep, uint8_t bmReqType, uint8_t bRequest, uint8_t wValLo, uint8_t wValHi,
uint16_t wInd, uint16_t total, uint16_t nbytes, uint8_t* dataptr, USBReadParser *p)
{
boolean direction = false; //request direction, IN or OUT
uint8_t USB::ctrlReq(uint8_t addr, uint8_t ep, uint8_t bmReqType, uint8_t bRequest, uint8_t wValLo, uint8_t wValHi,
uint16_t wInd, uint16_t total, uint16_t nbytes, uint8_t* dataptr, USBReadParser *p) {
bool direction = false; //request direction, IN or OUT
uint8_t rcode;
SETUP_PKT setup_pkt;
@ -147,7 +139,7 @@ uint8_t USB::ctrlReq( uint8_t addr, uint8_t ep, uint8_t bmReqType, uint8_t bRequ
if (rcode)
return rcode;
direction = (( bmReqType & 0x80 ) > 0);
direction = ((bmReqType & 0x80) > 0);
/* fill in setup packet */
setup_pkt.ReqType_u.bmRequestType = bmReqType;
@ -157,96 +149,98 @@ uint8_t USB::ctrlReq( uint8_t addr, uint8_t ep, uint8_t bmReqType, uint8_t bRequ
setup_pkt.wIndex = wInd;
setup_pkt.wLength = total;
bytesWr( rSUDFIFO, 8, (uint8_t*)&setup_pkt ); //transfer to setup packet FIFO
bytesWr(rSUDFIFO, 8, (uint8_t*) & setup_pkt); //transfer to setup packet FIFO
rcode = dispatchPkt( tokSETUP, ep, nak_limit ); //dispatch packet
rcode = dispatchPkt(tokSETUP, ep, nak_limit); //dispatch packet
if( rcode ) //return HRSLT if not zero
return( rcode );
if (rcode) //return HRSLT if not zero
return ( rcode);
if( dataptr != NULL ) //data stage, if present
if (dataptr != NULL) //data stage, if present
{
if( direction ) //IN transfer
if (direction) //IN transfer
{
uint16_t left = total;
pep->bmRcvToggle = 1; //bmRCVTOG1;
while (left)
{
while (left) {
// Bytes read into buffer
uint16_t read = nbytes;
//uint16_t read = (left<nbytes) ? left : nbytes;
rcode = InTransfer( pep, nak_limit, &read, dataptr );
rcode = InTransfer(pep, nak_limit, &read, dataptr);
if (rcode)
return rcode;
// Invoke callback function if inTransfer completed successfuly and callback function pointer is specified
if (!rcode && p)
((USBReadParser*)p)->Parse( read, dataptr, total - left );
((USBReadParser*)p)->Parse(read, dataptr, total - left);
left -= read;
if (read < nbytes)
break;
}
}
else //OUT transfer
} else //OUT transfer
{
pep->bmSndToggle = 1; //bmSNDTOG1;
rcode = OutTransfer( pep, nak_limit, nbytes, dataptr );
rcode = OutTransfer(pep, nak_limit, nbytes, dataptr);
}
if( rcode ) //return error
return( rcode );
if (rcode) //return error
return ( rcode);
}
// Status stage
return dispatchPkt( (direction) ? tokOUTHS : tokINHS, ep, nak_limit ); //GET if direction
return dispatchPkt((direction) ? tokOUTHS : tokINHS, ep, nak_limit); //GET if direction
}
/* IN transfer to arbitrary endpoint. Assumes PERADDR is set. Handles multiple packets if necessary. Transfers 'nbytes' bytes. */
/* Keep sending INs and writes data to memory area pointed by 'data' */
/* rcode 0 if no errors. rcode 01-0f is relayed from dispatchPkt(). Rcode f0 means RCVDAVIRQ error,
fe USB xfer timeout */
uint8_t USB::inTransfer( uint8_t addr, uint8_t ep, uint16_t *nbytesptr, uint8_t* data)
{
uint8_t USB::inTransfer(uint8_t addr, uint8_t ep, uint16_t *nbytesptr, uint8_t* data) {
EpInfo *pep = NULL;
uint16_t nak_limit = 0;
uint8_t rcode = SetAddress(addr, ep, &pep, nak_limit);
if (rcode)
if (rcode) {
//printf("SetAddress Failed");
return rcode;
}
return InTransfer(pep, nak_limit, nbytesptr, data);
}
uint8_t USB::InTransfer(EpInfo *pep, uint16_t nak_limit, uint16_t *nbytesptr, uint8_t* data)
{
uint8_t USB::InTransfer(EpInfo *pep, uint16_t nak_limit, uint16_t *nbytesptr, uint8_t* data) {
uint8_t rcode = 0;
uint8_t pktsize;
uint16_t nbytes = *nbytesptr;
//printf("Requesting %i bytes ", nbytes);
uint8_t maxpktsize = pep->maxPktSize;
*nbytesptr = 0;
regWr( rHCTL, (pep->bmRcvToggle) ? bmRCVTOG1 : bmRCVTOG0 ); //set toggle value
regWr(rHCTL, (pep->bmRcvToggle) ? bmRCVTOG1 : bmRCVTOG0); //set toggle value
while( 1 ) // use a 'return' to exit this loop
while (1) // use a 'return' to exit this loop
{
rcode = dispatchPkt( tokIN, pep->epAddr, nak_limit ); //IN packet to EP-'endpoint'. Function takes care of NAKS.
if( rcode )
return( rcode ); //should be 0, indicating ACK. Else return error code.
rcode = dispatchPkt(tokIN, pep->epAddr, nak_limit); //IN packet to EP-'endpoint'. Function takes care of NAKS.
if (rcode) {
//printf("Problem! %i\r\n", rcode);
break; //should be 0, indicating ACK. Else return error code.
}
/* check for RCVDAVIRQ and generate error if not present */
/* the only case when absense of RCVDAVIRQ makes sense is when toggle error occured. Need to add handling for that */
if(( regRd( rHIRQ ) & bmRCVDAVIRQ ) == 0 )
return ( 0xf0 ); //receive error
pktsize = regRd( rRCVBC ); //number of received bytes
if ((regRd(rHIRQ) & bmRCVDAVIRQ) == 0) {
//printf("Problem! NO RCVDAVIRQ!\r\n");
rcode = 0xf0; //receive error
break;
}
pktsize = regRd(rRCVBC); //number of received bytes
//printf("Got %i bytes ", pktsize);
assert(pktsize <= nbytes);
int16_t mem_left = (int16_t)nbytes - *((int16_t*)nbytesptr);
@ -254,29 +248,31 @@ uint8_t USB::InTransfer(EpInfo *pep, uint16_t nak_limit, uint16_t *nbytesptr, ui
if (mem_left < 0)
mem_left = 0;
data = bytesRd( rRCVFIFO, ((pktsize > mem_left) ? mem_left : pktsize), data );
data = bytesRd(rRCVFIFO, ((pktsize > mem_left) ? mem_left : pktsize), data);
regWr( rHIRQ, bmRCVDAVIRQ ); // Clear the IRQ & free the buffer
regWr(rHIRQ, bmRCVDAVIRQ); // Clear the IRQ & free the buffer
*nbytesptr += pktsize; // add this packet's byte count to total transfer length
/* The transfer is complete under two conditions: */
/* 1. The device sent a short packet (L.T. maxPacketSize) */
/* 2. 'nbytes' have been transferred. */
if (( pktsize < maxpktsize ) || (*nbytesptr >= nbytes )) // have we transferred 'nbytes' bytes?
if ((pktsize < maxpktsize) || (*nbytesptr >= nbytes)) // have we transferred 'nbytes' bytes?
{
// Save toggle value
pep->bmRcvToggle = (( regRd( rHRSL ) & bmRCVTOGRD )) ? 1 : 0;
return( 0 );
pep->bmRcvToggle = ((regRd(rHRSL) & bmRCVTOGRD)) ? 1 : 0;
//printf("\r\n");
rcode = 0;
break;
} // if
} //while( 1 )
return ( rcode);
}
/* OUT transfer to arbitrary endpoint. Handles multiple packets if necessary. Transfers 'nbytes' bytes. */
/* Handles NAK bug per Maxim Application Note 4000 for single buffer transfer */
/* rcode 0 if no errors. rcode 01-0f is relayed from HRSL */
uint8_t USB::outTransfer( uint8_t addr, uint8_t ep, uint16_t nbytes, uint8_t* data )
{
uint8_t USB::outTransfer(uint8_t addr, uint8_t ep, uint16_t nbytes, uint8_t* data) {
EpInfo *pep = NULL;
uint16_t nak_limit;
@ -288,9 +284,8 @@ uint8_t USB::outTransfer( uint8_t addr, uint8_t ep, uint16_t nbytes, uint8_t* da
return OutTransfer(pep, nak_limit, nbytes, data);
}
uint8_t USB::OutTransfer(EpInfo *pep, uint16_t nak_limit, uint16_t nbytes, uint8_t *data)
{
uint8_t rcode, retry_count;
uint8_t USB::OutTransfer(EpInfo *pep, uint16_t nak_limit, uint16_t nbytes, uint8_t *data) {
uint8_t rcode = hrSUCCESS, retry_count;
uint8_t *data_p = data; //local copy of the data pointer
uint16_t bytes_tosend, nak_count;
uint16_t bytes_left = nbytes;
@ -302,117 +297,110 @@ uint8_t USB::OutTransfer(EpInfo *pep, uint16_t nak_limit, uint16_t nbytes, uint8
unsigned long timeout = millis() + USB_XFER_TIMEOUT;
regWr( rHCTL, (pep->bmSndToggle) ? bmSNDTOG1 : bmSNDTOG0 ); //set toggle value
regWr(rHCTL, (pep->bmSndToggle) ? bmSNDTOG1 : bmSNDTOG0); //set toggle value
while( bytes_left )
{
while (bytes_left) {
retry_count = 0;
nak_count = 0;
bytes_tosend = ( bytes_left >= maxpktsize ) ? maxpktsize : bytes_left;
bytesWr( rSNDFIFO, bytes_tosend, data_p ); //filling output FIFO
regWr( rSNDBC, bytes_tosend ); //set number of bytes
regWr( rHXFR, ( tokOUT | pep->epAddr )); //dispatch packet
while(!(regRd( rHIRQ ) & bmHXFRDNIRQ )); //wait for the completion IRQ
regWr( rHIRQ, bmHXFRDNIRQ ); //clear IRQ
rcode = ( regRd( rHRSL ) & 0x0f );
bytes_tosend = (bytes_left >= maxpktsize) ? maxpktsize : bytes_left;
bytesWr(rSNDFIFO, bytes_tosend, data_p); //filling output FIFO
regWr(rSNDBC, bytes_tosend); //set number of bytes
regWr(rHXFR, (tokOUT | pep->epAddr)); //dispatch packet
while (!(regRd(rHIRQ) & bmHXFRDNIRQ)); //wait for the completion IRQ
regWr(rHIRQ, bmHXFRDNIRQ); //clear IRQ
rcode = (regRd(rHRSL) & 0x0f);
while( rcode && ( timeout > millis()))
{
switch( rcode )
{
while (rcode && (timeout > millis())) {
switch (rcode) {
case hrNAK:
nak_count ++;
if( nak_limit && ( nak_count == nak_limit ))
return( rcode );
nak_count++;
if (nak_limit && (nak_count == nak_limit))
return ( rcode);
break;
case hrTIMEOUT:
retry_count ++;
if( retry_count == USB_RETRY_LIMIT )
return( rcode );
retry_count++;
if (retry_count == USB_RETRY_LIMIT)
return ( rcode);
break;
default:
return( rcode );
return ( rcode);
}//switch( rcode
/* process NAK according to Host out NAK bug */
regWr( rSNDBC, 0 );
regWr( rSNDFIFO, *data_p );
regWr( rSNDBC, bytes_tosend );
regWr( rHXFR, ( tokOUT | pep->epAddr )); //dispatch packet
while(!(regRd( rHIRQ ) & bmHXFRDNIRQ )); //wait for the completion IRQ
regWr( rHIRQ, bmHXFRDNIRQ ); //clear IRQ
rcode = ( regRd( rHRSL ) & 0x0f );
regWr(rSNDBC, 0);
regWr(rSNDFIFO, *data_p);
regWr(rSNDBC, bytes_tosend);
regWr(rHXFR, (tokOUT | pep->epAddr)); //dispatch packet
while (!(regRd(rHIRQ) & bmHXFRDNIRQ)); //wait for the completion IRQ
regWr(rHIRQ, bmHXFRDNIRQ); //clear IRQ
rcode = (regRd(rHRSL) & 0x0f);
}//while( rcode && ....
bytes_left -= bytes_tosend;
data_p += bytes_tosend;
}//while( bytes_left...
pep->bmSndToggle = ( regRd( rHRSL ) & bmSNDTOGRD ) ? 1 : 0; //bmSNDTOG1 : bmSNDTOG0; //update toggle
return( rcode ); //should be 0 in all cases
pep->bmSndToggle = (regRd(rHRSL) & bmSNDTOGRD) ? 1 : 0; //bmSNDTOG1 : bmSNDTOG0; //update toggle
return ( rcode); //should be 0 in all cases
}
/* dispatch usb packet. Assumes peripheral address is set and relevant buffer is loaded/empty */
/* If NAK, tries to re-send up to nak_limit times */
/* If nak_limit == 0, do not count NAKs, exit after timeout */
/* If bus timeout, re-sends up to USB_RETRY_LIMIT times */
/* return codes 0x00-0x0f are HRSLT( 0x00 being success ), 0xff means timeout */
uint8_t USB::dispatchPkt( uint8_t token, uint8_t ep, uint16_t nak_limit )
{
uint8_t USB::dispatchPkt(uint8_t token, uint8_t ep, uint16_t nak_limit) {
unsigned long timeout = millis() + USB_XFER_TIMEOUT;
uint8_t tmpdata;
uint8_t rcode;
uint8_t rcode = hrSUCCESS;
uint8_t retry_count = 0;
uint16_t nak_count = 0;
while( timeout > millis() )
{
regWr( rHXFR, ( token|ep )); //launch the transfer
while (timeout > millis()) {
regWr(rHXFR, (token | ep)); //launch the transfer
rcode = USB_ERROR_TRANSFER_TIMEOUT;
while( millis() < timeout ) //wait for transfer completion
while (millis() < timeout) //wait for transfer completion
{
tmpdata = regRd( rHIRQ );
tmpdata = regRd(rHIRQ);
if( tmpdata & bmHXFRDNIRQ )
{
regWr( rHIRQ, bmHXFRDNIRQ ); //clear the interrupt
if (tmpdata & bmHXFRDNIRQ) {
regWr(rHIRQ, bmHXFRDNIRQ); //clear the interrupt
rcode = 0x00;
break;
}//if( tmpdata & bmHXFRDNIRQ
}//while ( millis() < timeout
if( rcode != 0x00 ) //exit if timeout
return( rcode );
if (rcode != 0x00) //exit if timeout
return ( rcode);
rcode = ( regRd( rHRSL ) & 0x0f ); //analyze transfer result
rcode = (regRd(rHRSL) & 0x0f); //analyze transfer result
switch( rcode )
{
switch (rcode) {
case hrNAK:
nak_count ++;
if( nak_limit && ( nak_count == nak_limit ))
return( rcode );
//delay(1);
nak_count++;
if (nak_limit && (nak_count == nak_limit))
return ( rcode);
break;
case hrTIMEOUT:
retry_count ++;
if( retry_count == USB_RETRY_LIMIT )
return( rcode );
retry_count++;
if (retry_count == USB_RETRY_LIMIT)
return ( rcode);
break;
default:
return( rcode );
return ( rcode);
}//switch( rcode
}//while( timeout > millis()
return( rcode );
return ( rcode);
}
/* USB main task. Performs enumeration/cleanup */
void USB::Task( void ) //USB state machine
void USB::Task(void) //USB state machine
{
uint8_t rcode;
uint8_t tmpdata;
static unsigned long delay = 0;
USB_DEVICE_DESCRIPTOR buf;
//USB_DEVICE_DESCRIPTOR buf;
bool lowspeed = false;
MAX3421E::Task();
@ -420,37 +408,35 @@ void USB::Task( void ) //USB state machine
tmpdata = getVbusState();
/* modify USB task state if Vbus changed */
switch( tmpdata )
{
switch (tmpdata) {
case SE1: //illegal state
usb_task_state = USB_DETACHED_SUBSTATE_ILLEGAL;
lowspeed = false;
break;
case SE0: //disconnected
if(( usb_task_state & USB_STATE_MASK ) != USB_STATE_DETACHED )
if ((usb_task_state & USB_STATE_MASK) != USB_STATE_DETACHED)
usb_task_state = USB_DETACHED_SUBSTATE_INITIALIZE;
lowspeed = false;
break;
case LSHOST:
lowspeed = true;
case FSHOST: //attached
if(( usb_task_state & USB_STATE_MASK ) == USB_STATE_DETACHED )
{
if ((usb_task_state & USB_STATE_MASK) == USB_STATE_DETACHED) {
delay = millis() + USB_SETTLE_DELAY;
usb_task_state = USB_ATTACHED_SUBSTATE_SETTLE;
}
break;
}// switch( tmpdata
for (uint8_t i=0; i<USB_NUMDEVICES; i++)
for (uint8_t i = 0; i < USB_NUMDEVICES; i++)
if (devConfig[i])
rcode = devConfig[i]->Poll();
switch( usb_task_state ) {
switch (usb_task_state) {
case USB_DETACHED_SUBSTATE_INITIALIZE:
init();
for (uint8_t i=0; i<USB_NUMDEVICES; i++)
for (uint8_t i = 0; i < USB_NUMDEVICES; i++)
if (devConfig[i])
rcode = devConfig[i]->Release();
@ -460,42 +446,38 @@ void USB::Task( void ) //USB state machine
break;
case USB_DETACHED_SUBSTATE_ILLEGAL: //just sit here
break;
case USB_ATTACHED_SUBSTATE_SETTLE: //setlle time for just attached device
if( delay < millis() )
case USB_ATTACHED_SUBSTATE_SETTLE: //settle time for just attached device
if (delay < millis())
usb_task_state = USB_ATTACHED_SUBSTATE_RESET_DEVICE;
break;
case USB_ATTACHED_SUBSTATE_RESET_DEVICE:
regWr( rHCTL, bmBUSRST ); //issue bus reset
regWr(rHCTL, bmBUSRST); //issue bus reset
usb_task_state = USB_ATTACHED_SUBSTATE_WAIT_RESET_COMPLETE;
break;
case USB_ATTACHED_SUBSTATE_WAIT_RESET_COMPLETE:
if(( regRd( rHCTL ) & bmBUSRST ) == 0 )
{
tmpdata = regRd( rMODE ) | bmSOFKAENAB; //start SOF generation
regWr( rMODE, tmpdata );
if ((regRd(rHCTL) & bmBUSRST) == 0) {
tmpdata = regRd(rMODE) | bmSOFKAENAB; //start SOF generation
regWr(rMODE, tmpdata);
usb_task_state = USB_ATTACHED_SUBSTATE_WAIT_SOF;
delay = millis() + 20; //20ms wait after reset per USB spec
}
break;
case USB_ATTACHED_SUBSTATE_WAIT_SOF: //todo: change check order
if( regRd( rHIRQ ) & bmFRAMEIRQ ) //when first SOF received we can continue
if (regRd(rHIRQ) & bmFRAMEIRQ) //when first SOF received we can continue
{
if( delay < millis() ) //20ms passed
if (delay < millis()) //20ms passed
usb_task_state = USB_STATE_CONFIGURING;
}
break;
case USB_STATE_CONFIGURING:
rcode = Configuring(0, 0, lowspeed);
if (rcode)
{
if (rcode != USB_DEV_CONFIG_ERROR_DEVICE_INIT_INCOMPLETE)
{
if (rcode) {
if (rcode != USB_DEV_CONFIG_ERROR_DEVICE_INIT_INCOMPLETE) {
usb_error = rcode;
usb_task_state = USB_STATE_ERROR;
}
}
else
} else
usb_task_state = USB_STATE_RUNNING;
break;
case USB_STATE_RUNNING:
@ -505,9 +487,8 @@ void USB::Task( void ) //USB state machine
} // switch( usb_task_state )
}
uint8_t USB::DefaultAddressing(uint8_t parent, uint8_t port, bool lowspeed)
{
uint8_t buf[12];
uint8_t USB::DefaultAddressing(uint8_t parent, uint8_t port, bool lowspeed) {
//uint8_t buf[12];
uint8_t rcode;
UsbDevice *p0 = NULL, *p = NULL;
@ -536,10 +517,9 @@ uint8_t USB::DefaultAddressing(uint8_t parent, uint8_t port, bool lowspeed)
p->lowspeed = lowspeed;
// Assign new address to the device
rcode = setAddr( 0, 0, bAddress );
rcode = setAddr(0, 0, bAddress);
if (rcode)
{
if (rcode) {
addrPool.FreeAddress(bAddress);
bAddress = 0;
return rcode;
@ -547,25 +527,21 @@ uint8_t USB::DefaultAddressing(uint8_t parent, uint8_t port, bool lowspeed)
return 0;
};
uint8_t USB::Configuring(uint8_t parent, uint8_t port, bool lowspeed)
{
static uint8_t dev_index = 0;
uint8_t USB::Configuring(uint8_t parent, uint8_t port, bool lowspeed) {
//static uint8_t dev_index = 0;
uint8_t rcode = 0;
for (; devConfigIndex<USB_NUMDEVICES; devConfigIndex++)
{
for (; devConfigIndex < USB_NUMDEVICES; devConfigIndex++) {
if (!devConfig[devConfigIndex])
continue;
rcode = devConfig[devConfigIndex]->Init(parent, port, lowspeed);
if (!rcode)
{
if (!rcode) {
devConfigIndex = 0;
return 0;
}
if (!(rcode == USB_DEV_CONFIG_ERROR_DEVICE_NOT_SUPPORTED || rcode == USB_ERROR_CLASS_INSTANCE_ALREADY_IN_USE))
{
if (!(rcode == USB_DEV_CONFIG_ERROR_DEVICE_NOT_SUPPORTED || rcode == USB_ERROR_CLASS_INSTANCE_ALREADY_IN_USE)) {
// in case of an error dev_index should be reset to 0
// in order to start from the very beginning the
// next time the program gets here
@ -583,59 +559,59 @@ uint8_t USB::Configuring(uint8_t parent, uint8_t port, bool lowspeed)
return rcode;
}
uint8_t USB::ReleaseDevice(uint8_t addr)
{
uint8_t USB::ReleaseDevice(uint8_t addr) {
if (!addr)
return 0;
for (uint8_t i=0; i<USB_NUMDEVICES; i++)
for (uint8_t i = 0; i < USB_NUMDEVICES; i++)
if (devConfig[i]->GetAddress() == addr)
return devConfig[i]->Release();
return 0;
}
#if 1 //!defined(USB_METHODS_INLINE)
//get device descriptor
uint8_t USB::getDevDescr( uint8_t addr, uint8_t ep, uint16_t nbytes, uint8_t* dataptr )
{
return( ctrlReq( addr, ep, bmREQ_GET_DESCR, USB_REQUEST_GET_DESCRIPTOR, 0x00, USB_DESCRIPTOR_DEVICE, 0x0000, nbytes, nbytes, dataptr, NULL ));
uint8_t USB::getDevDescr(uint8_t addr, uint8_t ep, uint16_t nbytes, uint8_t* dataptr) {
return ( ctrlReq(addr, ep, bmREQ_GET_DESCR, USB_REQUEST_GET_DESCRIPTOR, 0x00, USB_DESCRIPTOR_DEVICE, 0x0000, nbytes, nbytes, dataptr, NULL));
}
//get configuration descriptor
uint8_t USB::getConfDescr( uint8_t addr, uint8_t ep, uint16_t nbytes, uint8_t conf, uint8_t* dataptr )
{
return( ctrlReq( addr, ep, bmREQ_GET_DESCR, USB_REQUEST_GET_DESCRIPTOR, conf, USB_DESCRIPTOR_CONFIGURATION, 0x0000, nbytes, nbytes, dataptr, NULL ));
uint8_t USB::getConfDescr(uint8_t addr, uint8_t ep, uint16_t nbytes, uint8_t conf, uint8_t* dataptr) {
return ( ctrlReq(addr, ep, bmREQ_GET_DESCR, USB_REQUEST_GET_DESCRIPTOR, conf, USB_DESCRIPTOR_CONFIGURATION, 0x0000, nbytes, nbytes, dataptr, NULL));
}
uint8_t USB::getConfDescr( uint8_t addr, uint8_t ep, uint8_t conf, USBReadParser *p )
{
uint8_t USB::getConfDescr(uint8_t addr, uint8_t ep, uint8_t conf, USBReadParser *p) {
const uint8_t bufSize = 64;
uint8_t buf[bufSize];
uint8_t ret = getConfDescr( addr, ep, 8, conf, buf );
uint8_t ret = getConfDescr(addr, ep, 8, conf, buf);
if (ret)
return ret;
uint16_t total = ((USB_CONFIGURATION_DESCRIPTOR*)buf)->wTotalLength;
delay(100);
//USBTRACE2("\r\ntotal conf.size:", total);
return( ctrlReq( addr, ep, bmREQ_GET_DESCR, USB_REQUEST_GET_DESCRIPTOR, conf, USB_DESCRIPTOR_CONFIGURATION, 0x0000, total, bufSize, buf, p ));
return ( ctrlReq(addr, ep, bmREQ_GET_DESCR, USB_REQUEST_GET_DESCRIPTOR, conf, USB_DESCRIPTOR_CONFIGURATION, 0x0000, total, bufSize, buf, p));
}
//get string descriptor
uint8_t USB::getStrDescr( uint8_t addr, uint8_t ep, uint16_t ns, uint8_t index, uint16_t langid, uint8_t* dataptr )
{
return( ctrlReq( addr, ep, bmREQ_GET_DESCR, USB_REQUEST_GET_DESCRIPTOR, index, USB_DESCRIPTOR_STRING, langid, ns, ns, dataptr, NULL ));
uint8_t USB::getStrDescr(uint8_t addr, uint8_t ep, uint16_t ns, uint8_t index, uint16_t langid, uint8_t* dataptr) {
return ( ctrlReq(addr, ep, bmREQ_GET_DESCR, USB_REQUEST_GET_DESCRIPTOR, index, USB_DESCRIPTOR_STRING, langid, ns, ns, dataptr, NULL));
}
//set address
uint8_t USB::setAddr( uint8_t oldaddr, uint8_t ep, uint8_t newaddr )
{
return( ctrlReq( oldaddr, ep, bmREQ_SET, USB_REQUEST_SET_ADDRESS, newaddr, 0x00, 0x0000, 0x0000, 0x0000, NULL, NULL ));
uint8_t USB::setAddr(uint8_t oldaddr, uint8_t ep, uint8_t newaddr) {
return ( ctrlReq(oldaddr, ep, bmREQ_SET, USB_REQUEST_SET_ADDRESS, newaddr, 0x00, 0x0000, 0x0000, 0x0000, NULL, NULL));
}
//set configuration
uint8_t USB::setConf( uint8_t addr, uint8_t ep, uint8_t conf_value )
{
return( ctrlReq( addr, ep, bmREQ_SET, USB_REQUEST_SET_CONFIGURATION, conf_value, 0x00, 0x0000, 0x0000, 0x0000, NULL, NULL ));
uint8_t USB::setConf(uint8_t addr, uint8_t ep, uint8_t conf_value) {
return ( ctrlReq(addr, ep, bmREQ_SET, USB_REQUEST_SET_CONFIGURATION, conf_value, 0x00, 0x0000, 0x0000, 0x0000, NULL, NULL));
}
#endif // defined(USB_METHODS_INLINE)

153
Usb.h
View file

@ -13,7 +13,7 @@ Contact information
Circuits At Home, LTD
Web : http://www.circuitsathome.com
e-mail : support@circuitsathome.com
*/
*/
/* USB functions */
#ifndef _usb_h_
#define _usb_h_
@ -44,28 +44,18 @@ e-mail : support@circuitsathome.com
#include "hexdump.h"
#include "message.h"
extern int UsbDEBUGlvl;
/* shield pins. First parameter - SS pin, second parameter - INT pin */
#if defined(__AVR_AT90USB646__) || defined(__AVR_AT90USB1286__)
#define BOARD_TEENSY_PLUS_PLUS
#endif
#ifdef BOARD_BLACK_WIDDOW
typedef MAX3421e<P6, P3> MAX3421E; // Black Widow
#elif defined(BOARD_TEENSY_PLUS_PLUS)
typedef MAX3421e<P9, P8> MAX3421E; // Teensy++ 2.0 & 1.0
#elif defined(BOARD_MEGA_ADK)
typedef MAX3421e<P53, P54> MAX3421E; // Arduino Mega ADK
#elif defined(BOARD_BALANDUINO)
typedef MAX3421e<P20, P19> MAX3421E; // Balanduino
#else
typedef MAX3421e<P10, P9> MAX3421E; // Official Arduinos (UNO, Duemilanove, Mega, 2560, Leonardo etc.)
typedef MAX3421e<P10, P9> MAX3421E; // Official Arduinos (UNO, Duemilanove, Mega, 2560
#endif
//Debug macros. In 1.0 it is possible to move strings to PROGMEM by defining USBTRACE (Serial.print(F(s)))
#define USBTRACE(s) (Serial.print((s)))
#define USBTRACE2(s,r) (Serial.print((s)), Serial.println((r),HEX))
#define USBTRACE(s) (Notify(PSTR(s), 0x80))
#define USBTRACE2(s,r) (Notify(PSTR(s), 0x80), PrintHex((r), 0x80), Notify(PSTR("\r\n"), 0x80))
@ -113,8 +103,7 @@ typedef MAX3421e<P10, P9> MAX3421E; // Official Arduinos (UNO, Duemilanove, Me
#define USB_ERROR_EP_NOT_FOUND_IN_TBL 0xDB
#define USB_ERROR_TRANSFER_TIMEOUT 0xFF
class USBDeviceConfig
{
class USBDeviceConfig {
public:
virtual uint8_t Init(uint8_t parent, uint8_t port, bool lowspeed) = 0;
virtual uint8_t Release() = 0;
@ -150,134 +139,138 @@ public:
/* USB Setup Packet Structure */
typedef struct {
union { // offset description
uint8_t bmRequestType; // 0 Bit-map of request type
struct {
uint8_t recipient: 5; // Recipient of the request
uint8_t type: 2; // Type of request
uint8_t direction: 1; // Direction of data X-fer
};
}ReqType_u;
uint8_t recipient : 5; // Recipient of the request
uint8_t type : 2; // Type of request
uint8_t direction : 1; // Direction of data X-fer
} __attribute__((packed));
} ReqType_u;
uint8_t bRequest; // 1 Request
union {
uint16_t wValue; // 2 Depends on bRequest
struct {
uint8_t wValueLo;
uint8_t wValueHi;
};
}wVal_u;
} __attribute__((packed));
} wVal_u;
uint16_t wIndex; // 4 Depends on bRequest
uint16_t wLength; // 6 Depends on bRequest
} SETUP_PKT, *PSETUP_PKT;
} SETUP_PKT, *PSETUP_PKT __attribute__((packed));
// Base class for incomming data parser
class USBReadParser
{
class USBReadParser {
public:
virtual void Parse(const uint16_t len, const uint8_t *pbuf, const uint16_t &offset) = 0;
};
class USB : public MAX3421E
{
class USB : public MAX3421E {
AddressPoolImpl<USB_NUMDEVICES> addrPool;
USBDeviceConfig* devConfig[USB_NUMDEVICES];
uint8_t devConfigIndex;
uint8_t bmHubPre;
public:
USB( void );
public:
USB(void);
void SetHubPreMask() { bmHubPre |= bmHUBPRE; };
void ResetHubPreMask() { bmHubPre &= (~bmHUBPRE); };
AddressPool& GetAddressPool()
{
return (AddressPool&)addrPool;
void SetHubPreMask() {
bmHubPre |= bmHUBPRE;
};
uint8_t RegisterDeviceClass(USBDeviceConfig *pdev)
{
for (uint8_t i=0; i<USB_NUMDEVICES; i++)
{
if (!devConfig[i])
{
void ResetHubPreMask() {
bmHubPre &= (~bmHUBPRE);
};
AddressPool& GetAddressPool() {
return(AddressPool&) addrPool;
};
uint8_t RegisterDeviceClass(USBDeviceConfig *pdev) {
for(uint8_t i = 0; i < USB_NUMDEVICES; i++) {
if(!devConfig[i]) {
devConfig[i] = pdev;
return 0;
}
}
return USB_ERROR_UNABLE_TO_REGISTER_DEVICE_CLASS;
};
void ForEachUsbDevice(UsbDeviceHandleFunc pfunc)
{
void ForEachUsbDevice(UsbDeviceHandleFunc pfunc) {
addrPool.ForEachUsbDevice(pfunc);
};
uint8_t getUsbTaskState( void );
void setUsbTaskState( uint8_t state );
uint8_t getUsbTaskState(void);
void setUsbTaskState(uint8_t state);
EpInfo* getEpInfoEntry( uint8_t addr, uint8_t ep );
uint8_t setEpInfoEntry( uint8_t addr, uint8_t epcount, EpInfo* eprecord_ptr );
EpInfo* getEpInfoEntry(uint8_t addr, uint8_t ep);
uint8_t setEpInfoEntry(uint8_t addr, uint8_t epcount, EpInfo* eprecord_ptr);
//uint8_t ctrlReq( uint8_t addr, uint8_t ep, uint8_t bmReqType, uint8_t bRequest, uint8_t wValLo, uint8_t wValHi, uint16_t wInd, uint16_t nbytes, uint8_t* dataptr);
/* Control requests */
uint8_t getDevDescr( uint8_t addr, uint8_t ep, uint16_t nbytes, uint8_t* dataptr );
uint8_t getConfDescr( uint8_t addr, uint8_t ep, uint16_t nbytes, uint8_t conf, uint8_t* dataptr );
uint8_t getDevDescr(uint8_t addr, uint8_t ep, uint16_t nbytes, uint8_t* dataptr);
uint8_t getConfDescr(uint8_t addr, uint8_t ep, uint16_t nbytes, uint8_t conf, uint8_t* dataptr);
uint8_t getConfDescr( uint8_t addr, uint8_t ep, uint8_t conf, USBReadParser *p );
uint8_t getConfDescr(uint8_t addr, uint8_t ep, uint8_t conf, USBReadParser *p);
uint8_t getStrDescr( uint8_t addr, uint8_t ep, uint16_t nbytes, uint8_t index, uint16_t langid, uint8_t* dataptr );
uint8_t setAddr( uint8_t oldaddr, uint8_t ep, uint8_t newaddr );
uint8_t setConf( uint8_t addr, uint8_t ep, uint8_t conf_value );
uint8_t getStrDescr(uint8_t addr, uint8_t ep, uint16_t nbytes, uint8_t index, uint16_t langid, uint8_t* dataptr);
uint8_t setAddr(uint8_t oldaddr, uint8_t ep, uint8_t newaddr);
uint8_t setConf(uint8_t addr, uint8_t ep, uint8_t conf_value);
/**/
uint8_t ctrlData( uint8_t addr, uint8_t ep, uint16_t nbytes, uint8_t* dataptr, boolean direction );
uint8_t ctrlStatus( uint8_t ep, boolean direction, uint16_t nak_limit );
uint8_t inTransfer( uint8_t addr, uint8_t ep, uint16_t *nbytesptr, uint8_t* data );
uint8_t outTransfer( uint8_t addr, uint8_t ep, uint16_t nbytes, uint8_t* data );
uint8_t dispatchPkt( uint8_t token, uint8_t ep, uint16_t nak_limit );
uint8_t ctrlData(uint8_t addr, uint8_t ep, uint16_t nbytes, uint8_t* dataptr, boolean direction);
uint8_t ctrlStatus(uint8_t ep, boolean direction, uint16_t nak_limit);
uint8_t inTransfer(uint8_t addr, uint8_t ep, uint16_t *nbytesptr, uint8_t* data);
uint8_t outTransfer(uint8_t addr, uint8_t ep, uint16_t nbytes, uint8_t* data);
uint8_t dispatchPkt(uint8_t token, uint8_t ep, uint16_t nak_limit);
void Task( void );
void Task(void);
uint8_t DefaultAddressing(uint8_t parent, uint8_t port, bool lowspeed);
uint8_t Configuring(uint8_t parent, uint8_t port, bool lowspeed);
uint8_t ReleaseDevice(uint8_t addr);
uint8_t ctrlReq( uint8_t addr, uint8_t ep, uint8_t bmReqType, uint8_t bRequest, uint8_t wValLo, uint8_t wValHi,
uint8_t ctrlReq(uint8_t addr, uint8_t ep, uint8_t bmReqType, uint8_t bRequest, uint8_t wValLo, uint8_t wValHi,
uint16_t wInd, uint16_t total, uint16_t nbytes, uint8_t* dataptr, USBReadParser *p);
private:
private:
void init();
uint8_t SetAddress(uint8_t addr, uint8_t ep, EpInfo **ppep, uint16_t &nak_limit);
uint8_t OutTransfer(EpInfo *pep, uint16_t nak_limit, uint16_t nbytes, uint8_t *data);
uint8_t InTransfer (EpInfo *pep, uint16_t nak_limit, uint16_t *nbytesptr, uint8_t *data);
uint8_t InTransfer(EpInfo *pep, uint16_t nak_limit, uint16_t *nbytesptr, uint8_t *data);
};
#if 0 //defined(USB_METHODS_INLINE)
//get device descriptor
inline uint8_t USB::getDevDescr( uint8_t addr, uint8_t ep, uint16_t nbytes, uint8_t* dataptr )
{
return( ctrlReq( addr, ep, bmREQ_GET_DESCR, USB_REQUEST_GET_DESCRIPTOR, 0x00, USB_DESCRIPTOR_DEVICE, 0x0000, nbytes, dataptr ));
inline uint8_t USB::getDevDescr(uint8_t addr, uint8_t ep, uint16_t nbytes, uint8_t* dataptr) {
return( ctrlReq(addr, ep, bmREQ_GET_DESCR, USB_REQUEST_GET_DESCRIPTOR, 0x00, USB_DESCRIPTOR_DEVICE, 0x0000, nbytes, dataptr));
}
//get configuration descriptor
inline uint8_t USB::getConfDescr( uint8_t addr, uint8_t ep, uint16_t nbytes, uint8_t conf, uint8_t* dataptr )
{
return( ctrlReq( addr, ep, bmREQ_GET_DESCR, USB_REQUEST_GET_DESCRIPTOR, conf, USB_DESCRIPTOR_CONFIGURATION, 0x0000, nbytes, dataptr ));
inline uint8_t USB::getConfDescr(uint8_t addr, uint8_t ep, uint16_t nbytes, uint8_t conf, uint8_t* dataptr) {
return( ctrlReq(addr, ep, bmREQ_GET_DESCR, USB_REQUEST_GET_DESCRIPTOR, conf, USB_DESCRIPTOR_CONFIGURATION, 0x0000, nbytes, dataptr));
}
//get string descriptor
inline uint8_t USB::getStrDescr( uint8_t addr, uint8_t ep, uint16_t nuint8_ts, uint8_t index, uint16_t langid, uint8_t* dataptr )
{
return( ctrlReq( addr, ep, bmREQ_GET_DESCR, USB_REQUEST_GET_DESCRIPTOR, index, USB_DESCRIPTOR_STRING, langid, nuint8_ts, dataptr ));
inline uint8_t USB::getStrDescr(uint8_t addr, uint8_t ep, uint16_t nuint8_ts, uint8_t index, uint16_t langid, uint8_t* dataptr) {
return( ctrlReq(addr, ep, bmREQ_GET_DESCR, USB_REQUEST_GET_DESCRIPTOR, index, USB_DESCRIPTOR_STRING, langid, nuint8_ts, dataptr));
}
//set address
inline uint8_t USB::setAddr( uint8_t oldaddr, uint8_t ep, uint8_t newaddr )
{
return( ctrlReq( oldaddr, ep, bmREQ_SET, USB_REQUEST_SET_ADDRESS, newaddr, 0x00, 0x0000, 0x0000, NULL ));
inline uint8_t USB::setAddr(uint8_t oldaddr, uint8_t ep, uint8_t newaddr) {
return( ctrlReq(oldaddr, ep, bmREQ_SET, USB_REQUEST_SET_ADDRESS, newaddr, 0x00, 0x0000, 0x0000, NULL));
}
//set configuration
inline uint8_t USB::setConf( uint8_t addr, uint8_t ep, uint8_t conf_value )
{
return( ctrlReq( addr, ep, bmREQ_SET, USB_REQUEST_SET_CONFIGURATION, conf_value, 0x00, 0x0000, 0x0000, NULL ));
inline uint8_t USB::setConf(uint8_t addr, uint8_t ep, uint8_t conf_value) {
return( ctrlReq(addr, ep, bmREQ_SET, USB_REQUEST_SET_CONFIGURATION, conf_value, 0x00, 0x0000, 0x0000, NULL));
}
#endif // defined(USB_METHODS_INLINE)

577
Wii.cpp

File diff suppressed because it is too large Load diff

89
Wii.h
View file

@ -101,7 +101,7 @@ public:
* @param pair Set this to true in order to pair with the Wiimote. If the argument is omitted then it won't pair with it.
* One can use ::PAIR to set it to true.
*/
WII(BTD *p, bool pair=false);
WII(BTD *p, bool pair = false);
/** @name BluetoothService implementation */
/**
@ -148,19 +148,27 @@ public:
* Pitch calculated from the Wiimote. A complimentary filter is used if the Motion Plus is connected.
* @return Pitch in the range from 0-360.
*/
double getPitch() { return pitch; };
double getPitch() {
return pitch;
};
/**
* Roll calculated from the Wiimote. A complimentary filter is used if the Motion Plus is connected.
* @return Roll in the range from 0-360.
*/
double getRoll() { return roll; };
double getRoll() {
return roll;
};
/**
* This is the yaw calculated by the gyro.
*
* <B>NOTE:</B> This angle will drift a lot and is only available if the Motion Plus extension is connected.
* @return The angle calculated using the gyro.
*/
double getYaw() { return gyroYaw; };
double getYaw() {
return gyroYaw;
};
/** Used to set all LEDs and rumble off. */
void setAllOff();
@ -200,12 +208,17 @@ public:
* Return the battery level of the Wiimote.
* @return The battery level in the range 0-255.
*/
uint8_t getBatteryLevel() { return batteryLevel; };
uint8_t getBatteryLevel() {
return batteryLevel;
};
/**
* Return the Wiimote state.
* @return See: http://wiibrew.org/wiki/Wiimote#0x20:_Status.
*/
uint8_t getWiiState() { return wiiState; };
uint8_t getWiiState() {
return wiiState;
};
/**@}*/
/**@{*/
@ -287,72 +300,106 @@ public:
* IR object 1 x-position read from the Wii IR camera.
* @return The x-position of the object in the range 0-1023.
*/
uint16_t getIRx1() { return IR_object_x1; };
uint16_t getIRx1() {
return IR_object_x1;
};
/**
* IR object 1 y-position read from the Wii IR camera.
* @return The y-position of the object in the range 0-767.
*/
uint16_t getIRy1() { return IR_object_y1; };
uint16_t getIRy1() {
return IR_object_y1;
};
/**
* IR object 1 size read from the Wii IR camera.
* @return The size of the object in the range 0-15.
*/
uint8_t getIRs1() { return IR_object_s1; };
uint8_t getIRs1() {
return IR_object_s1;
};
/**
* IR object 2 x-position read from the Wii IR camera.
* @return The x-position of the object in the range 0-1023.
*/
uint16_t getIRx2() { return IR_object_x2; };
uint16_t getIRx2() {
return IR_object_x2;
};
/**
* IR object 2 y-position read from the Wii IR camera.
* @return The y-position of the object in the range 0-767.
*/
uint16_t getIRy2() { return IR_object_y2; };
uint16_t getIRy2() {
return IR_object_y2;
};
/**
* IR object 2 size read from the Wii IR camera.
* @return The size of the object in the range 0-15.
*/
uint8_t getIRs2() { return IR_object_s2; };
uint8_t getIRs2() {
return IR_object_s2;
};
/**
* IR object 3 x-position read from the Wii IR camera.
* @return The x-position of the object in the range 0-1023.
*/
uint16_t getIRx3() { return IR_object_x3; };
uint16_t getIRx3() {
return IR_object_x3;
};
/**
* IR object 3 y-position read from the Wii IR camera.
* @return The y-position of the object in the range 0-767.
*/
uint16_t getIRy3() { return IR_object_y3; };
uint16_t getIRy3() {
return IR_object_y3;
};
/**
* IR object 3 size read from the Wii IR camera.
* @return The size of the object in the range 0-15.
*/
uint8_t getIRs3() { return IR_object_s3; };
uint8_t getIRs3() {
return IR_object_s3;
};
/**
* IR object 4 x-position read from the Wii IR camera.
* @return The x-position of the object in the range 0-1023.
*/
uint16_t getIRx4() { return IR_object_x4; };
uint16_t getIRx4() {
return IR_object_x4;
};
/**
* IR object 4 y-position read from the Wii IR camera.
* @return The y-position of the object in the range 0-767.
*/
uint16_t getIRy4() { return IR_object_y4; };
uint16_t getIRy4() {
return IR_object_y4;
};
/**
* IR object 4 size read from the Wii IR camera.
* @return The size of the object in the range 0-15.
*/
uint8_t getIRs4() { return IR_object_s4; };
uint8_t getIRs4() {
return IR_object_s4;
};
/**
* Use this to check if the camera is enabled or not.
* If not call WII#IRinitialize to initialize the IR camera.
* @return True if it's enabled, false if not.
*/
bool isIRCameraEnabled() { return (wiiState & 0x08); };
bool isIRCameraEnabled() {
return(wiiState & 0x08);
};
/**@}*/
#endif
@ -368,14 +415,14 @@ private:
/* variables used by high level L2CAP task */
uint8_t l2cap_state;
uint16_t l2cap_event_flag;// l2cap flags of received bluetooth events
uint16_t l2cap_event_flag; // l2cap flags of received bluetooth events
uint32_t ButtonState;
uint32_t OldButtonState;
uint32_t ButtonClickState;
uint16_t hatValues[4];
uint8_t HIDBuffer[3];// Used to store HID commands
uint8_t HIDBuffer[3]; // Used to store HID commands
uint16_t stateCounter;
bool unknownExtensionConnected;

View file

@ -22,11 +22,11 @@
//#define EXTRADEBUG // Uncomment to get even more debugging data
//#define PRINTREPORT // Uncomment to print the report send by the Xbox 360 Controller
XBOXRECV::XBOXRECV(USB *p):
XBOXRECV::XBOXRECV(USB *p) :
pUsb(p), // pointer to USB class instance - mandatory
bAddress(0), // device address - mandatory
bPollEnable(false) { // don't start polling before dongle is connected
for(uint8_t i=0; i<XBOX_MAX_ENDPOINTS; i++) {
for (uint8_t i = 0; i < XBOX_MAX_ENDPOINTS; i++) {
epInfo[i].epAddr = 0;
epInfo[i].maxPktSize = (i) ? 0 : 8;
epInfo[i].epAttribs = 0;
@ -38,7 +38,7 @@ bPollEnable(false) { // don't start polling before dongle is connected
}
uint8_t XBOXRECV::Init(uint8_t parent, uint8_t port, bool lowspeed) {
uint8_t buf[sizeof(USB_DEVICE_DESCRIPTOR)];
uint8_t buf[sizeof (USB_DEVICE_DESCRIPTOR)];
uint8_t rcode;
UsbDevice *p = NULL;
EpInfo *oldep_ptr = NULL;
@ -48,12 +48,12 @@ uint8_t XBOXRECV::Init(uint8_t parent, uint8_t port, bool lowspeed) {
// get memory address of USB device address pool
AddressPool &addrPool = pUsb->GetAddressPool();
#ifdef EXTRADEBUG
Notify(PSTR("\r\nXBOXRECV Init"));
Notify(PSTR("\r\nXBOXRECV Init"), 0x80);
#endif
// check if address has already been assigned to an instance
if (bAddress) {
#ifdef DEBUG
Notify(PSTR("\r\nAddress in use"));
Notify(PSTR("\r\nAddress in use"), 0x80);
#endif
return USB_ERROR_CLASS_INSTANCE_ALREADY_IN_USE;
}
@ -63,14 +63,14 @@ uint8_t XBOXRECV::Init(uint8_t parent, uint8_t port, bool lowspeed) {
if (!p) {
#ifdef DEBUG
Notify(PSTR("\r\nAddress not found"));
Notify(PSTR("\r\nAddress not found"), 0x80);
#endif
return USB_ERROR_ADDRESS_NOT_FOUND_IN_POOL;
}
if (!p->epinfo) {
#ifdef DEBUG
Notify(PSTR("\r\nepinfo is null"));
Notify(PSTR("\r\nepinfo is null"), 0x80);
#endif
return USB_ERROR_EPINFO_IS_NULL;
}
@ -84,21 +84,21 @@ uint8_t XBOXRECV::Init(uint8_t parent, uint8_t port, bool lowspeed) {
p->lowspeed = lowspeed;
// Get device descriptor
rcode = pUsb->getDevDescr(0, 0, sizeof(USB_DEVICE_DESCRIPTOR), (uint8_t*)buf);// Get device descriptor - addr, ep, nbytes, data
rcode = pUsb->getDevDescr(0, 0, sizeof (USB_DEVICE_DESCRIPTOR), (uint8_t*)buf); // Get device descriptor - addr, ep, nbytes, data
// Restore p->epinfo
p->epinfo = oldep_ptr;
if(rcode)
if (rcode)
goto FailGetDevDescr;
VID = ((USB_DEVICE_DESCRIPTOR*)buf)->idVendor;
PID = ((USB_DEVICE_DESCRIPTOR*)buf)->idProduct;
if(VID != XBOX_VID && VID != MADCATZ_VID) // We just check if it's a xbox receiver using the Vendor ID
if (VID != XBOX_VID && VID != MADCATZ_VID) // We just check if it's a xbox receiver using the Vendor ID
goto FailUnknownDevice;
else if(PID != XBOX_WIRELESS_RECEIVER_PID && PID != XBOX_WIRELESS_RECEIVER_THIRD_PARTY_PID) {
else if (PID != XBOX_WIRELESS_RECEIVER_PID && PID != XBOX_WIRELESS_RECEIVER_THIRD_PARTY_PID) {
#ifdef DEBUG
Notify(PSTR("\r\nYou'll need a wireless receiver for this libary to work"));
Notify(PSTR("\r\nYou'll need a wireless receiver for this libary to work"), 0x80);
#endif
goto FailUnknownDevice;
}
@ -113,20 +113,20 @@ uint8_t XBOXRECV::Init(uint8_t parent, uint8_t port, bool lowspeed) {
epInfo[0].maxPktSize = (uint8_t)((USB_DEVICE_DESCRIPTOR*)buf)->bMaxPacketSize0;
// Assign new address to the device
rcode = pUsb->setAddr( 0, 0, bAddress );
rcode = pUsb->setAddr(0, 0, bAddress);
if (rcode) {
p->lowspeed = false;
addrPool.FreeAddress(bAddress);
bAddress = 0;
#ifdef DEBUG
Notify(PSTR("\r\nsetAddr: "));
Notify(PSTR("\r\nsetAddr: "), 0x80);
#endif
PrintHex<uint8_t>(rcode);
PrintHex<uint8_t > (rcode, 0x80);
return rcode;
}
#ifdef EXTRADEBUG
Notify(PSTR("\r\nAddr: "));
PrintHex<uint8_t>(bAddress);
Notify(PSTR("\r\nAddr: "), 0x80);
PrintHex<uint8_t > (bAddress, 0x80);
#endif
p->lowspeed = false;
@ -200,17 +200,17 @@ uint8_t XBOXRECV::Init(uint8_t parent, uint8_t port, bool lowspeed) {
epInfo[ XBOX_OUTPUT_PIPE_4 ].bmRcvToggle = bmRCVTOG0;
rcode = pUsb->setEpInfoEntry(bAddress, 9, epInfo);
if( rcode )
if (rcode)
goto FailSetDevTblEntry;
delay(200);//Give time for address change
delay(200); //Give time for address change
rcode = pUsb->setConf(bAddress, epInfo[ XBOX_CONTROL_PIPE ].epAddr, 1);
if( rcode )
if (rcode)
goto FailSetConf;
#ifdef DEBUG
Notify(PSTR("\r\nXbox Wireless Receiver Connected\r\n"));
Notify(PSTR("\r\nXbox Wireless Receiver Connected\r\n"), 0x80);
#endif
XboxReceiverConnected = true;
bPollEnable = true;
@ -219,32 +219,32 @@ uint8_t XBOXRECV::Init(uint8_t parent, uint8_t port, bool lowspeed) {
/* diagnostic messages */
FailGetDevDescr:
#ifdef DEBUG
Notify(PSTR("\r\ngetDevDescr:"));
Notify(PSTR("\r\ngetDevDescr:"), 0x80);
#endif
goto Fail;
FailSetDevTblEntry:
#ifdef DEBUG
Notify(PSTR("\r\nsetDevTblEn:"));
Notify(PSTR("\r\nsetDevTblEn:"), 0x80);
#endif
goto Fail;
FailSetConf:
#ifdef DEBUG
Notify(PSTR("\r\nsetConf:"));
Notify(PSTR("\r\nsetConf:"), 0x80);
#endif
goto Fail;
FailUnknownDevice:
#ifdef DEBUG
Notify(PSTR("\r\nUnknown Device Connected - VID: "));
PrintHex<uint16_t>(VID);
Notify(PSTR(" PID: "));
PrintHex<uint16_t>(PID);
Notify(PSTR("\r\nUnknown Device Connected - VID: "), 0x80);
PrintHex<uint16_t > (VID, 0x80);
Notify(PSTR(" PID: "), 0x80);
PrintHex<uint16_t > (PID, 0x80);
#endif
rcode = USB_DEV_CONFIG_ERROR_DEVICE_NOT_SUPPORTED;
goto Fail;
Fail:
#ifdef DEBUG
Notify(PSTR("\r\nXbox 360 Init Failed, error code: "));
Serial.print(rcode,HEX);
Notify(PSTR("\r\nXbox 360 Init Failed, error code: "), 0x80);
Serial.print(rcode, HEX);
#endif
Release();
return rcode;
@ -253,40 +253,45 @@ Fail:
/* Performs a cleanup after failed Init() attempt */
uint8_t XBOXRECV::Release() {
XboxReceiverConnected = false;
for(uint8_t i=0;i<4;i++)
for (uint8_t i = 0; i < 4; i++)
Xbox360Connected[i] = 0x00;
pUsb->GetAddressPool().FreeAddress(bAddress);
bAddress = 0;
bPollEnable = false;
return 0;
}
uint8_t XBOXRECV::Poll() {
if (!bPollEnable)
return 0;
if(!timer || ((millis() - timer) > 3000)) { // Run checkStatus every 3 seconds
if (!timer || ((millis() - timer) > 3000)) { // Run checkStatus every 3 seconds
timer = millis();
checkStatus();
}
uint8_t inputPipe;
uint16_t bufferSize;
for(uint8_t i=0;i<4;i++) {
for (uint8_t i = 0; i < 4; i++) {
switch (i) {
case 0: inputPipe = XBOX_INPUT_PIPE_1; break;
case 1: inputPipe = XBOX_INPUT_PIPE_2; break;
case 2: inputPipe = XBOX_INPUT_PIPE_3; break;
case 3: inputPipe = XBOX_INPUT_PIPE_4; break;
case 0: inputPipe = XBOX_INPUT_PIPE_1;
break;
case 1: inputPipe = XBOX_INPUT_PIPE_2;
break;
case 2: inputPipe = XBOX_INPUT_PIPE_3;
break;
case 3: inputPipe = XBOX_INPUT_PIPE_4;
break;
}
bufferSize = EP_MAXPKTSIZE; // This is the maximum number of bytes we want to receive
pUsb->inTransfer(bAddress, epInfo[ inputPipe ].epAddr, &bufferSize, readBuf);
if(bufferSize > 0) { // The number of received bytes
if (bufferSize > 0) { // The number of received bytes
#ifdef EXTRADEBUG
Notify(PSTR("Bytes Received: "));
Notify(PSTR("Bytes Received: "), 0x80);
Serial.print(bufferSize);
Notify(PSTR("\r\n"));
Notify(PSTR("\r\n"), 0x80);
#endif
readReport(i);
#ifdef PRINTREPORT
printReport(i,bufferSize); // Uncomment "#define PRINTREPORT" to print the report send by the Xbox 360 Controller
printReport(i, bufferSize); // Uncomment "#define PRINTREPORT" to print the report send by the Xbox 360 Controller
#endif
}
}
@ -297,48 +302,55 @@ void XBOXRECV::readReport(uint8_t controller) {
if (readBuf == NULL)
return;
// This report is send when a controller is connected and disconnected
if(readBuf[0] == 0x08 && readBuf[1] != Xbox360Connected[controller]) {
if (readBuf[0] == 0x08 && readBuf[1] != Xbox360Connected[controller]) {
Xbox360Connected[controller] = readBuf[1];
#ifdef DEBUG
Notify(PSTR("Controller "));
Notify(PSTR("Controller "), 0x80);
Serial.print(controller);
#endif
if(Xbox360Connected[controller]) {
if (Xbox360Connected[controller]) {
#ifdef DEBUG
char* str = 0;
switch(readBuf[1]) {
case 0x80: str = PSTR(" as controller\r\n"); break;
case 0x40: str = PSTR(" as headset\r\n"); break;
case 0xC0: str = PSTR(" as controller+headset\r\n"); break;
switch (readBuf[1]) {
case 0x80: str = PSTR(" as controller\r\n");
break;
case 0x40: str = PSTR(" as headset\r\n");
break;
case 0xC0: str = PSTR(" as controller+headset\r\n");
break;
}
Notify(PSTR(": connected"));
Notify(str);
Notify(PSTR(": connected"), 0x80);
Notify(str, 0x80);
#endif
LED led;
switch (controller) {
case 0: led = LED1; break;
case 1: led = LED2; break;
case 2: led = LED3; break;
case 3: led = LED4; break;
case 0: led = LED1;
break;
case 1: led = LED2;
break;
case 2: led = LED3;
break;
case 3: led = LED4;
break;
}
setLedOn(controller,led);
setLedOn(controller, led);
}
#ifdef DEBUG
else
Notify(PSTR(": disconnected\r\n"));
Notify(PSTR(": disconnected\r\n"), 0x80);
#endif
return;
}
// Controller status report
if(readBuf[1] == 0x00 && readBuf[3] & 0x13 && readBuf[4] >= 0x22) {
if (readBuf[1] == 0x00 && readBuf[3] & 0x13 && readBuf[4] >= 0x22) {
controllerStatus[controller] = ((uint16_t)readBuf[3] << 8) | readBuf[4];
return;
}
if(readBuf[1] != 0x01) // Check if it's the correct report - the receiver also sends different status reports
if (readBuf[1] != 0x01) // Check if it's the correct report - the receiver also sends different status reports
return;
// A controller must be connected if it's sending data
if(!Xbox360Connected[controller])
if (!Xbox360Connected[controller])
Xbox360Connected[controller] |= 0x80;
ButtonState[controller] = (uint32_t)(readBuf[9] | ((uint16_t)readBuf[8] << 8) | ((uint32_t)readBuf[7] << 16) | ((uint32_t)readBuf[6] << 24));
@ -348,15 +360,15 @@ void XBOXRECV::readReport(uint8_t controller) {
hatValue[controller][RightHatX] = (int16_t)(((uint16_t)readBuf[15] << 8) | readBuf[14]);
hatValue[controller][RightHatY] = (int16_t)(((uint16_t)readBuf[17] << 8) | readBuf[16]);
//Notify(PSTR("\r\nButtonState: "));
//PrintHex<uint32_t>(ButtonState[controller]);
//Notify(PSTR("\r\nButtonState: "), 0x80);
//PrintHex<uint32_t>(ButtonState[controller], 0x80);
if(ButtonState[controller] != OldButtonState[controller]) {
if (ButtonState[controller] != OldButtonState[controller]) {
buttonStateChanged[controller] = true;
ButtonClickState[controller] = (ButtonState[controller] >> 16) & ((~OldButtonState[controller]) >> 16); // Update click state variable, but don't include the two trigger buttons L2 and R2
if(((uint8_t)OldButtonState[controller]) == 0 && ((uint8_t)ButtonState[controller]) != 0) // The L2 and R2 buttons are special as they are analog buttons
if (((uint8_t)OldButtonState[controller]) == 0 && ((uint8_t)ButtonState[controller]) != 0) // The L2 and R2 buttons are special as they are analog buttons
R2Clicked[controller] = true;
if((uint8_t)(OldButtonState[controller] >> 8) == 0 && (uint8_t)(ButtonState[controller] >> 8) != 0)
if ((uint8_t)(OldButtonState[controller] >> 8) == 0 && (uint8_t)(ButtonState[controller] >> 8) != 0)
L2Clicked[controller] = true;
OldButtonState[controller] = ButtonState[controller];
}
@ -366,33 +378,34 @@ void XBOXRECV::printReport(uint8_t controller, uint8_t nBytes) { //Uncomment "#d
#ifdef PRINTREPORT
if (readBuf == NULL)
return;
Notify(PSTR("Controller "));
Notify(PSTR("Controller "), 0x80);
Serial.print(controller);
Notify(PSTR(": "));
for(uint8_t i = 0; i < nBytes;i++) {
PrintHex<uint8_t>(readBuf[i]);
Notify(PSTR(": "), 0x80);
for (uint8_t i = 0; i < nBytes; i++) {
PrintHex<uint8_t > (readBuf[i], 0x80);
Serial.print(" ");
}
Serial.println();
#endif
}
uint8_t XBOXRECV::getButtonPress(uint8_t controller, Button b) {
if(b == L2) // These are analog buttons
if (b == L2) // These are analog buttons
return (uint8_t)(ButtonState[controller] >> 8);
else if(b == R2)
else if (b == R2)
return (uint8_t)ButtonState[controller];
return (ButtonState[controller] & ((uint32_t)pgm_read_word(&XBOXBUTTONS[(uint8_t)b]) << 16));
}
bool XBOXRECV::getButtonClick(uint8_t controller, Button b) {
if(b == L2) {
if(L2Clicked[controller]) {
if (b == L2) {
if (L2Clicked[controller]) {
L2Clicked[controller] = false;
return true;
}
return false;
}
else if(b == R2) {
if(R2Clicked[controller]) {
} else if (b == R2) {
if (R2Clicked[controller]) {
R2Clicked[controller] = false;
return true;
}
@ -403,14 +416,17 @@ bool XBOXRECV::getButtonClick(uint8_t controller, Button b) {
ButtonClickState[controller] &= ~button; // clear "click" event
return click;
}
int16_t XBOXRECV::getAnalogHat(uint8_t controller, AnalogHat a) {
return hatValue[controller][a];
}
bool XBOXRECV::buttonChanged(uint8_t controller) {
bool state = buttonStateChanged[controller];
buttonStateChanged[controller] = false;
return state;
}
/*
ControllerStatus Breakdown
ControllerStatus[controller] & 0x0001 // 0
@ -429,10 +445,10 @@ ControllerStatus Breakdown
ControllerStatus[controller] & 0x2000 // 0
ControllerStatus[controller] & 0x4000 // 0
ControllerStatus[controller] & 0x8000 // 0
*/
*/
uint8_t XBOXRECV::getBatteryLevel(uint8_t controller) {
uint8_t batteryLevel = ((controllerStatus[controller] & 0x00C0) >> 6) * 33;
if(batteryLevel == 99)
if (batteryLevel == 99)
batteryLevel = 100;
return batteryLevel;
}
@ -441,17 +457,22 @@ void XBOXRECV::XboxCommand(uint8_t controller, uint8_t* data, uint16_t nbytes) {
uint8_t rcode;
uint8_t outputPipe;
switch (controller) {
case 0: outputPipe = XBOX_OUTPUT_PIPE_1; break;
case 1: outputPipe = XBOX_OUTPUT_PIPE_2; break;
case 2: outputPipe = XBOX_OUTPUT_PIPE_3; break;
case 3: outputPipe = XBOX_OUTPUT_PIPE_4; break;
case 0: outputPipe = XBOX_OUTPUT_PIPE_1;
break;
case 1: outputPipe = XBOX_OUTPUT_PIPE_2;
break;
case 2: outputPipe = XBOX_OUTPUT_PIPE_3;
break;
case 3: outputPipe = XBOX_OUTPUT_PIPE_4;
break;
}
rcode = pUsb->outTransfer(bAddress, epInfo[ outputPipe ].epAddr, nbytes, data);
#ifdef EXTRADEBUG
if(rcode)
Notify(PSTR("Error sending Xbox message\r\n"));
if (rcode)
Notify(PSTR("Error sending Xbox message\r\n"), 0x80);
#endif
}
void XBOXRECV::setLedRaw(uint8_t controller, uint8_t value) {
writeBuf[0] = 0x00;
writeBuf[1] = 0x00;
@ -460,29 +481,33 @@ void XBOXRECV::setLedRaw(uint8_t controller, uint8_t value) {
XboxCommand(controller, writeBuf, 4);
}
void XBOXRECV::setLedOn(uint8_t controller, LED led) {
if(led != ALL) // All LEDs can't be on a the same time
setLedRaw(controller,(pgm_read_byte(&XBOXLEDS[(uint8_t)led]))+4);
if (led != ALL) // All LEDs can't be on a the same time
setLedRaw(controller, (pgm_read_byte(&XBOXLEDS[(uint8_t)led])) + 4);
}
void XBOXRECV::setLedBlink(uint8_t controller, LED led) {
setLedRaw(controller,pgm_read_byte(&XBOXLEDS[(uint8_t)led]));
setLedRaw(controller, pgm_read_byte(&XBOXLEDS[(uint8_t)led]));
}
void XBOXRECV::setLedMode(uint8_t controller, LEDMode ledMode) { // This function is used to do some speciel LED stuff the controller supports
setLedRaw(controller,(uint8_t)ledMode);
setLedRaw(controller, (uint8_t)ledMode);
}
/* PC runs this at interval of approx 2 seconds
Thanks to BusHound from Perisoft.net for the Windows USB Analysis output
Found by timstamp.co.uk
*/
*/
void XBOXRECV::checkStatus() {
if(!bPollEnable)
if (!bPollEnable)
return;
// Get controller info
writeBuf[0] = 0x08;
writeBuf[1] = 0x00;
writeBuf[2] = 0x0f;
writeBuf[3] = 0xc0;
for(uint8_t i=0; i<4; i++) {
for (uint8_t i = 0; i < 4; i++) {
XboxCommand(i, writeBuf, 4);
}
// Get battery status
@ -490,8 +515,8 @@ void XBOXRECV::checkStatus() {
writeBuf[1] = 0x00;
writeBuf[2] = 0x00;
writeBuf[3] = 0x40;
for(uint8_t i=0; i<4; i++) {
if(Xbox360Connected[i])
for (uint8_t i = 0; i < 4; i++) {
if (Xbox360Connected[i])
XboxCommand(i, writeBuf, 4);
}
}

View file

@ -87,16 +87,22 @@ public:
* @return 0 on success.
*/
virtual uint8_t Poll();
/**
* Get the device address.
* @return The device address.
*/
virtual uint8_t GetAddress() { return bAddress; };
virtual uint8_t GetAddress() {
return bAddress;
};
/**
* Used to check if the controller has been initialized.
* @return True if it's ready.
*/
virtual bool isReady() { return bPollEnable; };
virtual bool isReady() {
return bPollEnable;
};
/**@}*/
/** @name Xbox Controller functions */
@ -124,16 +130,23 @@ public:
* @return Returns a signed 16-bit integer.
*/
int16_t getAnalogHat(uint8_t controller, AnalogHat a);
/**
* Turn rumble off and all the LEDs on the specific controller.
* @param controller The controller to write to.
*/
void setAllOff(uint8_t controller) { setRumbleOn(controller,0,0); setLedOff(controller); };
void setAllOff(uint8_t controller) {
setRumbleOn(controller, 0, 0);
setLedOff(controller);
};
/**
* Turn rumble off the specific controller.
* @param controller The controller to write to.
*/
void setRumbleOff(uint8_t controller) { setRumbleOn(controller,0,0); };
void setRumbleOff(uint8_t controller) {
setRumbleOn(controller, 0, 0);
};
/**
* Turn rumble on.
* @param controller The controller to write to.
@ -149,11 +162,14 @@ public:
* setLedBlink(uint8_t controller, LED l), and setLedMode(uint8_t controller, LEDMode lm).
*/
void setLedRaw(uint8_t controller, uint8_t value);
/**
* Turn all LEDs off the specific controller.
* @param controller The controller to write to.
*/
void setLedOff(uint8_t controller) { setLedRaw(controller,0); };
void setLedOff(uint8_t controller) {
setLedRaw(controller, 0);
};
/**
* Turn on a LED by using the ::LED enum.
* @param controller The controller to write to.

View file

@ -20,11 +20,11 @@
//#define EXTRADEBUG // Uncomment to get even more debugging data
//#define PRINTREPORT // Uncomment to print the report send by the Xbox 360 Controller
XBOXUSB::XBOXUSB(USB *p):
XBOXUSB::XBOXUSB(USB *p) :
pUsb(p), // pointer to USB class instance - mandatory
bAddress(0), // device address - mandatory
bPollEnable(false) { // don't start polling before dongle is connected
for(uint8_t i=0; i<XBOX_MAX_ENDPOINTS; i++) {
for (uint8_t i = 0; i < XBOX_MAX_ENDPOINTS; i++) {
epInfo[i].epAddr = 0;
epInfo[i].maxPktSize = (i) ? 0 : 8;
epInfo[i].epAttribs = 0;
@ -36,7 +36,7 @@ bPollEnable(false) { // don't start polling before dongle is connected
}
uint8_t XBOXUSB::Init(uint8_t parent, uint8_t port, bool lowspeed) {
uint8_t buf[sizeof(USB_DEVICE_DESCRIPTOR)];
uint8_t buf[sizeof (USB_DEVICE_DESCRIPTOR)];
uint8_t rcode;
UsbDevice *p = NULL;
EpInfo *oldep_ptr = NULL;
@ -46,12 +46,12 @@ uint8_t XBOXUSB::Init(uint8_t parent, uint8_t port, bool lowspeed) {
// get memory address of USB device address pool
AddressPool &addrPool = pUsb->GetAddressPool();
#ifdef EXTRADEBUG
Notify(PSTR("\r\nXBOXUSB Init"));
Notify(PSTR("\r\nXBOXUSB Init"), 0x80);
#endif
// check if address has already been assigned to an instance
if (bAddress) {
#ifdef DEBUG
Notify(PSTR("\r\nAddress in use"));
Notify(PSTR("\r\nAddress in use"), 0x80);
#endif
return USB_ERROR_CLASS_INSTANCE_ALREADY_IN_USE;
}
@ -61,14 +61,14 @@ uint8_t XBOXUSB::Init(uint8_t parent, uint8_t port, bool lowspeed) {
if (!p) {
#ifdef DEBUG
Notify(PSTR("\r\nAddress not found"));
Notify(PSTR("\r\nAddress not found"), 0x80);
#endif
return USB_ERROR_ADDRESS_NOT_FOUND_IN_POOL;
}
if (!p->epinfo) {
#ifdef DEBUG
Notify(PSTR("\r\nepinfo is null"));
Notify(PSTR("\r\nepinfo is null"), 0x80);
#endif
return USB_ERROR_EPINFO_IS_NULL;
}
@ -82,27 +82,26 @@ uint8_t XBOXUSB::Init(uint8_t parent, uint8_t port, bool lowspeed) {
p->lowspeed = lowspeed;
// Get device descriptor
rcode = pUsb->getDevDescr(0, 0, sizeof(USB_DEVICE_DESCRIPTOR), (uint8_t*)buf);// Get device descriptor - addr, ep, nbytes, data
rcode = pUsb->getDevDescr(0, 0, sizeof (USB_DEVICE_DESCRIPTOR), (uint8_t*)buf); // Get device descriptor - addr, ep, nbytes, data
// Restore p->epinfo
p->epinfo = oldep_ptr;
if(rcode)
if (rcode)
goto FailGetDevDescr;
VID = ((USB_DEVICE_DESCRIPTOR*)buf)->idVendor;
PID = ((USB_DEVICE_DESCRIPTOR*)buf)->idProduct;
if(VID != XBOX_VID && VID != MADCATZ_VID && VID != JOYTECH_VID) // We just check if it's a xbox controller using the Vendor ID
if (VID != XBOX_VID && VID != MADCATZ_VID && VID != JOYTECH_VID) // We just check if it's a xbox controller using the Vendor ID
goto FailUnknownDevice;
if(PID == XBOX_WIRELESS_PID) {
if (PID == XBOX_WIRELESS_PID) {
#ifdef DEBUG
Notify(PSTR("\r\nYou have plugged in a wireless Xbox 360 controller - it doesn't support USB communication"));
Notify(PSTR("\r\nYou have plugged in a wireless Xbox 360 controller - it doesn't support USB communication"), 0x80);
#endif
goto FailUnknownDevice;
}
else if(PID == XBOX_WIRELESS_RECEIVER_PID || PID == XBOX_WIRELESS_RECEIVER_THIRD_PARTY_PID) {
} else if (PID == XBOX_WIRELESS_RECEIVER_PID || PID == XBOX_WIRELESS_RECEIVER_THIRD_PARTY_PID) {
#ifdef DEBUG
Notify(PSTR("\r\nThis library only supports Xbox 360 controllers via USB"));
Notify(PSTR("\r\nThis library only supports Xbox 360 controllers via USB"), 0x80);
#endif
goto FailUnknownDevice;
}
@ -117,20 +116,20 @@ uint8_t XBOXUSB::Init(uint8_t parent, uint8_t port, bool lowspeed) {
epInfo[0].maxPktSize = (uint8_t)((USB_DEVICE_DESCRIPTOR*)buf)->bMaxPacketSize0;
// Assign new address to the device
rcode = pUsb->setAddr( 0, 0, bAddress );
rcode = pUsb->setAddr(0, 0, bAddress);
if (rcode) {
p->lowspeed = false;
addrPool.FreeAddress(bAddress);
bAddress = 0;
#ifdef DEBUG
Notify(PSTR("\r\nsetAddr: "));
Notify(PSTR("\r\nsetAddr: "), 0x80);
#endif
PrintHex<uint8_t>(rcode);
PrintHex<uint8_t > (rcode, 0x80);
return rcode;
}
#ifdef EXTRADEBUG
Notify(PSTR("\r\nAddr: "));
PrintHex<uint8_t>(bAddress);
Notify(PSTR("\r\nAddr: "), 0x80);
PrintHex<uint8_t > (bAddress, 0x80);
#endif
p->lowspeed = false;
@ -165,17 +164,17 @@ uint8_t XBOXUSB::Init(uint8_t parent, uint8_t port, bool lowspeed) {
epInfo[ XBOX_OUTPUT_PIPE ].bmRcvToggle = bmRCVTOG0;
rcode = pUsb->setEpInfoEntry(bAddress, 3, epInfo);
if( rcode )
if (rcode)
goto FailSetDevTblEntry;
delay(200);//Give time for address change
delay(200); //Give time for address change
rcode = pUsb->setConf(bAddress, epInfo[ XBOX_CONTROL_PIPE ].epAddr, 1);
if( rcode )
if (rcode)
goto FailSetConf;
#ifdef DEBUG
Notify(PSTR("\r\nXbox 360 Controller Connected\r\n"));
Notify(PSTR("\r\nXbox 360 Controller Connected\r\n"), 0x80);
#endif
setLedOn(LED1);
Xbox360Connected = true;
@ -185,32 +184,32 @@ uint8_t XBOXUSB::Init(uint8_t parent, uint8_t port, bool lowspeed) {
/* diagnostic messages */
FailGetDevDescr:
#ifdef DEBUG
Notify(PSTR("\r\ngetDevDescr:"));
Notify(PSTR("\r\ngetDevDescr:"), 0x80);
#endif
goto Fail;
FailSetDevTblEntry:
#ifdef DEBUG
Notify(PSTR("\r\nsetDevTblEn:"));
Notify(PSTR("\r\nsetDevTblEn:"), 0x80);
#endif
goto Fail;
FailSetConf:
#ifdef DEBUG
Notify(PSTR("\r\nsetConf:"));
Notify(PSTR("\r\nsetConf:"), 0x80);
#endif
goto Fail;
FailUnknownDevice:
#ifdef DEBUG
Notify(PSTR("\r\nUnknown Device Connected - VID: "));
PrintHex<uint16_t>(VID);
Notify(PSTR(" PID: "));
PrintHex<uint16_t>(PID);
Notify(PSTR("\r\nUnknown Device Connected - VID: "), 0x80);
PrintHex<uint16_t > (VID, 0x80);
Notify(PSTR(" PID: "), 0x80);
PrintHex<uint16_t > (PID, 0x80);
#endif
rcode = USB_DEV_CONFIG_ERROR_DEVICE_NOT_SUPPORTED;
goto Fail;
Fail:
#ifdef DEBUG
Notify(PSTR("\r\nXbox 360 Init Failed, error code: "));
Serial.print(rcode,HEX);
Notify(PSTR("\r\nXbox 360 Init Failed, error code: "), 0x80);
Serial.print(rcode, HEX);
#endif
Release();
return rcode;
@ -224,6 +223,7 @@ uint8_t XBOXUSB::Release() {
bPollEnable = false;
return 0;
}
uint8_t XBOXUSB::Poll() {
if (!bPollEnable)
return 0;
@ -239,7 +239,7 @@ uint8_t XBOXUSB::Poll() {
void XBOXUSB::readReport() {
if (readBuf == NULL)
return;
if(readBuf[0] != 0x00 || readBuf[1] != 0x14) { // Check if it's the correct report - the controller also sends different status reports
if (readBuf[0] != 0x00 || readBuf[1] != 0x14) { // Check if it's the correct report - the controller also sends different status reports
return;
}
@ -250,14 +250,14 @@ void XBOXUSB::readReport() {
hatValue[RightHatX] = (int16_t)(((uint16_t)readBuf[11] << 8) | readBuf[10]);
hatValue[RightHatY] = (int16_t)(((uint16_t)readBuf[13] << 8) | readBuf[12]);
//Notify(PSTR("\r\nButtonState"));
//PrintHex<uint32_t>(ButtonState);
//Notify(PSTR("\r\nButtonState"), 0x80);
//PrintHex<uint32_t>(ButtonState, 0x80);
if(ButtonState != OldButtonState) {
if (ButtonState != OldButtonState) {
ButtonClickState = (ButtonState >> 16) & ((~OldButtonState) >> 16); // Update click state variable, but don't include the two trigger buttons L2 and R2
if(((uint8_t)OldButtonState) == 0 && ((uint8_t)ButtonState) != 0) // The L2 and R2 buttons are special as they are analog buttons
if (((uint8_t)OldButtonState) == 0 && ((uint8_t)ButtonState) != 0) // The L2 and R2 buttons are special as they are analog buttons
R2Clicked = true;
if((uint8_t)(OldButtonState >> 8) == 0 && (uint8_t)(ButtonState >> 8) != 0)
if ((uint8_t)(OldButtonState >> 8) == 0 && (uint8_t)(ButtonState >> 8) != 0)
L2Clicked = true;
OldButtonState = ButtonState;
}
@ -267,8 +267,8 @@ void XBOXUSB::printReport() { //Uncomment "#define PRINTREPORT" to print the rep
#ifdef PRINTREPORT
if (readBuf == NULL)
return;
for(uint8_t i = 0; i < XBOX_REPORT_BUFFER_SIZE;i++) {
PrintHex<uint8_t>(readBuf[i]);
for (uint8_t i = 0; i < XBOX_REPORT_BUFFER_SIZE; i++) {
PrintHex<uint8_t > (readBuf[i], 0x80);
Serial.print(" ");
}
Serial.println();
@ -276,22 +276,22 @@ void XBOXUSB::printReport() { //Uncomment "#define PRINTREPORT" to print the rep
}
uint8_t XBOXUSB::getButtonPress(Button b) {
if(b == L2) // These are analog buttons
if (b == L2) // These are analog buttons
return (uint8_t)(ButtonState >> 8);
else if(b == R2)
else if (b == R2)
return (uint8_t)ButtonState;
return (ButtonState & ((uint32_t)pgm_read_word(&XBOXBUTTONS[(uint8_t)b]) << 16));
}
bool XBOXUSB::getButtonClick(Button b) {
if(b == L2) {
if(L2Clicked) {
if (b == L2) {
if (L2Clicked) {
L2Clicked = false;
return true;
}
return false;
}
else if(b == R2) {
if(R2Clicked) {
} else if (b == R2) {
if (R2Clicked) {
R2Clicked = false;
return true;
}
@ -302,6 +302,7 @@ bool XBOXUSB::getButtonClick(Button b) {
ButtonClickState &= ~button; // clear "click" event
return click;
}
int16_t XBOXUSB::getAnalogHat(AnalogHat a) {
return hatValue[a];
}
@ -309,8 +310,9 @@ int16_t XBOXUSB::getAnalogHat(AnalogHat a) {
/* Xbox Controller commands */
void XBOXUSB::XboxCommand(uint8_t* data, uint16_t nbytes) {
//bmRequest = Host to device (0x00) | Class (0x20) | Interface (0x01) = 0x21, bRequest = Set Report (0x09), Report ID (0x00), Report Type (Output 0x02), interface (0x00), datalength, datalength, data)
pUsb->ctrlReq(bAddress,epInfo[XBOX_CONTROL_PIPE].epAddr, bmREQ_HID_OUT, HID_REQUEST_SET_REPORT, 0x00, 0x02, 0x00, nbytes, nbytes, data, NULL);
pUsb->ctrlReq(bAddress, epInfo[XBOX_CONTROL_PIPE].epAddr, bmREQ_HID_OUT, HID_REQUEST_SET_REPORT, 0x00, 0x02, 0x00, nbytes, nbytes, data, NULL);
}
void XBOXUSB::setLedRaw(uint8_t value) {
writeBuf[0] = 0x01;
writeBuf[1] = 0x03;
@ -318,16 +320,20 @@ void XBOXUSB::setLedRaw(uint8_t value) {
XboxCommand(writeBuf, 3);
}
void XBOXUSB::setLedOn(LED led) {
if(led != ALL) // All LEDs can't be on a the same time
setLedRaw((pgm_read_byte(&XBOXLEDS[(uint8_t)led]))+4);
if (led != ALL) // All LEDs can't be on a the same time
setLedRaw((pgm_read_byte(&XBOXLEDS[(uint8_t)led])) + 4);
}
void XBOXUSB::setLedBlink(LED led) {
setLedRaw(pgm_read_byte(&XBOXLEDS[(uint8_t)led]));
}
void XBOXUSB::setLedMode(LEDMode ledMode) { // This function is used to do some speciel LED stuff the controller supports
setLedRaw((uint8_t)ledMode);
}
void XBOXUSB::setRumbleOn(uint8_t lValue, uint8_t rValue) {
writeBuf[0] = 0x00;
writeBuf[1] = 0x08;

View file

@ -83,16 +83,22 @@ public:
* @return 0 on success.
*/
virtual uint8_t Poll();
/**
* Get the device address.
* @return The device address.
*/
virtual uint8_t GetAddress() { return bAddress; };
virtual uint8_t GetAddress() {
return bAddress;
};
/**
* Used to check if the controller has been initialized.
* @return True if it's ready.
*/
virtual bool isReady() { return bPollEnable; };
virtual bool isReady() {
return bPollEnable;
};
/**@}*/
/** @name Xbox Controller functions */
@ -120,9 +126,15 @@ public:
int16_t getAnalogHat(AnalogHat a);
/** Turn rumble off and all the LEDs on the controller. */
void setAllOff() { setRumbleOn(0,0); setLedRaw(0); };
void setAllOff() {
setRumbleOn(0, 0);
setLedRaw(0);
};
/** Turn rumble off the controller. */
void setRumbleOff() { setRumbleOn(0,0); };
void setRumbleOff() {
setRumbleOn(0, 0);
};
/**
* Turn rumble on.
* @param lValue Left motor (big weight) inside the controller.
@ -136,8 +148,11 @@ public:
* setLedBlink(LED l), and setLedMode(LEDMode lm).
*/
void setLedRaw(uint8_t value);
/** Turn all LEDs off the controller. */
void setLedOff() { setLedRaw(0); };
void setLedOff() {
setLedRaw(0);
};
/**
* Turn on a LED by using the ::LED enum.
* @param l ::LED1, ::LED2, ::LED3 and ::LED4 is supported by the Xbox controller.

156
address.h
View file

@ -13,7 +13,7 @@ Contact information
Circuits At Home, LTD
Web : http://www.circuitsathome.com
e-mail : support@circuitsathome.com
*/
*/
#if !defined(__ADDRESS_H__)
#define __ADDRESS_H__
@ -24,28 +24,25 @@ e-mail : support@circuitsathome.com
/* NAK powers. To save space in endpoint data structure, amount of retries before giving up and returning 0x4 is stored in */
/* bmNakPower as a power of 2. The actual nak_limit is then calculated as nak_limit = ( 2^bmNakPower - 1) */
#define USB_NAK_MAX_POWER 16 //NAK binary order maximum value
#define USB_NAK_DEFAULT 14 //default 16K-1 NAKs before giving up
#define USB_NAK_MAX_POWER 15 //NAK binary order maximum value
#define USB_NAK_DEFAULT 14 //default 32K-1 NAKs before giving up
#define USB_NAK_NOWAIT 1 //Single NAK stops transfer
#define USB_NAK_NONAK 0 //Do not count NAKs, stop retrying after USB Timeout
struct EpInfo
{
struct EpInfo {
uint8_t epAddr; // Endpoint address
uint8_t maxPktSize; // Maximum packet size
union
{
union {
uint8_t epAttribs;
struct
{
struct {
uint8_t bmSndToggle : 1; // Send toggle, when zero bmSNDTOG0, bmSNDTOG1 otherwise
uint8_t bmRcvToggle : 1; // Send toggle, when zero bmRCVTOG0, bmRCVTOG1 otherwise
uint8_t bmNakPower : 6; // Binary order for NAK_LIMIT value
} __attribute__((packed));
};
};
};
} __attribute__((packed));
// 7 6 5 4 3 2 1 0
// ---------------------------------
@ -56,36 +53,34 @@ struct EpInfo
// P - parent hub address
// A - device address / port number in case of hub
//
struct UsbDeviceAddress
{
union
{
struct
{
struct UsbDeviceAddress {
union {
struct {
uint8_t bmAddress : 3; // device address/port number
uint8_t bmParent : 3; // parent hub address
uint8_t bmHub : 1; // hub flag
uint8_t bmReserved : 1; // reserved, must be zerro
};
} __attribute__((packed));
uint8_t devAddress;
};
};
} __attribute__((packed));
#define bmUSB_DEV_ADDR_ADDRESS 0x07
#define bmUSB_DEV_ADDR_PARENT 0x38
#define bmUSB_DEV_ADDR_HUB 0x40
struct UsbDevice
{
struct UsbDevice {
EpInfo *epinfo; // endpoint info pointer
uint8_t address; // address
uint8_t epcount; // number of endpoints
bool lowspeed; // indicates if a device is the low speed one
// uint8_t devclass; // device class
};
// uint8_t devclass; // device class
} __attribute__((packed));
class AddressPool
{
class AddressPool {
public:
virtual UsbDevice* GetUsbDevicePtr(uint8_t addr) = 0;
virtual uint8_t AllocAddress(uint8_t parent, bool is_hub = false, uint8_t port = 0) = 0;
@ -98,8 +93,7 @@ typedef void (*UsbDeviceHandleFunc)(UsbDevice *pdev);
#define ADDR_ERROR_INVALID_ADDRESS 0xFF
template <const uint8_t MAX_DEVICES_ALLOWED>
class AddressPoolImpl : public AddressPool
{
class AddressPoolImpl : public AddressPool {
EpInfo dev0ep; //Endpoint data structure used during enumeration for uninitialized device
uint8_t hubCounter; // hub counter is kept
@ -108,64 +102,61 @@ class AddressPoolImpl : public AddressPool
UsbDevice thePool[MAX_DEVICES_ALLOWED];
// Initializes address pool entry
void InitEntry(uint8_t index)
{
void InitEntry(uint8_t index) {
thePool[index].address = 0;
thePool[index].epcount = 1;
thePool[index].lowspeed = 0;
thePool[index].epinfo = &dev0ep;
};
// Returns thePool index for a given address
uint8_t FindAddressIndex(uint8_t address = 0)
{
for (uint8_t i=1; i<MAX_DEVICES_ALLOWED; i++)
{
if (thePool[i].address == address)
uint8_t FindAddressIndex(uint8_t address = 0) {
for(uint8_t i = 1; i < MAX_DEVICES_ALLOWED; i++) {
if(thePool[i].address == address)
return i;
}
return 0;
};
// Returns thePool child index for a given parent
uint8_t FindChildIndex(UsbDeviceAddress addr, uint8_t start = 1)
{
for (uint8_t i=(start<1 || start>=MAX_DEVICES_ALLOWED) ? 1 : start; i<MAX_DEVICES_ALLOWED; i++)
{
if (((UsbDeviceAddress*)&thePool[i].address)->bmParent == addr.bmAddress)
uint8_t FindChildIndex(UsbDeviceAddress addr, uint8_t start = 1) {
for(uint8_t i = (start < 1 || start >= MAX_DEVICES_ALLOWED) ? 1 : start; i < MAX_DEVICES_ALLOWED; i++) {
if(((UsbDeviceAddress*) & thePool[i].address)->bmParent == addr.bmAddress)
return i;
}
return 0;
};
// Frees address entry specified by index parameter
void FreeAddressByIndex(uint8_t index)
{
void FreeAddressByIndex(uint8_t index) {
// Zerro field is reserved and should not be affected
if (index == 0)
if(index == 0)
return;
// If a hub was switched off all port addresses should be freed
if (((UsbDeviceAddress*)&thePool[index].address)->bmHub == 1)
{
for (uint8_t i=1; i = FindChildIndex(*((UsbDeviceAddress*)&thePool[index].address), i); )
if(((UsbDeviceAddress*) & thePool[index].address)->bmHub == 1) {
for(uint8_t i = 1; (i = FindChildIndex(*((UsbDeviceAddress*) & thePool[index].address), i));)
FreeAddressByIndex(i);
// If the hub had the last allocated address, hubCounter should be decremented
if (hubCounter == ((UsbDeviceAddress*)&thePool[index].address)->bmAddress)
hubCounter --;
if(hubCounter == ((UsbDeviceAddress*) & thePool[index].address)->bmAddress)
hubCounter--;
}
InitEntry(index);
}
// Initializes the whole address pool at once
void InitAllAddresses()
{
for (uint8_t i=1; i<MAX_DEVICES_ALLOWED; i++)
void InitAllAddresses() {
for(uint8_t i = 1; i < MAX_DEVICES_ALLOWED; i++)
InitEntry(i);
hubCounter = 0;
};
public:
AddressPoolImpl() : hubCounter(0)
{
AddressPoolImpl() : hubCounter(0) {
// Zero address is reserved
InitEntry(0);
@ -179,52 +170,49 @@ public:
InitAllAddresses();
};
// Returns a pointer to a specified address entry
virtual UsbDevice* GetUsbDevicePtr(uint8_t addr)
{
if (!addr)
virtual UsbDevice* GetUsbDevicePtr(uint8_t addr) {
if(!addr)
return thePool;
uint8_t index = FindAddressIndex(addr);
return (!index) ? NULL : thePool + index;
return(!index) ? NULL : thePool + index;
};
// Performs an operation specified by pfunc for each addressed device
void ForEachUsbDevice(UsbDeviceHandleFunc pfunc)
{
if (!pfunc)
void ForEachUsbDevice(UsbDeviceHandleFunc pfunc) {
if(!pfunc)
return;
for (uint8_t i=1; i<MAX_DEVICES_ALLOWED; i++)
if (thePool[i].address)
for(uint8_t i = 1; i < MAX_DEVICES_ALLOWED; i++)
if(thePool[i].address)
pfunc(thePool + i);
};
// Allocates new address
virtual uint8_t AllocAddress(uint8_t parent, bool is_hub = false, uint8_t port = 0)
{
virtual uint8_t AllocAddress(uint8_t parent, bool is_hub = false, uint8_t port = 0) {
/* if (parent != 0 && port == 0)
Serial.println("PRT:0"); */
if (parent > 127 || port > 7)
if(parent > 127 || port > 7)
return 0;
if (is_hub && hubCounter == 7)
if(is_hub && hubCounter == 7)
return 0;
// finds first empty address entry starting from one
uint8_t index = FindAddressIndex(0);
if (!index) // if empty entry is not found
if(!index) // if empty entry is not found
return 0;
if (parent == 0)
{
if (is_hub)
{
if(parent == 0) {
if(is_hub) {
thePool[index].address = 0x41;
hubCounter ++;
}
else
hubCounter++;
} else
thePool[index].address = 1;
return thePool[index].address;
@ -232,35 +220,31 @@ public:
UsbDeviceAddress addr;
addr.bmParent = ((UsbDeviceAddress*)&parent)->bmAddress;
addr.bmParent = ((UsbDeviceAddress*) & parent)->bmAddress;
if (is_hub)
{
if(is_hub) {
addr.bmHub = 1;
addr.bmAddress = ++hubCounter;
}
else
{
} else {
addr.bmHub = 0;
addr.bmAddress = port;
}
thePool[index].address = *((uint8_t*)&addr);
/*
thePool[index].address = *((uint8_t*) & addr);
/*
Serial.print("Addr:");
Serial.print(addr.bmHub, HEX);
Serial.print(".");
Serial.print(addr.bmParent, HEX);
Serial.print(".");
Serial.println(addr.bmAddress, HEX);
*/
*/
return thePool[index].address;
};
// Empties pool entry
virtual void FreeAddress(uint8_t addr)
{
virtual void FreeAddress(uint8_t addr) {
// if the root hub is disconnected all the addresses should be initialized
if (addr == 0x41)
{
if(addr == 0x41) {
InitAllAddresses();
return;
}

226
adk.cpp
View file

@ -13,12 +13,11 @@ Contact information
Circuits At Home, LTD
Web : http://www.circuitsathome.com
e-mail : support@circuitsathome.com
*/
*/
/* Google ADK interface */
#include "adk.h"
#define DEBUG // Uncomment to print data for debugging
const uint8_t ADK::epDataInIndex = 1;
const uint8_t ADK::epDataOutIndex = 2;
@ -30,29 +29,29 @@ ADK::ADK(USB *p, const char* manufacturer,
const char* uri,
const char* serial) :
pUsb(p), //pointer to USB class instance - mandatory
bAddress(0), //device address - mandatory
bNumEP(1), //if config descriptor needs to be parsed
ready(false),
/* ADK ID Strings */
/* ADK ID Strings */
manufacturer(manufacturer),
model(model),
description(description),
version(version),
uri(uri),
serial(serial)
{
manufacturer(manufacturer),
model(model),
description(description),
version(version),
uri(uri),
serial(serial),
pUsb(p), //pointer to USB class instance - mandatory
bAddress(0), //device address - mandatory
bConfNum(0), //configuration number
bNumEP(1), //if config descriptor needs to be parsed
ready(false) {
// initialize endpoint data structures
for(uint8_t i=0; i<ADK_MAX_ENDPOINTS; i++) {
for (uint8_t i = 0; i < ADK_MAX_ENDPOINTS; i++) {
epInfo[i].epAddr = 0;
epInfo[i].maxPktSize = (i) ? 0 : 8;
epInfo[i].epAttribs = 0;
epInfo[i].bmNakPower = (i) ? USB_NAK_NOWAIT : USB_NAK_MAX_POWER;
epInfo[i].epAttribs = (0xfc & (USB_NAK_MAX_POWER << 2));
}//for(uint8_t i=0; i<ADK_MAX_ENDPOINTS; i++...
//set bulk-IN EP naklimit to 1
epInfo[epDataInIndex].epAttribs = (0xfc & (USB_NAK_NOWAIT << 2));
// register in USB subsystem
if (pUsb) {
pUsb->RegisterDeviceClass(this); //set devConfig[] entry
@ -60,10 +59,9 @@ ADK::ADK(USB *p, const char* manufacturer,
}
/* Connection initialization of an Android phone */
uint8_t ADK::Init(uint8_t parent, uint8_t port, bool lowspeed)
{
uint8_t ADK::Init(uint8_t parent, uint8_t port, bool lowspeed) {
uint8_t buf[sizeof(USB_DEVICE_DESCRIPTOR)];
uint8_t buf[sizeof (USB_DEVICE_DESCRIPTOR)];
uint8_t rcode;
UsbDevice *p = NULL;
EpInfo *oldep_ptr = NULL;
@ -71,14 +69,12 @@ uint8_t ADK::Init(uint8_t parent, uint8_t port, bool lowspeed)
// get memory address of USB device address pool
AddressPool &addrPool = pUsb->GetAddressPool();
#ifdef DEBUG
USBTRACE("\r\nADK Init");
#endif
// check if address has already been assigned to an instance
if (bAddress) {
#ifdef DEBUG
USBTRACE("\r\nAddress in use");
#endif
return USB_ERROR_CLASS_INSTANCE_ALREADY_IN_USE;
}
@ -86,16 +82,12 @@ uint8_t ADK::Init(uint8_t parent, uint8_t port, bool lowspeed)
p = addrPool.GetUsbDevicePtr(0);
if (!p) {
#ifdef DEBUG
USBTRACE("\r\nAddress not found");
#endif
return USB_ERROR_ADDRESS_NOT_FOUND_IN_POOL;
}
if (!p->epinfo) {
#ifdef DEBUG
USBTRACE("epinfo is null\r\n");
#endif
return USB_ERROR_EPINFO_IS_NULL;
}
@ -108,12 +100,12 @@ uint8_t ADK::Init(uint8_t parent, uint8_t port, bool lowspeed)
p->lowspeed = lowspeed;
// Get device descriptor
rcode = pUsb->getDevDescr( 0, 0, sizeof(USB_DEVICE_DESCRIPTOR), (uint8_t*)buf );
rcode = pUsb->getDevDescr(0, 0, sizeof (USB_DEVICE_DESCRIPTOR), (uint8_t*)buf);
// Restore p->epinfo
p->epinfo = oldep_ptr;
if( rcode ){
if (rcode) {
goto FailGetDevDescr;
}
@ -124,7 +116,7 @@ uint8_t ADK::Init(uint8_t parent, uint8_t port, bool lowspeed)
epInfo[0].maxPktSize = (uint8_t)((USB_DEVICE_DESCRIPTOR*)buf)->bMaxPacketSize0;
// Assign new address to the device
rcode = pUsb->setAddr( 0, 0, bAddress );
rcode = pUsb->setAddr(0, 0, bAddress);
if (rcode) {
p->lowspeed = false;
addrPool.FreeAddress(bAddress);
@ -152,39 +144,26 @@ uint8_t ADK::Init(uint8_t parent, uint8_t port, bool lowspeed)
}
//check if ADK device is already in accessory mode; if yes, configure and exit
if(((USB_DEVICE_DESCRIPTOR*)buf)->idVendor == ADK_VID &&
if (((USB_DEVICE_DESCRIPTOR*)buf)->idVendor == ADK_VID &&
(((USB_DEVICE_DESCRIPTOR*)buf)->idProduct == ADK_PID || ((USB_DEVICE_DESCRIPTOR*)buf)->idProduct == ADB_PID)) {
#ifdef DEBUG
USBTRACE("\r\nAcc.mode device detected");
#endif
/* go through configurations, find first bulk-IN, bulk-OUT EP, fill epInfo and quit */
num_of_conf = ((USB_DEVICE_DESCRIPTOR*)buf)->bNumConfigurations;
//USBTRACE2("\r\nNC:",num_of_conf);
for (uint8_t i=0; i<num_of_conf; i++) {
ConfigDescParser<0, 0, 0, 0> confDescrParser(this);
delay(1);
for (uint8_t i = 0; i < num_of_conf; i++) {
ConfigDescParser < 0, 0, 0, 0 > confDescrParser(this);
rcode = pUsb->getConfDescr(bAddress, 0, i, &confDescrParser);
#if defined(XOOM)
//added by Jaylen Scott Vanorden
if( rcode ) {
#ifdef DEBUG
USBTRACE2("\r\nGot 1st bad code for config: ", rcode);
#endif
// Try once more
rcode = pUsb->getConfDescr(bAddress, 0, i, &confDescrParser);
}
#endif
if( rcode ) {
if (rcode) {
goto FailGetConfDescr;
}
if( bNumEP > 2 ) {
if (bNumEP > 2) {
break;
}
} // for (uint8_t i=0; i<num_of_conf; i++...
if( bNumEP == 3 ) {
if (bNumEP == 3) {
// Assign epInfo to epinfo pointer - this time all 3 endpoins
rcode = pUsb->setEpInfoEntry(bAddress, 3, epInfo);
if (rcode) {
@ -196,26 +175,25 @@ uint8_t ADK::Init(uint8_t parent, uint8_t port, bool lowspeed)
// Set Configuration Value
rcode = pUsb->setConf(bAddress, 0, bConfNum);
if( rcode ){
if (rcode) {
goto FailSetConf;
}
/* print endpoint structure */
// USBTRACE("\r\nEndpoint Structure:");
// USBTRACE("\r\nEP0:");
// USBTRACE2("\r\nAddr: ", epInfo[0].epAddr );
// USBTRACE2("\r\nMax.pkt.size: ", epInfo[0].maxPktSize );
// USBTRACE2("\r\nAttr: ", epInfo[0].epAttribs );
// USBTRACE("\r\nEpout:");
// USBTRACE2("\r\nAddr: ", epInfo[epDataOutIndex].epAddr );
// USBTRACE2("\r\nMax.pkt.size: ", epInfo[epDataOutIndex].maxPktSize );
// USBTRACE2("\r\nAttr: ", epInfo[epDataOutIndex].epAttribs );
// USBTRACE("\r\nEpin:");
// USBTRACE2("\r\nAddr: ", epInfo[epDataInIndex].epAddr );
// USBTRACE2("\r\nMax.pkt.size: ", epInfo[epDataInIndex].maxPktSize );
// USBTRACE2("\r\nAttr: ", epInfo[epDataInIndex].epAttribs );
#ifdef DEBUG
// USBTRACE("\r\nEndpoint Structure:");
// USBTRACE("\r\nEP0:");
// USBTRACE2("\r\nAddr: ", epInfo[0].epAddr );
// USBTRACE2("\r\nMax.pkt.size: ", epInfo[0].maxPktSize );
// USBTRACE2("\r\nAttr: ", epInfo[0].epAttribs );
// USBTRACE("\r\nEpout:");
// USBTRACE2("\r\nAddr: ", epInfo[epDataOutIndex].epAddr );
// USBTRACE2("\r\nMax.pkt.size: ", epInfo[epDataOutIndex].maxPktSize );
// USBTRACE2("\r\nAttr: ", epInfo[epDataOutIndex].epAttribs );
// USBTRACE("\r\nEpin:");
// USBTRACE2("\r\nAddr: ", epInfo[epDataInIndex].epAddr );
// USBTRACE2("\r\nMax.pkt.size: ", epInfo[epDataInIndex].maxPktSize );
// USBTRACE2("\r\nAttr: ", epInfo[epDataInIndex].epAttribs );
USBTRACE("\r\nConfiguration successful");
#endif
ready = true;
return 0; //successful configuration
}//if( buf->idVendor == ADK_VID...
@ -223,38 +201,25 @@ uint8_t ADK::Init(uint8_t parent, uint8_t port, bool lowspeed)
//probe device - get accessory protocol revision
{
uint16_t adkproto = -1;
delay(1);
rcode = getProto((uint8_t*)&adkproto );
#if defined(XOOM)
//added by Jaylen Scott Vanorden
if( rcode ) {
#ifdef DEBUG
USBTRACE2("\r\nGot 1st bad code for proto: ", rcode);
#endif
// Try once more
rcode = getProto((uint8_t*)&adkproto );
}
#endif
if( rcode ){
rcode = getProto((uint8_t*) & adkproto);
if (rcode) {
goto FailGetProto; //init fails
}
#ifdef DEBUG
USBTRACE2("\r\nADK protocol rev. ", adkproto );
#endif
USBTRACE2("\r\nADK protocol rev. ", adkproto);
}
//sending ID strings
sendStr( ACCESSORY_STRING_MANUFACTURER, manufacturer);
sendStr( ACCESSORY_STRING_MODEL, model);
sendStr( ACCESSORY_STRING_DESCRIPTION, description);
sendStr( ACCESSORY_STRING_VERSION, version);
sendStr( ACCESSORY_STRING_URI, uri);
sendStr( ACCESSORY_STRING_SERIAL, serial);
sendStr(ACCESSORY_STRING_MANUFACTURER, manufacturer);
sendStr(ACCESSORY_STRING_MODEL, model);
sendStr(ACCESSORY_STRING_DESCRIPTION, description);
sendStr(ACCESSORY_STRING_VERSION, version);
sendStr(ACCESSORY_STRING_URI, uri);
sendStr(ACCESSORY_STRING_SERIAL, serial);
//switch to accessory mode
//the Android phone will reset
rcode = switchAcc();
if( rcode ) {
if (rcode) {
goto FailSwAcc; //init fails
}
rcode = -1;
@ -262,47 +227,37 @@ uint8_t ADK::Init(uint8_t parent, uint8_t port, bool lowspeed)
/* diagnostic messages */
FailGetDevDescr:
#ifdef DEBUG
USBTRACE("\r\ngetDevDescr:");
#endif
goto Fail;
FailSetDevTblEntry:
#ifdef DEBUG
USBTRACE("\r\nsetDevTblEn:");
#endif
goto Fail;
FailGetProto:
#ifdef DEBUG
USBTRACE("\r\ngetProto:");
#endif
goto Fail;
FailSwAcc:
#ifdef DEBUG
USBTRACE("\r\nswAcc:");
#endif
goto Fail;
SwAttempt:
#ifdef DEBUG
USBTRACE("\r\nAccessory mode switch attempt");
#endif
goto Fail;
FailGetConfDescr:
// USBTRACE("getConf:");
// USBTRACE("getConf:");
goto Fail;
//
//
FailSetConf:
// USBTRACE("setConf:");
// USBTRACE("setConf:");
goto Fail;
//
//FailOnInit:
// USBTRACE("OnInit:");
// goto Fail;
//
//
//FailOnInit:
// USBTRACE("OnInit:");
// goto Fail;
//
Fail:
//USBTRACE2("\r\nADK Init Failed, error code: ", rcode);
Release();
@ -310,14 +265,13 @@ Fail:
}
/* Extracts bulk-IN and bulk-OUT endpoint information from config descriptor */
void ADK::EndpointXtract(uint8_t conf, uint8_t iface, uint8_t alt, uint8_t proto, const USB_ENDPOINT_DESCRIPTOR *pep)
{
void ADK::EndpointXtract(uint8_t conf, uint8_t iface, uint8_t alt, uint8_t proto, const USB_ENDPOINT_DESCRIPTOR *pep) {
//ErrorMessage<uint8_t>(PSTR("Conf.Val"), conf);
//ErrorMessage<uint8_t>(PSTR("Iface Num"),iface);
//ErrorMessage<uint8_t>(PSTR("Alt.Set"), alt);
//added by Yuuichi Akagawa
if( bNumEP == 3 ) {
if (bNumEP == 3) {
return;
}
@ -325,22 +279,21 @@ void ADK::EndpointXtract(uint8_t conf, uint8_t iface, uint8_t alt, uint8_t proto
uint8_t index;
if ((pep->bmAttributes & 0x02) == 2) {
// if ((pep->bmAttributes & 0x02) == 2) {
index = ((pep->bEndpointAddress & 0x80) == 0x80) ? epDataInIndex : epDataOutIndex;
}
// }
// Fill in the endpoint info structure
epInfo[index].epAddr = (pep->bEndpointAddress & 0x0F);
epInfo[index].maxPktSize = (uint8_t)pep->wMaxPacketSize;
bNumEP ++;
bNumEP++;
//PrintEndpointDescriptor(pep);
}
/* Performs a cleanup after failed Init() attempt */
uint8_t ADK::Release()
{
uint8_t ADK::Release() {
pUsb->GetAddressPool().FreeAddress(bAddress);
bNumEP = 1; //must have to be reset to 1
@ -350,34 +303,29 @@ uint8_t ADK::Release()
return 0;
}
uint8_t ADK::RcvData(uint16_t *bytes_rcvd, uint8_t *dataptr)
{
uint8_t ADK::RcvData(uint16_t *bytes_rcvd, uint8_t *dataptr) {
//USBTRACE2("\r\nAddr: ", bAddress );
//USBTRACE2("\r\nEP: ",epInfo[epDataInIndex].epAddr);
return pUsb->inTransfer(bAddress, epInfo[epDataInIndex].epAddr, bytes_rcvd, dataptr);
}
uint8_t ADK::SndData(uint16_t nbytes, uint8_t *dataptr)
{
uint8_t ADK::SndData(uint16_t nbytes, uint8_t *dataptr) {
return pUsb->outTransfer(bAddress, epInfo[epDataOutIndex].epAddr, nbytes, dataptr);
}
void ADK::PrintEndpointDescriptor( const USB_ENDPOINT_DESCRIPTOR* ep_ptr )
{
#ifdef DEBUG
Notify(PSTR("Endpoint descriptor:"));
Notify(PSTR("\r\nLength:\t\t"));
PrintHex<uint8_t>(ep_ptr->bLength);
Notify(PSTR("\r\nType:\t\t"));
PrintHex<uint8_t>(ep_ptr->bDescriptorType);
Notify(PSTR("\r\nAddress:\t"));
PrintHex<uint8_t>(ep_ptr->bEndpointAddress);
Notify(PSTR("\r\nAttributes:\t"));
PrintHex<uint8_t>(ep_ptr->bmAttributes);
Notify(PSTR("\r\nMaxPktSize:\t"));
PrintHex<uint16_t>(ep_ptr->wMaxPacketSize);
Notify(PSTR("\r\nPoll Intrv:\t"));
PrintHex<uint8_t>(ep_ptr->bInterval);
Notify(PSTR("\r\n"));
#endif
void ADK::PrintEndpointDescriptor(const USB_ENDPOINT_DESCRIPTOR* ep_ptr) {
Notify(PSTR("Endpoint descriptor:"), 0x80);
Notify(PSTR("\r\nLength:\t\t"), 0x80);
PrintHex<uint8_t > (ep_ptr->bLength, 0x80);
Notify(PSTR("\r\nType:\t\t"), 0x80);
PrintHex<uint8_t > (ep_ptr->bDescriptorType, 0x80);
Notify(PSTR("\r\nAddress:\t"), 0x80);
PrintHex<uint8_t > (ep_ptr->bEndpointAddress, 0x80);
Notify(PSTR("\r\nAttributes:\t"), 0x80);
PrintHex<uint8_t > (ep_ptr->bmAttributes, 0x80);
Notify(PSTR("\r\nMaxPktSize:\t"), 0x80);
PrintHex<uint16_t > (ep_ptr->wMaxPacketSize, 0x80);
Notify(PSTR("\r\nPoll Intrv:\t"), 0x80);
PrintHex<uint8_t > (ep_ptr->bInterval, 0x80);
Notify(PSTR("\r\n"), 0x80);
}

46
adk.h
View file

@ -13,7 +13,7 @@ Contact information
Circuits At Home, LTD
Web : http://www.circuitsathome.com
e-mail : support@circuitsathome.com
*/
*/
/* Google ADK interface support header */
@ -44,10 +44,6 @@ e-mail : support@circuitsathome.com
#define ADK_PID 0x2D00
#define ADB_PID 0x2D01
#define XOOM //enables repeating getProto() and getConf() attempts
//necessary for slow devices such as Motorola XOOM
//defined by default, can be commented out to save memory
/* requests */
#define ADK_GETPROTO 51 //check USB accessory protocol version
@ -68,8 +64,7 @@ e-mail : support@circuitsathome.com
class ADK;
class ADK : public USBDeviceConfig, public UsbConfigXtracter
{
class ADK : public USBDeviceConfig, public UsbConfigXtracter {
private:
/* ID strings */
const char* manufacturer;
@ -80,9 +75,9 @@ private:
const char* serial;
/* ADK proprietary requests */
uint8_t getProto( uint8_t* adkproto );
uint8_t sendStr( uint8_t index, const char* str );
uint8_t switchAcc( void );
uint8_t getProto(uint8_t* adkproto);
uint8_t sendStr(uint8_t index, const char* str);
uint8_t switchAcc(void);
protected:
static const uint8_t epDataInIndex; // DataIn endpoint index
@ -117,28 +112,37 @@ public:
// USBDeviceConfig implementation
virtual uint8_t Init(uint8_t parent, uint8_t port, bool lowspeed);
virtual uint8_t Release();
virtual uint8_t Poll(){}; //not implemented
virtual uint8_t GetAddress() { return bAddress; };
virtual bool isReady() { return ready; };
virtual uint8_t Poll() {
return 0;
};
virtual uint8_t GetAddress() {
return bAddress;
};
virtual bool isReady() {
return ready;
};
//UsbConfigXtracter implementation
virtual void EndpointXtract(uint8_t conf, uint8_t iface, uint8_t alt, uint8_t proto, const USB_ENDPOINT_DESCRIPTOR *ep);
}; //class ADK : public USBDeviceConfig ...
/* get ADK protocol version */
/* returns 2 bytes in *adkproto */
inline uint8_t ADK::getProto( uint8_t* adkproto )
{
return( pUsb->ctrlReq(bAddress, 0, bmREQ_ADK_GET, ADK_GETPROTO, 0, 0, 0, 2, 2, adkproto, NULL ));
inline uint8_t ADK::getProto(uint8_t* adkproto) {
return( pUsb->ctrlReq(bAddress, 0, bmREQ_ADK_GET, ADK_GETPROTO, 0, 0, 0, 2, 2, adkproto, NULL));
}
/* send ADK string */
inline uint8_t ADK::sendStr( uint8_t index, const char* str )
{
return( pUsb->ctrlReq(bAddress, 0, bmREQ_ADK_SEND, ADK_SENDSTR, 0, 0, index, strlen(str) + 1, strlen(str) + 1, (uint8_t*)str, NULL));
inline uint8_t ADK::sendStr(uint8_t index, const char* str) {
return( pUsb->ctrlReq(bAddress, 0, bmREQ_ADK_SEND, ADK_SENDSTR, 0, 0, index, strlen(str) + 1, strlen(str) + 1, (uint8_t*) str, NULL));
}
/* switch to accessory mode */
inline uint8_t ADK::switchAcc( void )
{
inline uint8_t ADK::switchAcc(void) {
return( pUsb->ctrlReq(bAddress, 0, bmREQ_ADK_SEND, ADK_ACCSTART, 0, 0, 0, 0, 0, NULL, NULL));
}

420
avrpins.h
View file

@ -13,24 +13,13 @@ Contact information
Circuits At Home, LTD
Web : http://www.circuitsathome.com
e-mail : support@circuitsathome.com
*/
*/
/* derived from Konstantin Chizhov's AVR port templates */
#ifndef _avrpins_h_
#define _avrpins_h_
#if defined(__AVR_ATmega1280__) || (__AVR_ATmega2560__)
/* Uncomment the following if you have Arduino Mega ADK board with MAX3421e built-in */
//#define BOARD_MEGA_ADK
#endif
/* Uncomment the following if you are using a Teensy 2.0 */
//#define BOARD_TEENSY
/* Uncomment the following if you are using a Sanguino */
//#define BOARD_SANGUINO
#include <avr/io.h>
#ifdef PORTA
@ -122,6 +111,7 @@ e-mail : support@circuitsathome.com
};
#ifdef USE_PORTA
MAKE_PORT(PORTA, DDRA, PINA, Porta, 'A')
#endif
#ifdef USE_PORTB
@ -171,203 +161,234 @@ MAKE_TCCR(TCCR1A, Tccr1a)
MAKE_TCCR(TCCR2A, Tccr2a)
#endif
// this class represents one pin in a IO port.
// It is fully static.
template<typename PORT, uint8_t PIN>
class TPin
{
// BOOST_STATIC_ASSERT(PIN < PORT::Width);
public:
// this class represents one pin in a IO port.
// It is fully static.
template<typename PORT, uint8_t PIN>
class TPin {
// BOOST_STATIC_ASSERT(PIN < PORT::Width);
public:
typedef PORT Port;
enum{Number = PIN};
static void Set() { PORT::Set(1 << PIN); }
enum {
Number = PIN
};
static void Set(uint8_t val){
static void Set() {
PORT::Set(1 << PIN);
}
static void Set(uint8_t val) {
if(val)
Set();
else Clear();}
else Clear();
}
static void SetDir(uint8_t val){
static void SetDir(uint8_t val) {
if(val)
SetDirWrite();
else SetDirRead();}
else SetDirRead();
}
static void Clear(){PORT::Clear(1 << PIN);}
static void Clear() {
PORT::Clear(1 << PIN);
}
static void Toggle(){PORT::Toggle(1 << PIN);}
static void Toggle() {
PORT::Toggle(1 << PIN);
}
static void SetDirRead(){PORT::DirClear(1 << PIN);}
static void SetDirRead() {
PORT::DirClear(1 << PIN);
}
static void SetDirWrite(){PORT::DirSet(1 << PIN);}
static void SetDirWrite() {
PORT::DirSet(1 << PIN);
}
static uint8_t IsSet(){return PORT::PinRead() & (uint8_t)(1 << PIN);}
static uint8_t IsSet() {
return PORT::PinRead() & (uint8_t) (1 << PIN);
}
static void WaiteForSet(){ while(IsSet()==0){} }
static void WaiteForSet() {
while(IsSet() == 0) {
}
}
static void WaiteForClear(){ while(IsSet()){} }
}; //class TPin...
static void WaiteForClear() {
while(IsSet()) {
}
}
}; //class TPin...
// this class represents one bit in TCCR port.
// used to set/clear TCCRx bits
// It is fully static.
template<typename TCCR, uint8_t COM>
class TCom
{
// BOOST_STATIC_ASSERT(PIN < PORT::Width);
public:
// this class represents one bit in TCCR port.
// used to set/clear TCCRx bits
// It is fully static.
template<typename TCCR, uint8_t COM>
class TCom {
// BOOST_STATIC_ASSERT(PIN < PORT::Width);
public:
typedef TCCR Tccr;
enum{Com = COM};
static void Set() { TCCR::Set(1 << COM); }
enum {
Com = COM
};
static void Clear() { TCCR::Clear(1 << COM); }
static void Set() {
TCCR::Set(1 << COM);
}
static void Toggle() { TCCR::Toggle(1 << COM); }
}; //class TCom...
static void Clear() {
TCCR::Clear(1 << COM);
}
static void Toggle() {
TCCR::Toggle(1 << COM);
}
}; //class TCom...
//Short pin definitions
#ifdef USE_PORTA
typedef TPin<Porta, 0> Pa0;
typedef TPin<Porta, 1> Pa1;
typedef TPin<Porta, 2> Pa2;
typedef TPin<Porta, 3> Pa3;
typedef TPin<Porta, 4> Pa4;
typedef TPin<Porta, 5> Pa5;
typedef TPin<Porta, 6> Pa6;
typedef TPin<Porta, 7> Pa7;
typedef TPin<Porta, 0 > Pa0;
typedef TPin<Porta, 1 > Pa1;
typedef TPin<Porta, 2 > Pa2;
typedef TPin<Porta, 3 > Pa3;
typedef TPin<Porta, 4 > Pa4;
typedef TPin<Porta, 5 > Pa5;
typedef TPin<Porta, 6 > Pa6;
typedef TPin<Porta, 7 > Pa7;
#endif
#ifdef USE_PORTB
typedef TPin<Portb, 0> Pb0;
typedef TPin<Portb, 1> Pb1;
typedef TPin<Portb, 2> Pb2;
typedef TPin<Portb, 3> Pb3;
typedef TPin<Portb, 4> Pb4;
typedef TPin<Portb, 5> Pb5;
typedef TPin<Portb, 6> Pb6;
typedef TPin<Portb, 7> Pb7;
typedef TPin<Portb, 0 > Pb0;
typedef TPin<Portb, 1 > Pb1;
typedef TPin<Portb, 2 > Pb2;
typedef TPin<Portb, 3 > Pb3;
typedef TPin<Portb, 4 > Pb4;
typedef TPin<Portb, 5 > Pb5;
typedef TPin<Portb, 6 > Pb6;
typedef TPin<Portb, 7 > Pb7;
#endif
#ifdef USE_PORTC
typedef TPin<Portc, 0> Pc0;
typedef TPin<Portc, 1> Pc1;
typedef TPin<Portc, 2> Pc2;
typedef TPin<Portc, 3> Pc3;
typedef TPin<Portc, 4> Pc4;
typedef TPin<Portc, 5> Pc5;
typedef TPin<Portc, 6> Pc6;
typedef TPin<Portc, 7> Pc7;
typedef TPin<Portc, 0 > Pc0;
typedef TPin<Portc, 1 > Pc1;
typedef TPin<Portc, 2 > Pc2;
typedef TPin<Portc, 3 > Pc3;
typedef TPin<Portc, 4 > Pc4;
typedef TPin<Portc, 5 > Pc5;
typedef TPin<Portc, 6 > Pc6;
typedef TPin<Portc, 7 > Pc7;
#endif
#ifdef USE_PORTD
typedef TPin<Portd, 0> Pd0;
typedef TPin<Portd, 1> Pd1;
typedef TPin<Portd, 2> Pd2;
typedef TPin<Portd, 3> Pd3;
typedef TPin<Portd, 4> Pd4;
typedef TPin<Portd, 5> Pd5;
typedef TPin<Portd, 6> Pd6;
typedef TPin<Portd, 7> Pd7;
typedef TPin<Portd, 0 > Pd0;
typedef TPin<Portd, 1 > Pd1;
typedef TPin<Portd, 2 > Pd2;
typedef TPin<Portd, 3 > Pd3;
typedef TPin<Portd, 4 > Pd4;
typedef TPin<Portd, 5 > Pd5;
typedef TPin<Portd, 6 > Pd6;
typedef TPin<Portd, 7 > Pd7;
#endif
#ifdef USE_PORTE
typedef TPin<Porte, 0> Pe0;
typedef TPin<Porte, 1> Pe1;
typedef TPin<Porte, 2> Pe2;
typedef TPin<Porte, 3> Pe3;
typedef TPin<Porte, 4> Pe4;
typedef TPin<Porte, 5> Pe5;
typedef TPin<Porte, 6> Pe6;
typedef TPin<Porte, 7> Pe7;
typedef TPin<Porte, 0 > Pe0;
typedef TPin<Porte, 1 > Pe1;
typedef TPin<Porte, 2 > Pe2;
typedef TPin<Porte, 3 > Pe3;
typedef TPin<Porte, 4 > Pe4;
typedef TPin<Porte, 5 > Pe5;
typedef TPin<Porte, 6 > Pe6;
typedef TPin<Porte, 7 > Pe7;
#endif
#ifdef USE_PORTF
typedef TPin<Portf, 0> Pf0;
typedef TPin<Portf, 1> Pf1;
typedef TPin<Portf, 2> Pf2;
typedef TPin<Portf, 3> Pf3;
typedef TPin<Portf, 4> Pf4;
typedef TPin<Portf, 5> Pf5;
typedef TPin<Portf, 6> Pf6;
typedef TPin<Portf, 7> Pf7;
typedef TPin<Portf, 0 > Pf0;
typedef TPin<Portf, 1 > Pf1;
typedef TPin<Portf, 2 > Pf2;
typedef TPin<Portf, 3 > Pf3;
typedef TPin<Portf, 4 > Pf4;
typedef TPin<Portf, 5 > Pf5;
typedef TPin<Portf, 6 > Pf6;
typedef TPin<Portf, 7 > Pf7;
#endif
#ifdef USE_PORTG
typedef TPin<Portg, 0> Pg0;
typedef TPin<Portg, 1> Pg1;
typedef TPin<Portg, 2> Pg2;
typedef TPin<Portg, 3> Pg3;
typedef TPin<Portg, 4> Pg4;
typedef TPin<Portg, 5> Pg5;
typedef TPin<Portg, 6> Pg6;
typedef TPin<Portg, 7> Pg7;
typedef TPin<Portg, 0 > Pg0;
typedef TPin<Portg, 1 > Pg1;
typedef TPin<Portg, 2 > Pg2;
typedef TPin<Portg, 3 > Pg3;
typedef TPin<Portg, 4 > Pg4;
typedef TPin<Portg, 5 > Pg5;
typedef TPin<Portg, 6 > Pg6;
typedef TPin<Portg, 7 > Pg7;
#endif
#ifdef USE_PORTH
typedef TPin<Porth, 0> Ph0;
typedef TPin<Porth, 1> Ph1;
typedef TPin<Porth, 2> Ph2;
typedef TPin<Porth, 3> Ph3;
typedef TPin<Porth, 4> Ph4;
typedef TPin<Porth, 5> Ph5;
typedef TPin<Porth, 6> Ph6;
typedef TPin<Porth, 7> Ph7;
typedef TPin<Porth, 0 > Ph0;
typedef TPin<Porth, 1 > Ph1;
typedef TPin<Porth, 2 > Ph2;
typedef TPin<Porth, 3 > Ph3;
typedef TPin<Porth, 4 > Ph4;
typedef TPin<Porth, 5 > Ph5;
typedef TPin<Porth, 6 > Ph6;
typedef TPin<Porth, 7 > Ph7;
#endif
#ifdef USE_PORTJ
typedef TPin<Portj, 0> Pj0;
typedef TPin<Portj, 1> Pj1;
typedef TPin<Portj, 2> Pj2;
typedef TPin<Portj, 3> Pj3;
typedef TPin<Portj, 4> Pj4;
typedef TPin<Portj, 5> Pj5;
typedef TPin<Portj, 6> Pj6;
typedef TPin<Portj, 7> Pj7;
typedef TPin<Portj, 0 > Pj0;
typedef TPin<Portj, 1 > Pj1;
typedef TPin<Portj, 2 > Pj2;
typedef TPin<Portj, 3 > Pj3;
typedef TPin<Portj, 4 > Pj4;
typedef TPin<Portj, 5 > Pj5;
typedef TPin<Portj, 6 > Pj6;
typedef TPin<Portj, 7 > Pj7;
#endif
#ifdef USE_PORTK
typedef TPin<Portk, 0> Pk0;
typedef TPin<Portk, 1> Pk1;
typedef TPin<Portk, 2> Pk2;
typedef TPin<Portk, 3> Pk3;
typedef TPin<Portk, 4> Pk4;
typedef TPin<Portk, 5> Pk5;
typedef TPin<Portk, 6> Pk6;
typedef TPin<Portk, 7> Pk7;
typedef TPin<Portk, 0 > Pk0;
typedef TPin<Portk, 1 > Pk1;
typedef TPin<Portk, 2 > Pk2;
typedef TPin<Portk, 3 > Pk3;
typedef TPin<Portk, 4 > Pk4;
typedef TPin<Portk, 5 > Pk5;
typedef TPin<Portk, 6 > Pk6;
typedef TPin<Portk, 7 > Pk7;
#endif
#ifdef USE_PORTL
typedef TPin<Portl, 0> Pl0;
typedef TPin<Portl, 1> Pl1;
typedef TPin<Portl, 2> Pl2;
typedef TPin<Portl, 3> Pl3;
typedef TPin<Portl, 4> Pl4;
typedef TPin<Portl, 5> Pl5;
typedef TPin<Portl, 6> Pl6;
typedef TPin<Portl, 7> Pl7;
typedef TPin<Portl, 0 > Pl0;
typedef TPin<Portl, 1 > Pl1;
typedef TPin<Portl, 2 > Pl2;
typedef TPin<Portl, 3 > Pl3;
typedef TPin<Portl, 4 > Pl4;
typedef TPin<Portl, 5 > Pl5;
typedef TPin<Portl, 6 > Pl6;
typedef TPin<Portl, 7 > Pl7;
#endif
#ifdef USE_PORTQ
typedef TPin<Portq, 0> Pq0;
typedef TPin<Portq, 1> Pq1;
typedef TPin<Portq, 2> Pq2;
typedef TPin<Portq, 3> Pq3;
typedef TPin<Portq, 4> Pq4;
typedef TPin<Portq, 5> Pq5;
typedef TPin<Portq, 6> Pq6;
typedef TPin<Portq, 7> Pq7;
typedef TPin<Portq, 0 > Pq0;
typedef TPin<Portq, 1 > Pq1;
typedef TPin<Portq, 2 > Pq2;
typedef TPin<Portq, 3 > Pq3;
typedef TPin<Portq, 4 > Pq4;
typedef TPin<Portq, 5 > Pq5;
typedef TPin<Portq, 6 > Pq6;
typedef TPin<Portq, 7 > Pq7;
#endif
#ifdef USE_PORTR
typedef TPin<Portr, 0> Pr0;
typedef TPin<Portr, 1> Pr1;
typedef TPin<Portr, 2> Pr2;
typedef TPin<Portr, 3> Pr3;
typedef TPin<Portr, 4> Pr4;
typedef TPin<Portr, 5> Pr5;
typedef TPin<Portr, 6> Pr6;
typedef TPin<Portr, 7> Pr7;
typedef TPin<Portr, 0 > Pr0;
typedef TPin<Portr, 1 > Pr1;
typedef TPin<Portr, 2 > Pr2;
typedef TPin<Portr, 3 > Pr3;
typedef TPin<Portr, 4 > Pr4;
typedef TPin<Portr, 5 > Pr5;
typedef TPin<Portr, 6 > Pr6;
typedef TPin<Portr, 7 > Pr7;
#endif
#ifdef USE_TCCR0A
@ -386,23 +407,25 @@ typedef TCom<Tccr2a, COM2B1> Tc2b; //P3
#endif
template<typename Tp_pin, typename Tc_bit>
class Tp_Tc
{
public:
static void SetDir(uint8_t val){
class Tp_Tc {
public:
static void SetDir(uint8_t val) {
if(val)
SetDirWrite();
else SetDirRead();
}
static void SetDirRead(){
static void SetDirRead() {
Tp_pin::SetDirRead(); //set pin direction
Tc_bit::Clear(); //disconnect pin from PWM
}
static void SetDirWrite(){
static void SetDirWrite() {
Tp_pin::SetDirWrite();
Tc_bit::Clear();
}
};
};
/* pin definitions for cases where it's necessary to clear compare output mode bits */
@ -476,7 +499,6 @@ template<typename Tp_pin, typename Tc_bit>
#define P51 Pb2
#define P52 Pb1
#define P53 Pb0
#define P54 Pe6 // INT on Arduino ADK
#endif //"Mega" pin numbers
@ -508,47 +530,7 @@ template<typename Tp_pin, typename Tc_bit>
#endif // "Classic" Arduino pin numbers
#if !defined(BOARD_TEENSY) && defined(__AVR_ATmega32U4__)
// Arduino Leonardo pin numbers
#define P0 Pd2 // D0 - PD2
#define P1 Pd3 // D1 - PD3
#define P2 Pd1 // D2 - PD1
#define P3 Pd0 // D3 - PD0
#define P4 Pd4 // D4 - PD4
#define P5 Pc6 // D5 - PC6
#define P6 Pd7 // D6 - PD7
#define P7 Pe6 // D7 - PE6
#define P8 Pb4 // D8 - PB4
#define P9 Pb5 // D9 - PB5
#define P10 Pb6 // D10 - PB6
#define P11 Pb7 // D11 - PB7
#define P12 Pd6 // D12 - PD6
#define P13 Pc7 // D13 - PC7
#define P14 Pb3 // D14 - MISO - PB3
#define P15 Pb1 // D15 - SCK - PB1
#define P16 Pb2 // D16 - MOSI - PB2
#define P17 Pb0 // D17 - SS - PB0
#define P18 Pf7 // D18 - A0 - PF7
#define P19 Pf6 // D19 - A1 - PF6
#define P20 Pf5 // D20 - A2 - PF5
#define P21 Pf4 // D21 - A3 - PF4
#define P22 Pf1 // D22 - A4 - PF1
#define P23 Pf0 // D23 - A5 - PF0
#define P24 Pd4 // D24 / D4 - A6 - PD4
#define P25 Pd7 // D25 / D6 - A7 - PD7
#define P26 Pb4 // D26 / D8 - A8 - PB4
#define P27 Pb5 // D27 / D9 - A9 - PB5
#define P28 Pb6 // D28 / D10 - A10 - PB6
#define P29 Pd6 // D29 / D12 - A11 - PD6
#endif // Arduino Leonardo pin numbers
#if defined(BOARD_TEENSY) && defined(__AVR_ATmega32U4__)
#if defined(__AVR_ATmega32U4__)
// Teensy 2.0 pin numbers
// http://www.pjrc.com/teensy/pinout.html
#define P0 Pb0
@ -629,45 +611,7 @@ template<typename Tp_pin, typename Tc_bit>
#define P45 Pf7
#endif // Teensy++ 2.0
#if !defined(BOARD_SANGUINO) && (defined(__AVR_ATmega644__) || defined(__AVR_ATmega644P__))
#define BOARD_BALANDUINO
// Balanduino pin numbers
// http://balanduino.net/
#define P0 Pd0 /* 0 - PD0 */
#define P1 Pd1 /* 1 - PD1 */
#define P2 Pb2 /* 2 - PB2 */
#define P3 Pd6 /* 3 - PD6 */
#define P4 Pd7 /* 4 - PD7 */
#define P5 Pb3 /* 5 - PB3 */
#define P6 Pb4 /* 6 - PB4 */
#define P7 Pa0 /* 7 - PA0 */
#define P8 Pa1 /* 8 - PA1 */
#define P9 Pa2 /* 9 - PA2 */
#define P10 Pa3 /* 10 - PA3 */
#define P11 Pa4 /* 11 - PA4 */
#define P12 Pa5 /* 12 - PA5 */
#define P13 Pc0 /* 13 - PC0 */
#define P14 Pc1 /* 14 - PC1 */
#define P15 Pd2 /* 15 - PD2 */
#define P16 Pd3 /* 16 - PD3 */
#define P17 Pd4 /* 17 - PD4 */
#define P18 Pd5 /* 18 - PD5 */
#define P19 Pc2 /* 19 - PC2 */
#define P20 Pc3 /* 20 - PC3 */
#define P21 Pc4 /* 21 - PC4 */
#define P22 Pc5 /* 22 - PC5 */
#define P23 Pc6 /* 23 - PC6 */
#define P24 Pc7 /* 24 - PC7 */
#define P25 Pb0 /* 25 - PB0 */
#define P26 Pb1 /* 26 - PB1 */
#define P27 Pb5 /* 27 - PB5 */
#define P28 Pb6 /* 28 - PB6 */
#define P29 Pb7 /* 29 - PB7 */
#define P30 Pa6 /* 30 - PA6 */
#define P31 Pa7 /* 31 - PA7 */
#endif // Balanduino
#if defined(BOARD_SANGUINO) && (defined(__AVR_ATmega644__) || defined(__AVR_ATmega644P__))
#if defined(__AVR_ATmega644__) || defined(__AVR_ATmega644P__)
// Sanguino pin numbers
// http://sanguino.cc/hardware
#define P0 Pb0

View file

@ -13,7 +13,7 @@ Contact information
Circuits At Home, LTD
Web : http://www.circuitsathome.com
e-mail : support@circuitsathome.com
*/
*/
#include "cdcacm.h"
const uint8_t ACM::epDataInIndex = 1;
@ -21,35 +21,30 @@ const uint8_t ACM::epDataOutIndex = 2;
const uint8_t ACM::epInterruptInIndex = 3;
ACM::ACM(USB *p, CDCAsyncOper *pasync) :
pUsb(p),
pAsync(pasync),
bAddress(0),
qNextPollTime(0),
bPollEnable(false),
bControlIface(0),
bDataIface(0),
bNumEP(1),
ready(false)
{
for(uint8_t i=0; i<ACM_MAX_ENDPOINTS; i++)
{
pUsb(p),
pAsync(pasync),
bAddress(0),
bControlIface(0),
bDataIface(0),
bNumEP(1),
qNextPollTime(0),
bPollEnable(false) {
for (uint8_t i = 0; i < ACM_MAX_ENDPOINTS; i++) {
epInfo[i].epAddr = 0;
epInfo[i].maxPktSize = (i) ? 0 : 8;
epInfo[i].epAttribs = 0;
epInfo[i].bmNakPower = USB_NAK_NOWAIT;
//epInfo[i].bmNakPower = USB_NAK_MAX_POWER;
if (!i)
//epInfo[i].bmNakPower = USB_NAK_NOWAIT;
epInfo[i].bmNakPower = USB_NAK_MAX_POWER;
//if (!i)
epInfo[i].bmNakPower = USB_NAK_MAX_POWER;
}
if (pUsb)
pUsb->RegisterDeviceClass(this);
}
uint8_t ACM::Init(uint8_t parent, uint8_t port, bool lowspeed)
{
const uint8_t constBufSize = sizeof(USB_DEVICE_DESCRIPTOR);
uint8_t ACM::Init(uint8_t parent, uint8_t port, bool lowspeed) {
const uint8_t constBufSize = sizeof (USB_DEVICE_DESCRIPTOR);
uint8_t buf[constBufSize];
uint8_t rcode;
@ -70,8 +65,7 @@ uint8_t ACM::Init(uint8_t parent, uint8_t port, bool lowspeed)
if (!p)
return USB_ERROR_ADDRESS_NOT_FOUND_IN_POOL;
if (!p->epinfo)
{
if (!p->epinfo) {
USBTRACE("epinfo\r\n");
return USB_ERROR_EPINFO_IS_NULL;
}
@ -85,12 +79,12 @@ uint8_t ACM::Init(uint8_t parent, uint8_t port, bool lowspeed)
p->lowspeed = lowspeed;
// Get device descriptor
rcode = pUsb->getDevDescr( 0, 0, constBufSize, (uint8_t*)buf );
rcode = pUsb->getDevDescr(0, 0, constBufSize, (uint8_t*)buf);
// Restore p->epinfo
p->epinfo = oldep_ptr;
if( rcode )
if (rcode)
goto FailGetDevDescr;
// Allocate new address according to device class
@ -103,14 +97,13 @@ uint8_t ACM::Init(uint8_t parent, uint8_t port, bool lowspeed)
epInfo[0].maxPktSize = (uint8_t)((USB_DEVICE_DESCRIPTOR*)buf)->bMaxPacketSize0;
// Assign new address to the device
rcode = pUsb->setAddr( 0, 0, bAddress );
rcode = pUsb->setAddr(0, 0, bAddress);
if (rcode)
{
if (rcode) {
p->lowspeed = false;
addrPool.FreeAddress(bAddress);
bAddress = 0;
USBTRACE2("setAddr:",rcode);
USBTRACE2("setAddr:", rcode);
return rcode;
}
@ -135,21 +128,27 @@ uint8_t ACM::Init(uint8_t parent, uint8_t port, bool lowspeed)
USBTRACE2("NC:", num_of_conf);
for (uint8_t i=0; i<num_of_conf; i++)
{
for (uint8_t i = 0; i < num_of_conf; i++) {
ConfigDescParser< USB_CLASS_COM_AND_CDC_CTRL,
CDC_SUBCLASS_ACM,
CDC_PROTOCOL_ITU_T_V_250,
CP_MASK_COMPARE_CLASS |
CP_MASK_COMPARE_SUBCLASS |
CP_MASK_COMPARE_PROTOCOL> CdcControlParser(this);
CP_MASK_COMPARE_PROTOCOL > CdcControlParser(this);
ConfigDescParser<USB_CLASS_CDC_DATA, 0, 0,
CP_MASK_COMPARE_CLASS> CdcDataParser(this);
rcode = pUsb->getConfDescr(bAddress, 0, i, &CdcControlParser);
if (rcode)
goto FailGetConfDescr;
rcode = pUsb->getConfDescr(bAddress, 0, i, &CdcDataParser);
if (rcode)
goto FailGetConfDescr;
if (bNumEP > 1)
break;
} // for
@ -174,7 +173,6 @@ uint8_t ACM::Init(uint8_t parent, uint8_t port, bool lowspeed)
goto FailOnInit;
USBTRACE("ACM configured\r\n");
ready = true;
//bPollEnable = true;
@ -202,17 +200,17 @@ FailOnInit:
goto Fail;
Fail:
Serial.println(rcode, HEX);
PrintHex<uint8_t > (rcode, 0x80);
Notify(PSTR("\r\n"), 0x80);
// Serial.println(rcode, HEX);
Release();
return rcode;
}
void ACM::EndpointXtract(uint8_t conf, uint8_t iface, uint8_t alt, uint8_t proto, const USB_ENDPOINT_DESCRIPTOR *pep)
{
//ErrorMessage<uint8_t>(PSTR("Conf.Val"), conf);
//ErrorMessage<uint8_t>(PSTR("Iface Num"),iface);
//ErrorMessage<uint8_t>(PSTR("Alt.Set"), alt);
void ACM::EndpointXtract(uint8_t conf, uint8_t iface, uint8_t alt, uint8_t proto, const USB_ENDPOINT_DESCRIPTOR *pep) {
ErrorMessage<uint8_t > (PSTR("Conf.Val"), conf);
ErrorMessage<uint8_t > (PSTR("Iface Num"), iface);
ErrorMessage<uint8_t > (PSTR("Alt.Set"), alt);
bConfNum = conf;
@ -229,15 +227,14 @@ void ACM::EndpointXtract(uint8_t conf, uint8_t iface, uint8_t alt, uint8_t proto
// Fill in the endpoint info structure
epInfo[index].epAddr = (pep->bEndpointAddress & 0x0F);
epInfo[index].maxPktSize = (uint8_t)pep->wMaxPacketSize;
//epInfo[index].epAttribs = 0;
epInfo[index].epAttribs = 0;
bNumEP ++;
bNumEP++;
//PrintEndpointDescriptor(pep);
PrintEndpointDescriptor(pep);
}
uint8_t ACM::Release()
{
uint8_t ACM::Release() {
pUsb->GetAddressPool().FreeAddress(bAddress);
bControlIface = 0;
@ -247,12 +244,10 @@ uint8_t ACM::Release()
bAddress = 0;
qNextPollTime = 0;
bPollEnable = false;
ready = false;
return 0;
}
uint8_t ACM::Poll()
{
uint8_t ACM::Poll() {
uint8_t rcode = 0;
if (!bPollEnable)
@ -288,72 +283,55 @@ uint8_t ACM::Poll()
return rcode;
}
uint8_t ACM::RcvData(uint16_t *bytes_rcvd, uint8_t *dataptr)
{
uint8_t ACM::RcvData(uint16_t *bytes_rcvd, uint8_t *dataptr) {
return pUsb->inTransfer(bAddress, epInfo[epDataInIndex].epAddr, bytes_rcvd, dataptr);
}
uint8_t ACM::SndData(uint16_t nbytes, uint8_t *dataptr)
{
uint8_t ACM::SndData(uint16_t nbytes, uint8_t *dataptr) {
return pUsb->outTransfer(bAddress, epInfo[epDataOutIndex].epAddr, nbytes, dataptr);
}
/* untested */
uint8_t ACM::GetNotif( uint16_t *bytes_rcvd, uint8_t *dataptr )
{
return pUsb->inTransfer(bAddress, epInfo[epInterruptInIndex].epAddr, bytes_rcvd, dataptr);
uint8_t ACM::SetCommFeature(uint16_t fid, uint8_t nbytes, uint8_t *dataptr) {
return ( pUsb->ctrlReq(bAddress, 0, bmREQ_CDCOUT, CDC_SET_COMM_FEATURE, (fid & 0xff), (fid >> 8), bControlIface, nbytes, nbytes, dataptr, NULL));
}
uint8_t ACM::SetCommFeature(uint16_t fid, uint8_t nbytes, uint8_t *dataptr)
{
return( pUsb->ctrlReq( bAddress, 0, bmREQ_CDCOUT, CDC_SET_COMM_FEATURE, (fid & 0xff), (fid >> 8), bControlIface, nbytes, nbytes, dataptr, NULL ));
uint8_t ACM::GetCommFeature(uint16_t fid, uint8_t nbytes, uint8_t *dataptr) {
return ( pUsb->ctrlReq(bAddress, 0, bmREQ_CDCIN, CDC_GET_COMM_FEATURE, (fid & 0xff), (fid >> 8), bControlIface, nbytes, nbytes, dataptr, NULL));
}
uint8_t ACM::GetCommFeature(uint16_t fid, uint8_t nbytes, uint8_t *dataptr)
{
return( pUsb->ctrlReq( bAddress, 0, bmREQ_CDCIN, CDC_GET_COMM_FEATURE, (fid & 0xff), (fid >> 8), bControlIface, nbytes, nbytes, dataptr, NULL ));
uint8_t ACM::ClearCommFeature(uint16_t fid) {
return ( pUsb->ctrlReq(bAddress, 0, bmREQ_CDCOUT, CDC_CLEAR_COMM_FEATURE, (fid & 0xff), (fid >> 8), bControlIface, 0, 0, NULL, NULL));
}
uint8_t ACM::ClearCommFeature(uint16_t fid)
{
return( pUsb->ctrlReq( bAddress, 0, bmREQ_CDCOUT, CDC_CLEAR_COMM_FEATURE, (fid & 0xff), (fid >> 8), bControlIface, 0, 0, NULL, NULL ));
uint8_t ACM::SetLineCoding(const LINE_CODING *dataptr) {
return ( pUsb->ctrlReq(bAddress, 0, bmREQ_CDCOUT, CDC_SET_LINE_CODING, 0x00, 0x00, bControlIface, sizeof (LINE_CODING), sizeof (LINE_CODING), (uint8_t*)dataptr, NULL));
}
uint8_t ACM::SetLineCoding(const LINE_CODING *dataptr)
{
return( pUsb->ctrlReq( bAddress, 0, bmREQ_CDCOUT, CDC_SET_LINE_CODING, 0x00, 0x00, bControlIface, sizeof(LINE_CODING), sizeof(LINE_CODING), (uint8_t*)dataptr, NULL ));
uint8_t ACM::GetLineCoding(LINE_CODING *dataptr) {
return ( pUsb->ctrlReq(bAddress, 0, bmREQ_CDCIN, CDC_GET_LINE_CODING, 0x00, 0x00, bControlIface, sizeof (LINE_CODING), sizeof (LINE_CODING), (uint8_t*)dataptr, NULL));
}
uint8_t ACM::GetLineCoding(LINE_CODING *dataptr)
{
return( pUsb->ctrlReq( bAddress, 0, bmREQ_CDCIN, CDC_GET_LINE_CODING, 0x00, 0x00, bControlIface, sizeof(LINE_CODING), sizeof(LINE_CODING), (uint8_t*)dataptr, NULL ));
uint8_t ACM::SetControlLineState(uint8_t state) {
return ( pUsb->ctrlReq(bAddress, 0, bmREQ_CDCOUT, CDC_SET_CONTROL_LINE_STATE, state, 0, bControlIface, 0, 0, NULL, NULL));
}
uint8_t ACM::SetControlLineState(uint8_t state)
{
return( pUsb->ctrlReq( bAddress, 0, bmREQ_CDCOUT, CDC_SET_CONTROL_LINE_STATE, state, 0, bControlIface, 0, 0, NULL, NULL ));
uint8_t ACM::SendBreak(uint16_t duration) {
return ( pUsb->ctrlReq(bAddress, 0, bmREQ_CDCOUT, CDC_SEND_BREAK, (duration & 0xff), (duration >> 8), bControlIface, 0, 0, NULL, NULL));
}
uint8_t ACM::SendBreak(uint16_t duration)
{
return( pUsb->ctrlReq( bAddress, 0, bmREQ_CDCOUT, CDC_SEND_BREAK, (duration & 0xff), (duration >> 8), bControlIface, 0, 0, NULL, NULL ));
}
void ACM::PrintEndpointDescriptor( const USB_ENDPOINT_DESCRIPTOR* ep_ptr )
{
Notify(PSTR("Endpoint descriptor:"));
Notify(PSTR("\r\nLength:\t\t"));
PrintHex<uint8_t>(ep_ptr->bLength);
Notify(PSTR("\r\nType:\t\t"));
PrintHex<uint8_t>(ep_ptr->bDescriptorType);
Notify(PSTR("\r\nAddress:\t"));
PrintHex<uint8_t>(ep_ptr->bEndpointAddress);
Notify(PSTR("\r\nAttributes:\t"));
PrintHex<uint8_t>(ep_ptr->bmAttributes);
Notify(PSTR("\r\nMaxPktSize:\t"));
PrintHex<uint16_t>(ep_ptr->wMaxPacketSize);
Notify(PSTR("\r\nPoll Intrv:\t"));
PrintHex<uint8_t>(ep_ptr->bInterval);
Notify(PSTR("\r\n"));
void ACM::PrintEndpointDescriptor(const USB_ENDPOINT_DESCRIPTOR* ep_ptr) {
Notify(PSTR("Endpoint descriptor:"), 0x80);
Notify(PSTR("\r\nLength:\t\t"), 0x80);
PrintHex<uint8_t > (ep_ptr->bLength, 0x80);
Notify(PSTR("\r\nType:\t\t"), 0x80);
PrintHex<uint8_t > (ep_ptr->bDescriptorType, 0x80);
Notify(PSTR("\r\nAddress:\t"), 0x80);
PrintHex<uint8_t > (ep_ptr->bEndpointAddress, 0x80);
Notify(PSTR("\r\nAttributes:\t"), 0x80);
PrintHex<uint8_t > (ep_ptr->bmAttributes, 0x80);
Notify(PSTR("\r\nMaxPktSize:\t"), 0x80);
PrintHex<uint16_t > (ep_ptr->wMaxPacketSize, 0x80);
Notify(PSTR("\r\nPoll Intrv:\t"), 0x80);
PrintHex<uint8_t > (ep_ptr->bInterval, 0x80);
Notify(PSTR("\r\n"), 0x80);
}

View file

@ -13,7 +13,7 @@ Contact information
Circuits At Home, LTD
Web : http://www.circuitsathome.com
e-mail : support@circuitsathome.com
*/
*/
#if !defined(__CDCACM_H__)
#define __CDCACM_H__
@ -89,20 +89,9 @@ e-mail : support@circuitsathome.com
#define CDC_GET_LINE_PARMS 0x35
#define CDC_DIAL_DIGITS 0x36
//Class-Specific Notification Codes
#define NETWORK_CONNECTION 0x00
#define RESPONSE_AVAILABLE 0x01
#define AUX_JACK_HOOK_STATE 0x08
#define RING_DETECT 0x09
#define SERIAL_STATE 0x20
#define CALL_STATE_CHANGE 0x28
#define LINE_STATE_CHANGE 0x29
#define CONNECTION_SPEED_CHANGE 0x2a
// CDC Functional Descriptor Structures
typedef struct
{
typedef struct {
uint8_t bFunctionLength;
uint8_t bDescriptorType;
uint8_t bDescriptorSubtype;
@ -110,17 +99,15 @@ typedef struct
uint8_t bDataInterface;
} CALL_MGMNT_FUNC_DESCR;
typedef struct
{
typedef struct {
uint8_t bFunctionLength;
uint8_t bDescriptorType;
uint8_t bDescriptorSubtype;
uint8_t bmCapabilities;
} ACM_FUNC_DESCR, DLM_FUNC_DESCR, TEL_OPER_MODES_FUNC_DESCR,
TEL_CALL_STATE_REP_CPBL_FUNC_DESCR;
TEL_CALL_STATE_REP_CPBL_FUNC_DESCR;
typedef struct
{
typedef struct {
uint8_t bFunctionLength;
uint8_t bDescriptorType;
uint8_t bDescriptorSubtype;
@ -128,28 +115,16 @@ typedef struct
uint8_t bNumRingerPatterns;
} TEL_RINGER_FUNC_DESCR;
typedef struct
{
typedef struct {
uint32_t dwDTERate; // Data Terminal Rate in bits per second
uint8_t bCharFormat; // 0 - 1 stop bit, 1 - 1.5 stop bits, 2 - 2 stop bits
uint8_t bParityType; // 0 - None, 1 - Odd, 2 - Even, 3 - Mark, 4 - Space
uint8_t bDataBits; // Data bits (5, 6, 7, 8 or 16)
} LINE_CODING;
typedef struct
{
uint8_t bmRequestType; // 0xa1 for class-specific notifications
uint8_t bNotification;
uint16_t wValue;
uint16_t wIndex;
uint16_t wLength;
uint16_t bmState; //UART state bitmap for SERIAL_STATE, other notifications variable length
} CLASS_NOTIFICATION;
class ACM;
class CDCAsyncOper
{
class CDCAsyncOper {
public:
virtual uint8_t OnInit(ACM *pacm) = 0;
//virtual void OnDataRcvd(ACM *pacm, uint8_t nbytes, uint8_t *dataptr) = 0;
@ -159,8 +134,7 @@ public:
#define ACM_MAX_ENDPOINTS 4
class ACM : public USBDeviceConfig, public UsbConfigXtracter
{
class ACM : public USBDeviceConfig, public UsbConfigXtracter {
protected:
static const uint8_t epDataInIndex; // DataIn endpoint index
static const uint8_t epDataOutIndex; // DataOUT endpoint index
@ -175,7 +149,6 @@ protected:
uint8_t bNumEP; // total number of EP in the configuration
uint32_t qNextPollTime; // next poll time
bool bPollEnable; // poll enable flag
bool ready; //device ready indicator
EpInfo epInfo[ACM_MAX_ENDPOINTS];
@ -191,7 +164,6 @@ public:
uint8_t GetLineCoding(LINE_CODING *dataptr);
uint8_t SetControlLineState(uint8_t state);
uint8_t SendBreak(uint16_t duration);
uint8_t GetNotif( uint16_t *bytes_rcvd, uint8_t *dataptr );
// Methods for recieving and sending data
uint8_t RcvData(uint16_t *nbytesptr, uint8_t *dataptr);
@ -201,8 +173,10 @@ public:
virtual uint8_t Init(uint8_t parent, uint8_t port, bool lowspeed);
virtual uint8_t Release();
virtual uint8_t Poll();
virtual uint8_t GetAddress() { return bAddress; };
virtual bool isReady() { return ready; };
virtual uint8_t GetAddress() {
return bAddress;
};
// UsbConfigXtracter implementation
virtual void EndpointXtract(uint8_t conf, uint8_t iface, uint8_t alt, uint8_t proto, const USB_ENDPOINT_DESCRIPTOR *ep);

View file

@ -13,7 +13,7 @@ Contact information
Circuits At Home, LTD
Web : http://www.circuitsathome.com
e-mail : support@circuitsathome.com
*/
*/
#include "cdcftdi.h"
const uint8_t FTDI::epDataInIndex = 1;
@ -21,14 +21,12 @@ const uint8_t FTDI::epDataOutIndex = 2;
const uint8_t FTDI::epInterruptInIndex = 3;
FTDI::FTDI(USB *p, FTDIAsyncOper *pasync) :
pAsync(pasync),
pUsb(p),
bAddress(0),
bNumEP(1),
wFTDIType(0)
{
for(uint8_t i=0; i<FTDI_MAX_ENDPOINTS; i++)
{
pAsync(pasync),
pUsb(p),
bAddress(0),
bNumEP(1),
wFTDIType(0) {
for (uint8_t i = 0; i < FTDI_MAX_ENDPOINTS; i++) {
epInfo[i].epAddr = 0;
epInfo[i].maxPktSize = (i) ? 0 : 8;
epInfo[i].epAttribs = 0;
@ -40,19 +38,18 @@ FTDI::FTDI(USB *p, FTDIAsyncOper *pasync) :
pUsb->RegisterDeviceClass(this);
}
uint8_t FTDI::Init(uint8_t parent, uint8_t port, bool lowspeed)
{
const uint8_t constBufSize = sizeof(USB_DEVICE_DESCRIPTOR);
uint8_t FTDI::Init(uint8_t parent, uint8_t port, bool lowspeed) {
const uint8_t constBufSize = sizeof (USB_DEVICE_DESCRIPTOR);
uint8_t buf[constBufSize];
uint8_t rcode;
UsbDevice *p = NULL;
EpInfo *oldep_ptr = NULL;
uint8_t len = 0;
uint16_t cd_len = 0;
//uint8_t len = 0;
//uint16_t cd_len = 0;
uint8_t num_of_conf; // number of configurations
uint8_t num_of_intf; // number of interfaces
//uint8_t num_of_intf; // number of interfaces
AddressPool &addrPool = pUsb->GetAddressPool();
@ -67,8 +64,7 @@ uint8_t FTDI::Init(uint8_t parent, uint8_t port, bool lowspeed)
if (!p)
return USB_ERROR_ADDRESS_NOT_FOUND_IN_POOL;
if (!p->epinfo)
{
if (!p->epinfo) {
USBTRACE("epinfo\r\n");
return USB_ERROR_EPINFO_IS_NULL;
}
@ -82,12 +78,12 @@ uint8_t FTDI::Init(uint8_t parent, uint8_t port, bool lowspeed)
p->lowspeed = lowspeed;
// Get device descriptor
rcode = pUsb->getDevDescr( 0, 0, sizeof(USB_DEVICE_DESCRIPTOR), (uint8_t*)buf );
rcode = pUsb->getDevDescr(0, 0, sizeof (USB_DEVICE_DESCRIPTOR), (uint8_t*)buf);
// Restore p->epinfo
p->epinfo = oldep_ptr;
if( rcode )
if (rcode)
goto FailGetDevDescr;
if (((USB_DEVICE_DESCRIPTOR*)buf)->idVendor != FTDI_VID || ((USB_DEVICE_DESCRIPTOR*)buf)->idProduct != FTDI_PID)
@ -106,14 +102,13 @@ uint8_t FTDI::Init(uint8_t parent, uint8_t port, bool lowspeed)
epInfo[0].maxPktSize = (uint8_t)((USB_DEVICE_DESCRIPTOR*)buf)->bMaxPacketSize0;
// Assign new address to the device
rcode = pUsb->setAddr( 0, 0, bAddress );
rcode = pUsb->setAddr(0, 0, bAddress);
if (rcode)
{
if (rcode) {
p->lowspeed = false;
addrPool.FreeAddress(bAddress);
bAddress = 0;
USBTRACE2("setAddr:",rcode);
USBTRACE2("setAddr:", rcode);
return rcode;
}
@ -138,14 +133,20 @@ uint8_t FTDI::Init(uint8_t parent, uint8_t port, bool lowspeed)
USBTRACE2("NC:", num_of_conf);
for (uint8_t i=0; i<num_of_conf; i++)
{
for (uint8_t i = 0; i < num_of_conf; i++) {
HexDumper<USBReadParser, uint16_t, uint16_t> HexDump;
ConfigDescParser<0xFF, 0xFF, 0xFF, CP_MASK_COMPARE_ALL> confDescrParser(this);
ConfigDescParser < 0xFF, 0xFF, 0xFF, CP_MASK_COMPARE_ALL> confDescrParser(this);
rcode = pUsb->getConfDescr(bAddress, 0, i, &HexDump);
if (rcode)
goto FailGetConfDescr;
rcode = pUsb->getConfDescr(bAddress, 0, i, &confDescrParser);
if (rcode)
goto FailGetConfDescr;
if (bNumEP > 1)
break;
} // for
@ -192,30 +193,22 @@ FailSetConfDescr:
USBTRACE("setConf:");
goto Fail;
FailSetBaudRate:
USBTRACE("SetBaudRate:");
goto Fail;
FailSetFlowControl:
USBTRACE("SetFlowControl:");
goto Fail;
FailOnInit:
USBTRACE("OnInit:");
goto Fail;
Fail:
Serial.println(rcode, HEX);
PrintHex<uint8_t > (rcode, 0x80);
Notify(PSTR("\r\n"), 0x80);
//Serial.println(rcode, HEX);
Release();
return rcode;
}
void FTDI::EndpointXtract(uint8_t conf, uint8_t iface, uint8_t alt, uint8_t proto, const USB_ENDPOINT_DESCRIPTOR *pep)
{
ErrorMessage<uint8_t>(PSTR("Conf.Val"), conf);
ErrorMessage<uint8_t>(PSTR("Iface Num"),iface);
ErrorMessage<uint8_t>(PSTR("Alt.Set"), alt);
void FTDI::EndpointXtract(uint8_t conf, uint8_t iface, uint8_t alt, uint8_t proto, const USB_ENDPOINT_DESCRIPTOR *pep) {
ErrorMessage<uint8_t > (PSTR("Conf.Val"), conf);
ErrorMessage<uint8_t > (PSTR("Iface Num"), iface);
ErrorMessage<uint8_t > (PSTR("Alt.Set"), alt);
bConfNum = conf;
@ -232,15 +225,14 @@ void FTDI::EndpointXtract(uint8_t conf, uint8_t iface, uint8_t alt, uint8_t prot
// Fill in the endpoint info structure
epInfo[index].epAddr = (pep->bEndpointAddress & 0x0F);
epInfo[index].maxPktSize = (uint8_t)pep->wMaxPacketSize;
//epInfo[index].epAttribs = 0;
epInfo[index].epAttribs = 0;
bNumEP ++;
bNumEP++;
PrintEndpointDescriptor(pep);
}
uint8_t FTDI::Release()
{
uint8_t FTDI::Release() {
pUsb->GetAddressPool().FreeAddress(bAddress);
bAddress = 0;
@ -250,8 +242,7 @@ uint8_t FTDI::Release()
return 0;
}
uint8_t FTDI::Poll()
{
uint8_t FTDI::Poll() {
uint8_t rcode = 0;
//if (!bPollEnable)
@ -266,83 +257,76 @@ uint8_t FTDI::Poll()
return rcode;
}
uint8_t FTDI::SetBaudRate(uint32_t baud)
{
uint8_t FTDI::SetBaudRate(uint32_t baud) {
uint16_t baud_value, baud_index = 0;
uint32_t divisor3;
divisor3 = 48000000 / 2 / baud; // divisor shifted 3 bits to the left
if (wFTDIType == FT232AM)
{
if (wFTDIType == FT232AM) {
if ((divisor3 & 0x7) == 7)
divisor3 ++; // round x.7/8 up to x+1
divisor3++; // round x.7/8 up to x+1
baud_value = divisor3 >> 3;
divisor3 &= 0x7;
if (divisor3 == 1) baud_value |= 0xc000; else // 0.125
if (divisor3 >= 4) baud_value |= 0x4000; else // 0.5
if (divisor3 == 1) baud_value |= 0xc000;
else // 0.125
if (divisor3 >= 4) baud_value |= 0x4000;
else // 0.5
if (divisor3 != 0) baud_value |= 0x8000; // 0.25
if (baud_value == 1) baud_value = 0; /* special case for maximum baud rate */
}
else
{
static const unsigned char divfrac [8] = { 0, 3, 2, 0, 1, 1, 2, 3 };
static const unsigned char divindex[8] = { 0, 0, 0, 1, 0, 1, 1, 1 };
} else {
static const unsigned char divfrac [8] = {0, 3, 2, 0, 1, 1, 2, 3};
static const unsigned char divindex[8] = {0, 0, 0, 1, 0, 1, 1, 1};
baud_value = divisor3 >> 3;
baud_value |= divfrac [divisor3 & 0x7] << 14;
baud_index = divindex[divisor3 & 0x7];
/* Deal with special cases for highest baud rates. */
if (baud_value == 1) baud_value = 0; else // 1.0
if (baud_value == 1) baud_value = 0;
else // 1.0
if (baud_value == 0x4001) baud_value = 1; // 1.5
}
USBTRACE2("baud_value:", baud_value);
USBTRACE2("baud_index:", baud_index);
return pUsb->ctrlReq(bAddress, 0, bmREQ_FTDI_OUT, FTDI_SIO_SET_BAUD_RATE, baud_value & 0xff, baud_value >> 8, baud_index, 0, 0, NULL, NULL );
return pUsb->ctrlReq(bAddress, 0, bmREQ_FTDI_OUT, FTDI_SIO_SET_BAUD_RATE, baud_value & 0xff, baud_value >> 8, baud_index, 0, 0, NULL, NULL);
}
uint8_t FTDI::SetModemControl(uint16_t signal)
{
uint8_t FTDI::SetModemControl(uint16_t signal) {
return pUsb->ctrlReq(bAddress, 0, bmREQ_FTDI_OUT, FTDI_SIO_MODEM_CTRL, signal & 0xff, signal >> 8, 0, 0, 0, NULL, NULL);
}
uint8_t FTDI::SetFlowControl(uint8_t protocol, uint8_t xon, uint8_t xoff)
{
uint8_t FTDI::SetFlowControl(uint8_t protocol, uint8_t xon, uint8_t xoff) {
return pUsb->ctrlReq(bAddress, 0, bmREQ_FTDI_OUT, FTDI_SIO_SET_FLOW_CTRL, xon, xoff, protocol << 8, 0, 0, NULL, NULL);
}
uint8_t FTDI::SetData(uint16_t databm)
{
uint8_t FTDI::SetData(uint16_t databm) {
return pUsb->ctrlReq(bAddress, 0, bmREQ_FTDI_OUT, FTDI_SIO_SET_DATA, databm & 0xff, databm >> 8, 0, 0, 0, NULL, NULL);
}
uint8_t FTDI::RcvData(uint16_t *bytes_rcvd, uint8_t *dataptr)
{
uint8_t FTDI::RcvData(uint16_t *bytes_rcvd, uint8_t *dataptr) {
return pUsb->inTransfer(bAddress, epInfo[epDataInIndex].epAddr, bytes_rcvd, dataptr);
}
uint8_t FTDI::SndData(uint16_t nbytes, uint8_t *dataptr)
{
uint8_t FTDI::SndData(uint16_t nbytes, uint8_t *dataptr) {
return pUsb->outTransfer(bAddress, epInfo[epDataOutIndex].epAddr, nbytes, dataptr);
}
void FTDI::PrintEndpointDescriptor( const USB_ENDPOINT_DESCRIPTOR* ep_ptr )
{
Notify(PSTR("Endpoint descriptor:"));
Notify(PSTR("\r\nLength:\t\t"));
PrintHex<uint8_t>(ep_ptr->bLength);
Notify(PSTR("\r\nType:\t\t"));
PrintHex<uint8_t>(ep_ptr->bDescriptorType);
Notify(PSTR("\r\nAddress:\t"));
PrintHex<uint8_t>(ep_ptr->bEndpointAddress);
Notify(PSTR("\r\nAttributes:\t"));
PrintHex<uint8_t>(ep_ptr->bmAttributes);
Notify(PSTR("\r\nMaxPktSize:\t"));
PrintHex<uint16_t>(ep_ptr->wMaxPacketSize);
Notify(PSTR("\r\nPoll Intrv:\t"));
PrintHex<uint8_t>(ep_ptr->bInterval);
Notify(PSTR("\r\n"));
void FTDI::PrintEndpointDescriptor(const USB_ENDPOINT_DESCRIPTOR* ep_ptr) {
Notify(PSTR("Endpoint descriptor:"), 0x80);
Notify(PSTR("\r\nLength:\t\t"), 0x80);
PrintHex<uint8_t > (ep_ptr->bLength, 0x80);
Notify(PSTR("\r\nType:\t\t"), 0x80);
PrintHex<uint8_t > (ep_ptr->bDescriptorType, 0x80);
Notify(PSTR("\r\nAddress:\t"), 0x80);
PrintHex<uint8_t > (ep_ptr->bEndpointAddress, 0x80);
Notify(PSTR("\r\nAttributes:\t"), 0x80);
PrintHex<uint8_t > (ep_ptr->bmAttributes, 0x80);
Notify(PSTR("\r\nMaxPktSize:\t"), 0x80);
PrintHex<uint16_t > (ep_ptr->wMaxPacketSize, 0x80);
Notify(PSTR("\r\nPoll Intrv:\t"), 0x80);
PrintHex<uint8_t > (ep_ptr->bInterval, 0x80);
Notify(PSTR("\r\n"), 0x80);
}

View file

@ -13,7 +13,7 @@ Contact information
Circuits At Home, LTD
Web : http://www.circuitsathome.com
e-mail : support@circuitsathome.com
*/
*/
#if !defined(__CDCFTDI_H__)
#define __CDCFTDI_H__
@ -94,8 +94,7 @@ e-mail : support@circuitsathome.com
class FTDI;
class FTDIAsyncOper
{
class FTDIAsyncOper {
public:
virtual uint8_t OnInit(FTDI *pftdi) = 0;
};
@ -105,8 +104,7 @@ public:
// so only three endpoints are allocated.
#define FTDI_MAX_ENDPOINTS 3
class FTDI : public USBDeviceConfig, public UsbConfigXtracter
{
class FTDI : public USBDeviceConfig, public UsbConfigXtracter {
static const uint8_t epDataInIndex; // DataIn endpoint index
static const uint8_t epDataOutIndex; // DataOUT endpoint index
static const uint8_t epInterruptInIndex; // InterruptIN endpoint index
@ -141,7 +139,10 @@ public:
virtual uint8_t Init(uint8_t parent, uint8_t port, bool lowspeed);
virtual uint8_t Release();
virtual uint8_t Poll();
virtual uint8_t GetAddress() { return bAddress; };
virtual uint8_t GetAddress() {
return bAddress;
};
// UsbConfigXtracter implementation
virtual void EndpointXtract(uint8_t conf, uint8_t iface, uint8_t alt, uint8_t proto, const USB_ENDPOINT_DESCRIPTOR *ep);

View file

@ -13,25 +13,22 @@ Contact information
Circuits At Home, LTD
Web : http://www.circuitsathome.com
e-mail : support@circuitsathome.com
*/
*/
#include "cdcprolific.h"
PL2303::PL2303(USB *p, CDCAsyncOper *pasync) :
ACM(p, pasync)
//wPLType(0)
{
ACM(p, pasync),
wPLType(0) {
}
uint8_t PL2303::Init(uint8_t parent, uint8_t port, bool lowspeed)
{
const uint8_t constBufSize = sizeof(USB_DEVICE_DESCRIPTOR);
uint8_t PL2303::Init(uint8_t parent, uint8_t port, bool lowspeed) {
const uint8_t constBufSize = sizeof (USB_DEVICE_DESCRIPTOR);
uint8_t buf[constBufSize];
uint8_t rcode;
UsbDevice *p = NULL;
EpInfo *oldep_ptr = NULL;
uint8_t num_of_conf; // number of configurations
enum pl2303_type pltype = unknown;
AddressPool &addrPool = pUsb->GetAddressPool();
@ -46,8 +43,7 @@ uint8_t PL2303::Init(uint8_t parent, uint8_t port, bool lowspeed)
if (!p)
return USB_ERROR_ADDRESS_NOT_FOUND_IN_POOL;
if (!p->epinfo)
{
if (!p->epinfo) {
USBTRACE("epinfo\r\n");
return USB_ERROR_EPINFO_IS_NULL;
}
@ -61,32 +57,19 @@ uint8_t PL2303::Init(uint8_t parent, uint8_t port, bool lowspeed)
p->lowspeed = lowspeed;
// Get device descriptor
rcode = pUsb->getDevDescr( 0, 0, sizeof(USB_DEVICE_DESCRIPTOR), (uint8_t*)buf );
rcode = pUsb->getDevDescr(0, 0, sizeof (USB_DEVICE_DESCRIPTOR), (uint8_t*)buf);
// Restore p->epinfo
p->epinfo = oldep_ptr;
if( rcode )
if (rcode)
goto FailGetDevDescr;
if (((USB_DEVICE_DESCRIPTOR*)buf)->idVendor != PL_VID && ((USB_DEVICE_DESCRIPTOR*)buf)->idProduct != PL_PID ) {
if (((USB_DEVICE_DESCRIPTOR*)buf)->idVendor != PL_VID && ((USB_DEVICE_DESCRIPTOR*)buf)->idProduct != PL_PID)
return USB_DEV_CONFIG_ERROR_DEVICE_NOT_SUPPORTED;
}
/* determine chip variant */
if (((USB_DEVICE_DESCRIPTOR*)buf)->bDeviceClass == 0x02 ) {
pltype = type_0;
}
else if (((USB_DEVICE_DESCRIPTOR*)buf)->bMaxPacketSize0 == 0x40 ) {
pltype = rev_HX;
}
else if (((USB_DEVICE_DESCRIPTOR*)buf)->bDeviceClass == 0x00) {
pltype = type_1;
}
else if (((USB_DEVICE_DESCRIPTOR*)buf)->bDeviceClass == 0xff) {
pltype = type_1;
}
// Save type of PL chip
wPLType = ((USB_DEVICE_DESCRIPTOR*)buf)->bcdDevice;
// Allocate new address according to device class
bAddress = addrPool.AllocAddress(parent, false, port);
@ -98,14 +81,13 @@ uint8_t PL2303::Init(uint8_t parent, uint8_t port, bool lowspeed)
epInfo[0].maxPktSize = (uint8_t)((USB_DEVICE_DESCRIPTOR*)buf)->bMaxPacketSize0;
// Assign new address to the device
rcode = pUsb->setAddr( 0, 0, bAddress );
rcode = pUsb->setAddr(0, 0, bAddress);
if (rcode)
{
if (rcode) {
p->lowspeed = false;
addrPool.FreeAddress(bAddress);
bAddress = 0;
USBTRACE2("setAddr:",rcode);
USBTRACE2("setAddr:", rcode);
return rcode;
}
@ -130,23 +112,29 @@ uint8_t PL2303::Init(uint8_t parent, uint8_t port, bool lowspeed)
USBTRACE2("NC:", num_of_conf);
for( uint8_t i=0; i<num_of_conf; i++ )
{
//HexDumper<USBReadParser, uint16_t, uint16_t> HexDump;
ConfigDescParser<0xFF, 0, 0, CP_MASK_COMPARE_CLASS> confDescrParser(this);
for (uint8_t i = 0; i < num_of_conf; i++) {
HexDumper<USBReadParser, uint16_t, uint16_t> HexDump;
ConfigDescParser < 0xFF, 0, 0, CP_MASK_COMPARE_CLASS> confDescrParser(this);
rcode = pUsb->getConfDescr(bAddress, 0, i, &HexDump);
if (rcode)
goto FailGetConfDescr;
//rcode = pUsb->getConfDescr(bAddress, 0, i, &HexDump);
rcode = pUsb->getConfDescr(bAddress, 0, i, &confDescrParser);
if (rcode)
goto FailGetConfDescr;
if (bNumEP > 1)
break;
} // for
if ( bNumEP < 2 )
if (bNumEP < 2)
return USB_DEV_CONFIG_ERROR_DEVICE_NOT_SUPPORTED;
// Assign epInfo to epinfo pointer
rcode = pUsb->setEpInfoEntry( bAddress, bNumEP, epInfo );
rcode = pUsb->setEpInfoEntry(bAddress, bNumEP, epInfo);
USBTRACE2("Conf:", bConfNum);
@ -156,29 +144,6 @@ uint8_t PL2303::Init(uint8_t parent, uint8_t port, bool lowspeed)
if (rcode)
goto FailSetConfDescr;
#if defined(PL2303_COMPAT)
/* shamanic dance - sending Prolific init data as-is */
vendorRead( 0x84, 0x84, 0, buf );
vendorWrite( 0x04, 0x04, 0 );
vendorRead( 0x84, 0x84, 0, buf );
vendorRead( 0x83, 0x83, 0, buf );
vendorRead( 0x84, 0x84, 0, buf );
vendorWrite( 0x04, 0x04, 1 );
vendorRead( 0x84, 0x84, 0, buf);
vendorRead( 0x83, 0x83, 0, buf);
vendorWrite( 0, 0, 1 );
vendorWrite( 1, 0, 0 );
if ( pltype == rev_HX ) {
vendorWrite( 2, 0, 0x44 );
vendorWrite( 0x06, 0x06, 0 ); //from W7 init
}
else {
vendorWrite( 2, 0, 0x24 );
}
/* shamanic dance end */
#endif
/* calling post-init callback */
rcode = pAsync->OnInit(this);
if (rcode)
@ -186,8 +151,7 @@ uint8_t PL2303::Init(uint8_t parent, uint8_t port, bool lowspeed)
USBTRACE("PL configured\r\n");
//bPollEnable = true;
ready = true;
bPollEnable = true;
return 0;
FailGetDevDescr:
@ -206,20 +170,14 @@ FailSetConfDescr:
USBTRACE("setConf:");
goto Fail;
FailSetControlLineState:
USBTRACE("SetControlLineState:");
goto Fail;
FailSetLineCoding:
USBTRACE("SetLineCoding:");
goto Fail;
FailOnInit:
USBTRACE("OnInit:");
goto Fail;
Fail:
Serial.println(rcode, HEX);
PrintHex<uint8_t > (rcode, 0x80);
Notify(PSTR("\r\n"), 0x80);
//Serial.println(rcode, HEX);
Release();
return rcode;
}

View file

@ -13,7 +13,7 @@ Contact information
Circuits At Home, LTD
Web : http://www.circuitsathome.com
e-mail : support@circuitsathome.com
*/
*/
#if !defined(__CDCPROLIFIC_H__)
#define __CDCPROLIFIC_H__
@ -38,11 +38,11 @@ e-mail : support@circuitsathome.com
#include "confdescparser.h"
#include "cdcacm.h"
//#define PL2303_COMPAT //uncomment it if you have compatibility problems
#define PL_VID 0x067B
#define PL_PID ( 0x2303 || 0x0609 )
//#define PL_PID 0x0609
#define PROLIFIC_REV_H 0x0202
#define PROLIFIC_REV_X 0x0300
#define PROLIFIC_REV_HX_CHIP_D 0x0400
@ -76,15 +76,13 @@ e-mail : support@circuitsathome.com
#define kCONTROL_DTR 0x01
#define kCONTROL_RTS 0x02
enum tXO_State
{
enum tXO_State {
kXOnSent = -2,
kXOffSent = -1,
kXO_Idle = 0,
kXOffNeeded = 1,
kXOnNeeded = 2
} ;
};
#define kStateTransientMask 0x74
#define kBreakError 0x04
@ -125,10 +123,8 @@ enum tXO_State
#define RESET_DOWNSTREAM_DATA_PIPE 0x08
#define RESET_UPSTREAM_DATA_PIPE 0x09
enum pl2303_type
{
enum pl2303_type {
unknown,
type_0,
type_1, /* don't know the difference between type 0 and */
rev_X, /* type 1, until someone from prolific tells us... */
rev_HX, /* HX version of the pl2303 chip */
@ -138,13 +134,8 @@ enum pl2303_type
#define PL_MAX_ENDPOINTS 4
//class PL2303;
class PL2303 : public ACM
{
//uint16_t wPLType; // Type of chip
class PL2303 : public ACM {
uint16_t wPLType; // Type of chip
public:
PL2303(USB *pusb, CDCAsyncOper *pasync);
@ -157,23 +148,6 @@ public:
//// UsbConfigXtracter implementation
//virtual void EndpointXtract(uint8_t conf, uint8_t iface, uint8_t alt, uint8_t proto, const USB_ENDPOINT_DESCRIPTOR *ep);
private:
/* Prolific proprietary requests */
uint8_t vendorRead( uint8_t val_lo, uint8_t val_hi, uint16_t index, uint8_t* buf );
uint8_t vendorWrite( uint8_t val_lo, uint8_t val_hi, uint8_t index );
};
/* vendor read request */
inline uint8_t PL2303::vendorRead( uint8_t val_lo, uint8_t val_hi, uint16_t index, uint8_t* buf )
{
return( pUsb->ctrlReq(bAddress, 0, VENDOR_READ_REQUEST_TYPE, VENDOR_READ_REQUEST, val_lo, val_hi, index, 1, 1, buf, NULL ));
}
/* vendor write request */
inline uint8_t PL2303::vendorWrite( uint8_t val_lo, uint8_t val_hi, uint8_t index )
{
return( pUsb->ctrlReq(bAddress, 0, VENDOR_WRITE_REQUEST_TYPE, VENDOR_WRITE_REQUEST, val_lo, val_hi, index, 0, 0, NULL, NULL ));
}
#endif // __CDCPROLIFIC_H__

View file

@ -13,7 +13,7 @@ Contact information
Circuits At Home, LTD
Web : http://www.circuitsathome.com
e-mail : support@circuitsathome.com
*/
*/
#if !defined(__CONFDESCPARSER_H__)
#define __CONFDESCPARSER_H__
@ -27,8 +27,7 @@ e-mail : support@circuitsathome.com
//#include "hid.h"
class UsbConfigXtracter
{
class UsbConfigXtracter {
public:
//virtual void ConfigXtract(const USB_CONFIGURATION_DESCRIPTOR *conf) = 0;
//virtual void InterfaceXtract(uint8_t conf, const USB_INTERFACE_DESCRIPTOR *iface) = 0;
@ -41,9 +40,9 @@ public:
#define CP_MASK_COMPARE_ALL 7
// Configuration Descriptor Parser Class Template
template <const uint8_t CLASS_ID, const uint8_t SUBCLASS_ID, const uint8_t PROTOCOL_ID, const uint8_t MASK>
class ConfigDescParser : public USBReadParser
{
class ConfigDescParser : public USBReadParser {
UsbConfigXtracter *theXtractor;
MultiValueBuffer theBuffer;
MultiByteValueParser valParser;
@ -72,45 +71,42 @@ public:
template <const uint8_t CLASS_ID, const uint8_t SUBCLASS_ID, const uint8_t PROTOCOL_ID, const uint8_t MASK>
ConfigDescParser<CLASS_ID, SUBCLASS_ID, PROTOCOL_ID, MASK>::ConfigDescParser(UsbConfigXtracter *xtractor) :
stateParseDescr(0),
dscrLen(0),
dscrType(0),
theXtractor(xtractor)
{
theXtractor(xtractor),
stateParseDescr(0),
dscrLen(0),
dscrType(0) {
theBuffer.pValue = varBuffer;
valParser.Initialize(&theBuffer);
theSkipper.Initialize(&theBuffer);
};
template <const uint8_t CLASS_ID, const uint8_t SUBCLASS_ID, const uint8_t PROTOCOL_ID, const uint8_t MASK>
void ConfigDescParser<CLASS_ID, SUBCLASS_ID, PROTOCOL_ID, MASK>::Parse(const uint16_t len, const uint8_t *pbuf, const uint16_t &offset)
{
uint16_t cntdn = (uint16_t)len;
uint8_t *p = (uint8_t*)pbuf;
void ConfigDescParser<CLASS_ID, SUBCLASS_ID, PROTOCOL_ID, MASK>::Parse(const uint16_t len, const uint8_t *pbuf, const uint16_t &offset) {
uint16_t cntdn = (uint16_t) len;
uint8_t *p = (uint8_t*) pbuf;
while(cntdn)
if (!ParseDescriptor(&p, &cntdn))
if(!ParseDescriptor(&p, &cntdn))
return;
}
/* Parser for the configuration descriptor. Takes values for class, subclass, protocol fields in interface descriptor and
compare masks for them. When the match is found, calls EndpointXtract passing buffer containing endpoint descriptor */
template <const uint8_t CLASS_ID, const uint8_t SUBCLASS_ID, const uint8_t PROTOCOL_ID, const uint8_t MASK>
bool ConfigDescParser<CLASS_ID, SUBCLASS_ID, PROTOCOL_ID, MASK>::ParseDescriptor(uint8_t **pp, uint16_t *pcntdn)
{
switch (stateParseDescr)
{
bool ConfigDescParser<CLASS_ID, SUBCLASS_ID, PROTOCOL_ID, MASK>::ParseDescriptor(uint8_t **pp, uint16_t *pcntdn) {
switch(stateParseDescr) {
case 0:
theBuffer.valueSize = 2;
valParser.Initialize(&theBuffer);
stateParseDescr = 1;
case 1:
if (!valParser.Parse(pp, pcntdn))
if(!valParser.Parse(pp, pcntdn))
return false;
dscrLen = *((uint8_t*)theBuffer.pValue);
dscrType = *((uint8_t*)theBuffer.pValue + 1);
dscrLen = *((uint8_t*) theBuffer.pValue);
dscrType = *((uint8_t*) theBuffer.pValue + 1);
stateParseDescr = 2;
case 2:
// This is a sort of hack. Assuming that two bytes are already in the buffer
// This is a sort of hack. Assuming that two bytes are allready in the buffer
// the pointer is positioned two bytes ahead in order for the rest of descriptor
// to be read right after the size and the type fields.
// This should be used carefuly. varBuffer should be used directly to handle data
@ -118,8 +114,7 @@ bool ConfigDescParser<CLASS_ID, SUBCLASS_ID, PROTOCOL_ID, MASK>::ParseDescriptor
theBuffer.pValue = varBuffer + 2;
stateParseDescr = 3;
case 3:
switch (dscrType)
{
switch(dscrType) {
case USB_DESCRIPTOR_INTERFACE:
isGoodInterface = false;
case USB_DESCRIPTOR_CONFIGURATION:
@ -135,34 +130,33 @@ bool ConfigDescParser<CLASS_ID, SUBCLASS_ID, PROTOCOL_ID, MASK>::ParseDescriptor
valParser.Initialize(&theBuffer);
stateParseDescr = 4;
case 4:
switch (dscrType)
{
switch(dscrType) {
case USB_DESCRIPTOR_CONFIGURATION:
if (!valParser.Parse(pp, pcntdn))
if(!valParser.Parse(pp, pcntdn))
return false;
confValue = ((USB_CONFIGURATION_DESCRIPTOR*)varBuffer)->bConfigurationValue;
confValue = ((USB_CONFIGURATION_DESCRIPTOR*) varBuffer)->bConfigurationValue;
break;
case USB_DESCRIPTOR_INTERFACE:
if (!valParser.Parse(pp, pcntdn))
if(!valParser.Parse(pp, pcntdn))
return false;
if ((MASK & CP_MASK_COMPARE_CLASS) && ((USB_INTERFACE_DESCRIPTOR*)varBuffer)->bInterfaceClass != CLASS_ID)
if((MASK & CP_MASK_COMPARE_CLASS) && ((USB_INTERFACE_DESCRIPTOR*) varBuffer)->bInterfaceClass != CLASS_ID)
break;
if ((MASK & CP_MASK_COMPARE_SUBCLASS) && ((USB_INTERFACE_DESCRIPTOR*)varBuffer)->bInterfaceSubClass != SUBCLASS_ID)
if((MASK & CP_MASK_COMPARE_SUBCLASS) && ((USB_INTERFACE_DESCRIPTOR*) varBuffer)->bInterfaceSubClass != SUBCLASS_ID)
break;
if ((MASK & CP_MASK_COMPARE_PROTOCOL) && ((USB_INTERFACE_DESCRIPTOR*)varBuffer)->bInterfaceProtocol != PROTOCOL_ID)
if((MASK & CP_MASK_COMPARE_PROTOCOL) && ((USB_INTERFACE_DESCRIPTOR*) varBuffer)->bInterfaceProtocol != PROTOCOL_ID)
break;
isGoodInterface = true;
ifaceNumber = ((USB_INTERFACE_DESCRIPTOR*)varBuffer)->bInterfaceNumber;
ifaceAltSet = ((USB_INTERFACE_DESCRIPTOR*)varBuffer)->bAlternateSetting;
protoValue = ((USB_INTERFACE_DESCRIPTOR*)varBuffer)->bInterfaceProtocol;
ifaceNumber = ((USB_INTERFACE_DESCRIPTOR*) varBuffer)->bInterfaceNumber;
ifaceAltSet = ((USB_INTERFACE_DESCRIPTOR*) varBuffer)->bAlternateSetting;
protoValue = ((USB_INTERFACE_DESCRIPTOR*) varBuffer)->bInterfaceProtocol;
break;
case USB_DESCRIPTOR_ENDPOINT:
if (!valParser.Parse(pp, pcntdn))
if(!valParser.Parse(pp, pcntdn))
return false;
if (isGoodInterface)
if (theXtractor)
theXtractor->EndpointXtract(confValue, ifaceNumber, ifaceAltSet, protoValue, (USB_ENDPOINT_DESCRIPTOR*)varBuffer);
if(isGoodInterface)
if(theXtractor)
theXtractor->EndpointXtract(confValue, ifaceNumber, ifaceAltSet, protoValue, (USB_ENDPOINT_DESCRIPTOR*) varBuffer);
break;
//case HID_DESCRIPTOR_HID:
// if (!valParser.Parse(pp, pcntdn))
@ -170,7 +164,7 @@ bool ConfigDescParser<CLASS_ID, SUBCLASS_ID, PROTOCOL_ID, MASK>::ParseDescriptor
// PrintHidDescriptor((const USB_HID_DESCRIPTOR*)varBuffer);
// break;
default:
if (!theSkipper.Skip(pp, pcntdn, dscrLen-2))
if(!theSkipper.Skip(pp, pcntdn, dscrLen - 2))
return false;
}
theBuffer.pValue = varBuffer;
@ -180,23 +174,22 @@ bool ConfigDescParser<CLASS_ID, SUBCLASS_ID, PROTOCOL_ID, MASK>::ParseDescriptor
}
template <const uint8_t CLASS_ID, const uint8_t SUBCLASS_ID, const uint8_t PROTOCOL_ID, const uint8_t MASK>
void ConfigDescParser<CLASS_ID, SUBCLASS_ID, PROTOCOL_ID, MASK>::PrintHidDescriptor(const USB_HID_DESCRIPTOR *pDesc)
{
Notify(PSTR("\r\n\r\nHID Descriptor:\r\n"));
Notify(PSTR("bDescLength:\t\t"));
PrintHex<uint8_t>(pDesc->bLength);
void ConfigDescParser<CLASS_ID, SUBCLASS_ID, PROTOCOL_ID, MASK>::PrintHidDescriptor(const USB_HID_DESCRIPTOR *pDesc) {
Notify(PSTR("\r\n\r\nHID Descriptor:\r\n"), 0x80);
Notify(PSTR("bDescLength:\t\t"), 0x80);
PrintHex<uint8_t > (pDesc->bLength, 0x80);
Notify(PSTR("\r\nbDescriptorType:\t"));
PrintHex<uint8_t>(pDesc->bDescriptorType);
Notify(PSTR("\r\nbDescriptorType:\t"), 0x80);
PrintHex<uint8_t > (pDesc->bDescriptorType, 0x80);
Notify(PSTR("\r\nbcdHID:\t\t\t"));
PrintHex<uint16_t>(pDesc->bcdHID);
Notify(PSTR("\r\nbcdHID:\t\t\t"), 0x80);
PrintHex<uint16_t > (pDesc->bcdHID, 0x80);
Notify(PSTR("\r\nbCountryCode:\t\t"));
PrintHex<uint8_t>(pDesc->bCountryCode);
Notify(PSTR("\r\nbCountryCode:\t\t"), 0x80);
PrintHex<uint8_t > (pDesc->bCountryCode, 0x80);
Notify(PSTR("\r\nbNumDescriptors:\t"));
PrintHex<uint8_t>(pDesc->bNumDescriptors);
Notify(PSTR("\r\nbNumDescriptors:\t"), 0x80);
PrintHex<uint8_t > (pDesc->bNumDescriptors, 0x80);
//Notify(PSTR("\r\nbDescrType:\t\t"));
//PrintHex<uint8_t>(pDesc->bDescrType);
@ -204,17 +197,16 @@ void ConfigDescParser<CLASS_ID, SUBCLASS_ID, PROTOCOL_ID, MASK>::PrintHidDescrip
//Notify(PSTR("\r\nwDescriptorLength:\t"));
//PrintHex<uint16_t>(pDesc->wDescriptorLength);
for (uint8_t i=0; i<pDesc->bNumDescriptors; i++)
{
for(uint8_t i = 0; i < pDesc->bNumDescriptors; i++) {
HID_CLASS_DESCRIPTOR_LEN_AND_TYPE *pLT = (HID_CLASS_DESCRIPTOR_LEN_AND_TYPE*)&(pDesc->bDescrType);
Notify(PSTR("\r\nbDescrType:\t\t"));
PrintHex<uint8_t>(pLT[i].bDescrType);
Notify(PSTR("\r\nbDescrType:\t\t"), 0x80);
PrintHex<uint8_t > (pLT[i].bDescrType, 0x80);
Notify(PSTR("\r\nwDescriptorLength:\t"));
PrintHex<uint16_t>(pLT[i].wDescriptorLength);
Notify(PSTR("\r\nwDescriptorLength:\t"), 0x80);
PrintHex<uint16_t > (pLT[i].wDescriptorLength, 0x80);
}
Notify(PSTR("\r\n"));
Notify(PSTR("\r\n"), 0x80);
}

View file

@ -21,7 +21,7 @@
/*
This header file is used to store different enums for the controllers,
This is necessary so all the different libraries can be used at once
*/
*/
/** Enum used to turn on the LEDs on the different controllers. */
enum LED {
@ -39,6 +39,7 @@ enum LED {
/** Used to blink all LEDs on the Xbox controller */
ALL = 4,
};
/** This enum is used to read all the different buttons on the different controllers */
enum Button {
/**@{*/
@ -101,6 +102,7 @@ enum Button {
SYNC = 17,
/**@}*/
};
/** Joysticks on the PS3 and Xbox controllers. */
enum AnalogHat {
/** Left joystick x-axis */

View file

@ -13,7 +13,7 @@ Contact information
Circuits At Home, LTD
Web : http://www.circuitsathome.com
e-mail : support@circuitsathome.com
*/
*/
#if !defined(__HEXDUMP_H__)
#define __HEXDUMP_H__
@ -22,33 +22,34 @@ e-mail : support@circuitsathome.com
#include "printhex.h"
template <class BASE_CLASS, class LEN_TYPE, class OFFSET_TYPE>
class HexDumper : public BASE_CLASS
{
class HexDumper : public BASE_CLASS {
uint8_t byteCount;
OFFSET_TYPE byteTotal;
public:
HexDumper() : byteCount(0), byteTotal(0) {};
void Initialize() { byteCount = 0; byteTotal = 0; };
HexDumper() : byteCount(0), byteTotal(0) {
};
void Initialize() {
byteCount = 0;
byteTotal = 0;
};
virtual void Parse(const LEN_TYPE len, const uint8_t *pbuf, const OFFSET_TYPE &offset);
};
template <class BASE_CLASS, class LEN_TYPE, class OFFSET_TYPE>
void HexDumper<BASE_CLASS, LEN_TYPE, OFFSET_TYPE>::Parse(const LEN_TYPE len, const uint8_t *pbuf, const OFFSET_TYPE &offset)
{
for (LEN_TYPE j=0; j<len; j++, byteCount++, byteTotal++)
{
if (!byteCount)
{
PrintHex<OFFSET_TYPE>(byteTotal);
void HexDumper<BASE_CLASS, LEN_TYPE, OFFSET_TYPE>::Parse(const LEN_TYPE len, const uint8_t *pbuf, const OFFSET_TYPE &offset) {
for(LEN_TYPE j = 0; j < len; j++, byteCount++, byteTotal++) {
if(!byteCount) {
SerialPrintHex<OFFSET_TYPE > (byteTotal);
Serial.print(": ");
}
PrintHex<uint8_t>(pbuf[j]);
SerialPrintHex<uint8_t > (pbuf[j]);
Serial.print(" ");
if (byteCount == 15)
{
if(byteCount == 15) {
Serial.println("");
byteCount = 0xFF;
}

128
hid.cpp
View file

@ -1,13 +1,13 @@
#include "hid.h"
//get HID report descriptor
uint8_t HID::GetReportDescr( uint8_t ep, USBReadParser *parser )
{
uint8_t HID::GetReportDescr(uint8_t ep, USBReadParser *parser) {
const uint8_t constBufLen = 64;
uint8_t buf[constBufLen];
uint8_t rcode = pUsb->ctrlReq( bAddress, ep, bmREQ_HIDREPORT, USB_REQUEST_GET_DESCRIPTOR, 0x00,
HID_DESCRIPTOR_REPORT, 0x0000, 128, constBufLen, buf, (USBReadParser*)parser );
uint8_t rcode = pUsb->ctrlReq(bAddress, ep, bmREQ_HIDREPORT, USB_REQUEST_GET_DESCRIPTOR, 0x00,
HID_DESCRIPTOR_REPORT, 0x0000, 128, constBufLen, buf, (USBReadParser*)parser);
//return ((rcode != hrSTALL) ? rcode : 0);
return rcode;
@ -16,69 +16,67 @@ uint8_t HID::GetReportDescr( uint8_t ep, USBReadParser *parser )
//{
// return( pUsb->ctrlReq( bAddress, ep, bmREQ_GET_DESCR, USB_REQUEST_GET_DESCRIPTOR, 0x00, HID_DESCRIPTOR_HID, 0x0000, nbytes, dataptr ));
//}
uint8_t HID::SetReport( uint8_t ep, uint8_t iface, uint8_t report_type, uint8_t report_id, uint16_t nbytes, uint8_t* dataptr )
{
return( pUsb->ctrlReq( bAddress, ep, bmREQ_HIDOUT, HID_REQUEST_SET_REPORT, report_id, report_type, iface, nbytes, nbytes, dataptr, NULL ));
}
uint8_t HID::GetReport( uint8_t ep, uint8_t iface, uint8_t report_type, uint8_t report_id, uint16_t nbytes, uint8_t* dataptr )
{
return( pUsb->ctrlReq( bAddress, ep, bmREQ_HIDIN, HID_REQUEST_GET_REPORT, report_id, report_type, iface, nbytes, nbytes, dataptr, NULL ));
}
uint8_t HID::GetIdle( uint8_t iface, uint8_t reportID, uint8_t* dataptr )
{
return( pUsb->ctrlReq( bAddress, 0, bmREQ_HIDIN, HID_REQUEST_GET_IDLE, reportID, 0, iface, 0x0001, 0x0001, dataptr, NULL ));
}
uint8_t HID::SetIdle( uint8_t iface, uint8_t reportID, uint8_t duration )
{
return( pUsb->ctrlReq( bAddress, 0, bmREQ_HIDOUT, HID_REQUEST_SET_IDLE, reportID, duration, iface, 0x0000, 0x0000, NULL, NULL ));
}
uint8_t HID::SetProtocol( uint8_t iface, uint8_t protocol )
{
return( pUsb->ctrlReq( bAddress, 0, bmREQ_HIDOUT, HID_REQUEST_SET_PROTOCOL, protocol, 0x00, iface, 0x0000, 0x0000, NULL, NULL ));
}
uint8_t HID::GetProtocol( uint8_t iface, uint8_t* dataptr )
{
return( pUsb->ctrlReq( bAddress, 0, bmREQ_HIDIN, HID_REQUEST_GET_PROTOCOL, 0x00, 0x00, iface, 0x0001, 0x0001, dataptr, NULL ));
uint8_t HID::SetReport(uint8_t ep, uint8_t iface, uint8_t report_type, uint8_t report_id, uint16_t nbytes, uint8_t* dataptr) {
return ( pUsb->ctrlReq(bAddress, ep, bmREQ_HIDOUT, HID_REQUEST_SET_REPORT, report_id, report_type, iface, nbytes, nbytes, dataptr, NULL));
}
void HID::PrintEndpointDescriptor( const USB_ENDPOINT_DESCRIPTOR* ep_ptr )
{
Notify(PSTR("Endpoint descriptor:"));
Notify(PSTR("\r\nLength:\t\t"));
PrintHex<uint8_t>(ep_ptr->bLength);
Notify(PSTR("\r\nType:\t\t"));
PrintHex<uint8_t>(ep_ptr->bDescriptorType);
Notify(PSTR("\r\nAddress:\t"));
PrintHex<uint8_t>(ep_ptr->bEndpointAddress);
Notify(PSTR("\r\nAttributes:\t"));
PrintHex<uint8_t>(ep_ptr->bmAttributes);
Notify(PSTR("\r\nMaxPktSize:\t"));
PrintHex<uint16_t>(ep_ptr->wMaxPacketSize);
Notify(PSTR("\r\nPoll Intrv:\t"));
PrintHex<uint8_t>(ep_ptr->bInterval);
uint8_t HID::GetReport(uint8_t ep, uint8_t iface, uint8_t report_type, uint8_t report_id, uint16_t nbytes, uint8_t* dataptr) {
return ( pUsb->ctrlReq(bAddress, ep, bmREQ_HIDIN, HID_REQUEST_GET_REPORT, report_id, report_type, iface, nbytes, nbytes, dataptr, NULL));
}
void HID::PrintHidDescriptor(const USB_HID_DESCRIPTOR *pDesc)
{
Notify(PSTR("\r\n\r\nHID Descriptor:\r\n"));
Notify(PSTR("bDescLength:\t\t"));
PrintHex<uint8_t>(pDesc->bLength);
Notify(PSTR("\r\nbDescriptorType:\t"));
PrintHex<uint8_t>(pDesc->bDescriptorType);
Notify(PSTR("\r\nbcdHID:\t\t\t"));
PrintHex<uint16_t>(pDesc->bcdHID);
Notify(PSTR("\r\nbCountryCode:\t\t"));
PrintHex<uint8_t>(pDesc->bCountryCode);
Notify(PSTR("\r\nbNumDescriptors:\t"));
PrintHex<uint8_t>(pDesc->bNumDescriptors);
Notify(PSTR("\r\nbDescrType:\t\t"));
PrintHex<uint8_t>(pDesc->bDescrType);
Notify(PSTR("\r\nwDescriptorLength:\t"));
PrintHex<uint16_t>(pDesc->wDescriptorLength);
uint8_t HID::GetIdle(uint8_t iface, uint8_t reportID, uint8_t* dataptr) {
return ( pUsb->ctrlReq(bAddress, 0, bmREQ_HIDIN, HID_REQUEST_GET_IDLE, reportID, 0, iface, 0x0001, 0x0001, dataptr, NULL));
}
uint8_t HID::SetIdle(uint8_t iface, uint8_t reportID, uint8_t duration) {
return ( pUsb->ctrlReq(bAddress, 0, bmREQ_HIDOUT, HID_REQUEST_SET_IDLE, reportID, duration, iface, 0x0000, 0x0000, NULL, NULL));
}
uint8_t HID::SetProtocol(uint8_t iface, uint8_t protocol) {
return ( pUsb->ctrlReq(bAddress, 0, bmREQ_HIDOUT, HID_REQUEST_SET_PROTOCOL, protocol, 0x00, iface, 0x0000, 0x0000, NULL, NULL));
}
uint8_t HID::GetProtocol(uint8_t iface, uint8_t* dataptr) {
return ( pUsb->ctrlReq(bAddress, 0, bmREQ_HIDIN, HID_REQUEST_GET_PROTOCOL, 0x00, 0x00, iface, 0x0001, 0x0001, dataptr, NULL));
}
void HID::PrintEndpointDescriptor(const USB_ENDPOINT_DESCRIPTOR* ep_ptr) {
Notify(PSTR("Endpoint descriptor:"), 0x80);
Notify(PSTR("\r\nLength:\t\t"), 0x80);
PrintHex<uint8_t > (ep_ptr->bLength, 0x80);
Notify(PSTR("\r\nType:\t\t"), 0x80);
PrintHex<uint8_t > (ep_ptr->bDescriptorType, 0x80);
Notify(PSTR("\r\nAddress:\t"), 0x80);
PrintHex<uint8_t > (ep_ptr->bEndpointAddress, 0x80);
Notify(PSTR("\r\nAttributes:\t"), 0x80);
PrintHex<uint8_t > (ep_ptr->bmAttributes, 0x80);
Notify(PSTR("\r\nMaxPktSize:\t"), 0x80);
PrintHex<uint16_t > (ep_ptr->wMaxPacketSize, 0x80);
Notify(PSTR("\r\nPoll Intrv:\t"), 0x80);
PrintHex<uint8_t > (ep_ptr->bInterval, 0x80);
}
void HID::PrintHidDescriptor(const USB_HID_DESCRIPTOR *pDesc) {
Notify(PSTR("\r\n\r\nHID Descriptor:\r\n"), 0x80);
Notify(PSTR("bDescLength:\t\t"), 0x80);
PrintHex<uint8_t > (pDesc->bLength, 0x80);
Notify(PSTR("\r\nbDescriptorType:\t"), 0x80);
PrintHex<uint8_t > (pDesc->bDescriptorType, 0x80);
Notify(PSTR("\r\nbcdHID:\t\t\t"), 0x80);
PrintHex<uint16_t > (pDesc->bcdHID, 0x80);
Notify(PSTR("\r\nbCountryCode:\t\t"), 0x80);
PrintHex<uint8_t > (pDesc->bCountryCode, 0x80);
Notify(PSTR("\r\nbNumDescriptors:\t"), 0x80);
PrintHex<uint8_t > (pDesc->bNumDescriptors, 0x80);
Notify(PSTR("\r\nbDescrType:\t\t"), 0x80);
PrintHex<uint8_t > (pDesc->bDescrType, 0x80);
Notify(PSTR("\r\nwDescriptorLength:\t"), 0x80);
PrintHex<uint16_t > (pDesc->wDescriptorLength, 0x80);
}

38
hid.h
View file

@ -13,7 +13,7 @@ Contact information
Circuits At Home, LTD
Web : http://www.circuitsathome.com
e-mail : support@circuitsathome.com
*/
*/
#if !defined(__HID_H__)
#define __HID_H__
@ -108,8 +108,7 @@ e-mail : support@circuitsathome.com
#define HID_PROTOCOL_KEYBOARD 0x01
#define HID_PROTOCOL_MOUSE 0x02
struct HidItemPrefix
{
struct HidItemPrefix {
uint8_t bSize : 2;
uint8_t bType : 2;
uint8_t bTag : 4;
@ -138,8 +137,7 @@ struct HidItemPrefix
#define HID_MAIN_ITEM_COLLECTION_USAGE_SWITCH 5
#define HID_MAIN_ITEM_COLLECTION_USAGE_MODIFIER 6
struct MainItemIOFeature
{
struct MainItemIOFeature {
uint8_t bmIsConstantOrData : 1;
uint8_t bmIsArrayOrVariable : 1;
uint8_t bmIsRelativeOrAbsolute : 1;
@ -152,8 +150,7 @@ struct MainItemIOFeature
class HID;
class HIDReportParser
{
class HIDReportParser {
public:
virtual void Parse(HID *hid, bool is_rpt_id, uint8_t len, uint8_t *buf) = 0;
};
@ -161,8 +158,7 @@ public:
#define MAX_REPORT_PARSERS 2
#define HID_MAX_HID_CLASS_DESCRIPTORS 5
class HID : public USBDeviceConfig, public UsbConfigXtracter
{
class HID : public USBDeviceConfig, public UsbConfigXtracter {
protected:
USB *pUsb; // USB class instance pointer
uint8_t bAddress; // address
@ -181,21 +177,25 @@ protected:
virtual HIDReportParser* GetReportParser(uint8_t id);
public:
HID(USB *pusb) : pUsb(pusb) {};
const USB* GetUsb() { return pUsb; };
HID(USB *pusb) : pUsb(pusb) {
};
const USB* GetUsb() {
return pUsb;
};
virtual bool SetReportParser(uint8_t id, HIDReportParser *prs);
uint8_t SetProtocol( uint8_t iface, uint8_t protocol );
uint8_t GetProtocol( uint8_t iface, uint8_t* dataptr );
uint8_t GetIdle( uint8_t iface, uint8_t reportID, uint8_t* dataptr );
uint8_t SetIdle( uint8_t iface, uint8_t reportID, uint8_t duration );
uint8_t SetProtocol(uint8_t iface, uint8_t protocol);
uint8_t GetProtocol(uint8_t iface, uint8_t* dataptr);
uint8_t GetIdle(uint8_t iface, uint8_t reportID, uint8_t* dataptr);
uint8_t SetIdle(uint8_t iface, uint8_t reportID, uint8_t duration);
uint8_t GetReportDescr( uint8_t ep, USBReadParser *parser = NULL);
uint8_t GetReportDescr(uint8_t ep, USBReadParser *parser = NULL);
uint8_t GetHidDescr( uint8_t ep, uint16_t nbytes, uint8_t* dataptr );
uint8_t GetReport( uint8_t ep, uint8_t iface, uint8_t report_type, uint8_t report_id, uint16_t nbytes, uint8_t* dataptr );
uint8_t SetReport( uint8_t ep, uint8_t iface, uint8_t report_type, uint8_t report_id, uint16_t nbytes, uint8_t* dataptr );
uint8_t GetHidDescr(uint8_t ep, uint16_t nbytes, uint8_t* dataptr);
uint8_t GetReport(uint8_t ep, uint8_t iface, uint8_t report_type, uint8_t report_id, uint16_t nbytes, uint8_t* dataptr);
uint8_t SetReport(uint8_t ep, uint8_t iface, uint8_t report_type, uint8_t report_id, uint16_t nbytes, uint8_t* dataptr);
};
#endif // __HID_H__

View file

@ -13,11 +13,10 @@ Contact information
Circuits At Home, LTD
Web : http://www.circuitsathome.com
e-mail : support@circuitsathome.com
*/
*/
#include "hidboot.h"
void MouseReportParser::Parse(HID *hid, bool is_rpt_id, uint8_t len, uint8_t *buf)
{
void MouseReportParser::Parse(HID *hid, bool is_rpt_id, uint8_t len, uint8_t *buf) {
MOUSEINFO *pmi = (MOUSEINFO*)buf;
if (prevState.mouseInfo.bmLeftButton == 0 && pmi->bmLeftButton == 1)
@ -41,48 +40,43 @@ void MouseReportParser::Parse(HID *hid, bool is_rpt_id, uint8_t len, uint8_t *bu
if (prevState.mouseInfo.dX != pmi->dX || prevState.mouseInfo.dY != pmi->dY)
OnMouseMove(pmi);
for (uint8_t i=0; i<3; i++)
if (len > sizeof (MOUSEINFO))
for (uint8_t i = 0; i<sizeof (MOUSEINFO); i++)
prevState.bInfo[i] = buf[i];
};
void KeyboardReportParser::Parse(HID *hid, bool is_rpt_id, uint8_t len, uint8_t *buf)
{
void KeyboardReportParser::Parse(HID *hid, bool is_rpt_id, uint8_t len, uint8_t *buf) {
// On error - return
if (buf[2] == 1)
return;
KBDINFO *pki = (KBDINFO*)buf;
//KBDINFO *pki = (KBDINFO*)buf;
for (uint8_t i=2; i<8; i++)
{
for (uint8_t i = 2; i < 8; i++) {
bool down = false;
bool up = false;
for (uint8_t j=2; j<8; j++)
{
for (uint8_t j = 2; j < 8; j++) {
if (buf[i] == prevState.bInfo[j] && buf[i] != 1)
down = true;
if (buf[j] == prevState.bInfo[i] && prevState.bInfo[i] != 1)
up = true;
}
if (!down)
{
if (!down) {
HandleLockingKeys(hid, buf[i]);
OnKeyDown(*buf, buf[i]);
}
if (!up)
OnKeyUp(prevState.bInfo[0], prevState.bInfo[i]);
}
for (uint8_t i=0; i<8; i++)
for (uint8_t i = 0; i < 8; i++)
prevState.bInfo[i] = buf[i];
};
uint8_t KeyboardReportParser::HandleLockingKeys(HID *hid, uint8_t key)
{
uint8_t KeyboardReportParser::HandleLockingKeys(HID *hid, uint8_t key) {
uint8_t old_keys = kbdLockingKeys.bLeds;
switch (key)
{
switch (key) {
case KEY_NUM_LOCK:
kbdLockingKeys.kbdLeds.bmNumLock = ~kbdLockingKeys.kbdLeds.bmNumLock;
break;
@ -100,55 +94,46 @@ uint8_t KeyboardReportParser::HandleLockingKeys(HID *hid, uint8_t key)
return 0;
}
const uint8_t KeyboardReportParser::numKeys[] PROGMEM = { '!', '@', '#', '$', '%', '^', '&', '*', '(', ')' };
const uint8_t KeyboardReportParser::symKeysUp[] PROGMEM = { '_', '+', '{', '}', '|', '~', ':', '"', '~', '<', '>', '?' };
const uint8_t KeyboardReportParser::symKeysLo[] PROGMEM = { '-', '=', '[', ']', '\\', ' ', ';', '\'', '`', ',', '.', '/' };
const uint8_t KeyboardReportParser::padKeys[] PROGMEM = { '/', '*', '-', '+', 0x13 };
const uint8_t KeyboardReportParser::numKeys[] PROGMEM = {'!', '@', '#', '$', '%', '^', '&', '*', '(', ')'};
const uint8_t KeyboardReportParser::symKeysUp[] PROGMEM = {'_', '+', '{', '}', '|', '~', ':', '"', '~', '<', '>', '?'};
const uint8_t KeyboardReportParser::symKeysLo[] PROGMEM = {'-', '=', '[', ']', '\\', ' ', ';', '\'', '`', ',', '.', '/'};
const uint8_t KeyboardReportParser::padKeys[] PROGMEM = {'/', '*', '-', '+', 0x13};
uint8_t KeyboardReportParser::OemToAscii(uint8_t mod, uint8_t key)
{
uint8_t KeyboardReportParser::OemToAscii(uint8_t mod, uint8_t key) {
uint8_t shift = (mod & 0x22);
// [a-z]
if (key > 0x03 && key < 0x1e)
{
if (key > 0x03 && key < 0x1e) {
// Upper case letters
if ( (kbdLockingKeys.kbdLeds.bmCapsLock == 0 && (mod & 2)) ||
(kbdLockingKeys.kbdLeds.bmCapsLock == 1 && (mod & 2) == 0) )
if ((kbdLockingKeys.kbdLeds.bmCapsLock == 0 && (mod & 2)) ||
(kbdLockingKeys.kbdLeds.bmCapsLock == 1 && (mod & 2) == 0))
return (key - 4 + 'A');
// Lower case letters
else
return (key - 4 + 'a');
}
// Numbers
else if (key > 0x1d && key < 0x27)
{
}// Numbers
else if (key > 0x1d && key < 0x27) {
if (shift)
return ((uint8_t)pgm_read_byte(&numKeys[key - 0x1e]));
else
return (key - 0x1e + '1');
}
// Keypad Numbers
else if (key > 0x58 && key < 0x62)
{
}// Keypad Numbers
else if (key > 0x58 && key < 0x62) {
if (kbdLockingKeys.kbdLeds.bmNumLock == 1)
return (key - 0x59 + '1');
}
else if (key > 0x2c && key < 0x39)
return ((shift) ? (uint8_t)pgm_read_byte(&symKeysUp[key-0x2d]) : (uint8_t)pgm_read_byte(&symKeysLo[key-0x2d]));
} else if (key > 0x2c && key < 0x39)
return ((shift) ? (uint8_t)pgm_read_byte(&symKeysUp[key - 0x2d]) : (uint8_t)pgm_read_byte(&symKeysLo[key - 0x2d]));
else if (key > 0x53 && key < 0x59)
return (uint8_t)pgm_read_byte(&padKeys[key - 0x54]);
else
{
switch (key)
{
case KEY_SPACE: return(0x20);
case KEY_ENTER: return(0x13);
case KEY_ZERO: return((shift) ? ')' : '0');
case KEY_ZERO2: return((kbdLockingKeys.kbdLeds.bmNumLock == 1) ? '0' : 0);
case KEY_PERIOD: return((kbdLockingKeys.kbdLeds.bmNumLock == 1) ? '.' : 0);
else {
switch (key) {
case KEY_SPACE: return (0x20);
case KEY_ENTER: return (0x13);
case KEY_ZERO: return ((shift) ? ')': '0');
case KEY_ZERO2: return ((kbdLockingKeys.kbdLeds.bmNumLock == 1) ? '0': 0);
case KEY_PERIOD: return ((kbdLockingKeys.kbdLeds.bmNumLock == 1) ? '.': 0);
}
}
return( 0 );
return ( 0);
}

213
hidboot.h
View file

@ -13,7 +13,7 @@ Contact information
Circuits At Home, LTD
Web : http://www.circuitsathome.com
e-mail : support@circuitsathome.com
*/
*/
#if !defined(__HIDBOOT_H__)
#define __HIDBOOT_H__
@ -44,10 +44,9 @@ e-mail : support@circuitsathome.com
#define KEY_ENTER 0x28
#define KEY_PERIOD 0x63
struct MOUSEINFO
{
struct
{
struct MOUSEINFO {
struct {
uint8_t bmLeftButton : 1;
uint8_t bmRightButton : 1;
uint8_t bmMiddleButton : 1;
@ -57,29 +56,41 @@ struct MOUSEINFO
int8_t dY;
};
class MouseReportParser : public HIDReportParser
{
union
{
class MouseReportParser : public HIDReportParser {
union {
MOUSEINFO mouseInfo;
uint8_t bInfo[3];
uint8_t bInfo[sizeof(MOUSEINFO)];
} prevState;
public:
virtual void Parse(HID *hid, bool is_rpt_id, uint8_t len, uint8_t *buf);
protected:
virtual void OnMouseMove (MOUSEINFO *mi) {};
virtual void OnLeftButtonUp (MOUSEINFO *mi) {};
virtual void OnLeftButtonDown (MOUSEINFO *mi) {};
virtual void OnRightButtonUp (MOUSEINFO *mi) {};
virtual void OnRightButtonDown (MOUSEINFO *mi) {};
virtual void OnMiddleButtonUp (MOUSEINFO *mi) {};
virtual void OnMiddleButtonDown (MOUSEINFO *mi) {};
virtual void OnMouseMove(MOUSEINFO *mi) {
};
virtual void OnLeftButtonUp(MOUSEINFO *mi) {
};
virtual void OnLeftButtonDown(MOUSEINFO *mi) {
};
virtual void OnRightButtonUp(MOUSEINFO *mi) {
};
virtual void OnRightButtonDown(MOUSEINFO *mi) {
};
virtual void OnMiddleButtonUp(MOUSEINFO *mi) {
};
virtual void OnMiddleButtonDown(MOUSEINFO *mi) {
};
};
struct MODIFIERKEYS
{
struct MODIFIERKEYS {
uint8_t bmLeftCtrl : 1;
uint8_t bmLeftShift : 1;
uint8_t bmLeftAlt : 1;
@ -90,10 +101,9 @@ struct MODIFIERKEYS
uint8_t bmRightGUI : 1;
};
struct KBDINFO
{
struct
{
struct KBDINFO {
struct {
uint8_t bmLeftCtrl : 1;
uint8_t bmLeftShift : 1;
uint8_t bmLeftAlt : 1;
@ -107,8 +117,7 @@ struct KBDINFO
uint8_t Keys[6];
};
struct KBDLEDS
{
struct KBDLEDS {
uint8_t bmNumLock : 1;
uint8_t bmCapsLock : 1;
uint8_t bmScrollLock : 1;
@ -121,22 +130,20 @@ struct KBDLEDS
#define KEY_CAPS_LOCK 0x39
#define KEY_SCROLL_LOCK 0x47
class KeyboardReportParser : public HIDReportParser
{
class KeyboardReportParser : public HIDReportParser {
static const uint8_t numKeys[];
static const uint8_t symKeysUp[];
static const uint8_t symKeysLo[];
static const uint8_t padKeys[];
protected:
union
{
union {
KBDINFO kbdInfo;
uint8_t bInfo[sizeof(KBDINFO)];
} prevState;
union
{
union {
KBDLEDS kbdLeds;
uint8_t bLeds;
} kbdLockingKeys;
@ -144,15 +151,21 @@ protected:
uint8_t OemToAscii(uint8_t mod, uint8_t key);
public:
KeyboardReportParser() { kbdLockingKeys.bLeds = 0; };
KeyboardReportParser() {
kbdLockingKeys.bLeds = 0;
};
virtual void Parse(HID *hid, bool is_rpt_id, uint8_t len, uint8_t *buf);
protected:
uint8_t HandleLockingKeys(HID* hid, uint8_t key);
virtual void OnKeyDown (uint8_t mod, uint8_t key) {};
virtual void OnKeyUp (uint8_t mod, uint8_t key) {};
virtual void OnKeyDown(uint8_t mod, uint8_t key) {
};
virtual void OnKeyUp(uint8_t mod, uint8_t key) {
};
};
#define totalEndpoints 2
@ -175,18 +188,26 @@ class HIDBoot : public HID //public USBDeviceConfig, public UsbConfigXtracter
void Initialize();
virtual HIDReportParser* GetReportParser(uint8_t id) { return pRptParser; };
virtual HIDReportParser* GetReportParser(uint8_t id) {
return pRptParser;
};
public:
HIDBoot(USB *p);
virtual bool SetReportParser(uint8_t id, HIDReportParser *prs) { pRptParser = prs; };
virtual bool SetReportParser(uint8_t id, HIDReportParser *prs) {
pRptParser = prs;
return true;
};
// USBDeviceConfig implementation
virtual uint8_t Init(uint8_t parent, uint8_t port, bool lowspeed);
virtual uint8_t Release();
virtual uint8_t Poll();
virtual uint8_t GetAddress() { return bAddress; };
virtual uint8_t GetAddress() {
return bAddress;
};
// UsbConfigXtracter implementation
virtual void EndpointXtract(uint8_t conf, uint8_t iface, uint8_t alt, uint8_t proto, const USB_ENDPOINT_DESCRIPTOR *ep);
@ -194,22 +215,19 @@ public:
template <const uint8_t BOOT_PROTOCOL>
HIDBoot<BOOT_PROTOCOL>::HIDBoot(USB *p) :
HID(p),
qNextPollTime(0),
bPollEnable(false),
pRptParser(NULL)
{
HID(p),
qNextPollTime(0),
bPollEnable(false),
pRptParser(NULL) {
Initialize();
if (pUsb)
if(pUsb)
pUsb->RegisterDeviceClass(this);
}
template <const uint8_t BOOT_PROTOCOL>
void HIDBoot<BOOT_PROTOCOL>::Initialize()
{
for(uint8_t i=0; i<totalEndpoints; i++)
{
void HIDBoot<BOOT_PROTOCOL>::Initialize() {
for(uint8_t i = 0; i < totalEndpoints; i++) {
epInfo[i].epAddr = 0;
epInfo[i].maxPktSize = (i) ? 0 : 8;
epInfo[i].epAttribs = 0;
@ -221,8 +239,7 @@ void HIDBoot<BOOT_PROTOCOL>::Initialize()
}
template <const uint8_t BOOT_PROTOCOL>
uint8_t HIDBoot<BOOT_PROTOCOL>::Init(uint8_t parent, uint8_t port, bool lowspeed)
{
uint8_t HIDBoot<BOOT_PROTOCOL>::Init(uint8_t parent, uint8_t port, bool lowspeed) {
const uint8_t constBufSize = sizeof(USB_DEVICE_DESCRIPTOR);
uint8_t buf[constBufSize];
@ -239,17 +256,16 @@ uint8_t HIDBoot<BOOT_PROTOCOL>::Init(uint8_t parent, uint8_t port, bool lowspeed
USBTRACE("BM Init\r\n");
if (bAddress)
if(bAddress)
return USB_ERROR_CLASS_INSTANCE_ALREADY_IN_USE;
// Get pointer to pseudo device with address 0 assigned
p = addrPool.GetUsbDevicePtr(0);
if (!p)
if(!p)
return USB_ERROR_ADDRESS_NOT_FOUND_IN_POOL;
if (!p->epinfo)
{
if(!p->epinfo) {
USBTRACE("epinfo\r\n");
return USB_ERROR_EPINFO_IS_NULL;
}
@ -263,13 +279,12 @@ uint8_t HIDBoot<BOOT_PROTOCOL>::Init(uint8_t parent, uint8_t port, bool lowspeed
p->lowspeed = lowspeed;
// Get device descriptor
rcode = pUsb->getDevDescr( 0, 0, 8, (uint8_t*)buf );
rcode = pUsb->getDevDescr(0, 0, 8, (uint8_t*) buf);
if (!rcode)
if(!rcode)
len = (buf[0] > constBufSize) ? constBufSize : buf[0];
if( rcode )
{
if(rcode) {
// Restore p->epinfo
p->epinfo = oldep_ptr;
@ -282,21 +297,20 @@ uint8_t HIDBoot<BOOT_PROTOCOL>::Init(uint8_t parent, uint8_t port, bool lowspeed
// Allocate new address according to device class
bAddress = addrPool.AllocAddress(parent, false, port);
if (!bAddress)
if(!bAddress)
return USB_ERROR_OUT_OF_ADDRESS_SPACE_IN_POOL;
// Extract Max Packet Size from the device descriptor
epInfo[0].maxPktSize = (uint8_t)((USB_DEVICE_DESCRIPTOR*)buf)->bMaxPacketSize0;
epInfo[0].maxPktSize = (uint8_t) ((USB_DEVICE_DESCRIPTOR*) buf)->bMaxPacketSize0;
// Assign new address to the device
rcode = pUsb->setAddr( 0, 0, bAddress );
rcode = pUsb->setAddr(0, 0, bAddress);
if (rcode)
{
if(rcode) {
p->lowspeed = false;
addrPool.FreeAddress(bAddress);
bAddress = 0;
USBTRACE2("setAddr:",rcode);
USBTRACE2("setAddr:", rcode);
return rcode;
}
@ -306,44 +320,41 @@ uint8_t HIDBoot<BOOT_PROTOCOL>::Init(uint8_t parent, uint8_t port, bool lowspeed
p = addrPool.GetUsbDevicePtr(bAddress);
if (!p)
if(!p)
return USB_ERROR_ADDRESS_NOT_FOUND_IN_POOL;
p->lowspeed = lowspeed;
if (len)
rcode = pUsb->getDevDescr( bAddress, 0, len, (uint8_t*)buf );
if(len)
rcode = pUsb->getDevDescr(bAddress, 0, len, (uint8_t*) buf);
if(rcode)
goto FailGetDevDescr;
num_of_conf = ((USB_DEVICE_DESCRIPTOR*)buf)->bNumConfigurations;
num_of_conf = ((USB_DEVICE_DESCRIPTOR*) buf)->bNumConfigurations;
// Assign epInfo to epinfo pointer
rcode = pUsb->setEpInfoEntry(bAddress, 1, epInfo);
if (rcode)
if(rcode)
goto FailSetDevTblEntry;
//USBTRACE2("NC:", num_of_conf);
for (uint8_t i=0; i<num_of_conf; i++)
{
//HexDumper<USBReadParser, uint16_t, uint16_t> HexDump;
for(uint8_t i = 0; i < num_of_conf; i++) {
ConfigDescParser<
USB_CLASS_HID,
HID_BOOT_INTF_SUBCLASS,
BOOT_PROTOCOL,
CP_MASK_COMPARE_ALL> confDescrParser(this);
//rcode = pUsb->getConfDescr(bAddress, 0, i, &HexDump);
rcode = pUsb->getConfDescr(bAddress, 0, i, &confDescrParser);
if (bNumEP > 1)
if(bNumEP > 1)
break;
} // for
if (bNumEP < 2)
if(bNumEP < 2)
return USB_DEV_CONFIG_ERROR_DEVICE_NOT_SUPPORTED;
//USBTRACE2("\r\nbAddr:", bAddress);
@ -357,21 +368,20 @@ uint8_t HIDBoot<BOOT_PROTOCOL>::Init(uint8_t parent, uint8_t port, bool lowspeed
// Set Configuration Value
rcode = pUsb->setConf(bAddress, 0, bConfNum);
if (rcode)
if(rcode)
goto FailSetConfDescr;
//USBTRACE2("\r\nIf:", bIfaceNum);
rcode = SetProtocol(bIfaceNum, HID_BOOT_PROTOCOL);
if (rcode)
if(rcode)
goto FailSetProtocol;
if (BOOT_PROTOCOL == 1)
{
if(BOOT_PROTOCOL == 1) {
rcode = SetIdle(bIfaceNum, 0, 0);
if (rcode)
if(rcode)
goto FailSetIdle;
}
USBTRACE("BM configured\r\n");
@ -404,46 +414,38 @@ FailSetConfDescr:
goto Fail;
Fail:
Serial.println(rcode, HEX);
PrintHex<uint8_t > (rcode, 0x80);
Notify(PSTR("\n"), 0x80);
// Serial.println(rcode, HEX);
Release();
return rcode;
}
template <const uint8_t BOOT_PROTOCOL>
void HIDBoot<BOOT_PROTOCOL>::EndpointXtract(uint8_t conf, uint8_t iface, uint8_t alt, uint8_t proto, const USB_ENDPOINT_DESCRIPTOR *pep)
{
void HIDBoot<BOOT_PROTOCOL>::EndpointXtract(uint8_t conf, uint8_t iface, uint8_t alt, uint8_t proto, const USB_ENDPOINT_DESCRIPTOR *pep) {
// If the first configuration satisfies, the others are not concidered.
if (bNumEP > 1 && conf != bConfNum)
if(bNumEP > 1 && conf != bConfNum)
return;
//ErrorMessage<uint8_t>(PSTR("\r\nConf.Val"), conf);
//ErrorMessage<uint8_t>(PSTR("Iface Num"), iface);
//ErrorMessage<uint8_t>(PSTR("Alt.Set"), alt);
bConfNum = conf;
bIfaceNum = iface;
uint8_t index;
if ((pep->bmAttributes & 0x03) == 3 && (pep->bEndpointAddress & 0x80) == 0x80)
{
if((pep->bmAttributes & 0x03) == 3 && (pep->bEndpointAddress & 0x80) == 0x80) {
index = epInterruptInIndex;
// Fill in the endpoint info structure
epInfo[index].epAddr = (pep->bEndpointAddress & 0x0F);
epInfo[index].maxPktSize = (uint8_t)pep->wMaxPacketSize;
epInfo[index].maxPktSize = (uint8_t) pep->wMaxPacketSize;
epInfo[index].epAttribs = 0;
bNumEP ++;
//PrintEndpointDescriptor(pep);
bNumEP++;
}
}
template <const uint8_t BOOT_PROTOCOL>
uint8_t HIDBoot<BOOT_PROTOCOL>::Release()
{
uint8_t HIDBoot<BOOT_PROTOCOL>::Release() {
pUsb->GetAddressPool().FreeAddress(bAddress);
bConfNum = 0;
@ -456,27 +458,24 @@ uint8_t HIDBoot<BOOT_PROTOCOL>::Release()
}
template <const uint8_t BOOT_PROTOCOL>
uint8_t HIDBoot<BOOT_PROTOCOL>::Poll()
{
uint8_t HIDBoot<BOOT_PROTOCOL>::Poll() {
uint8_t rcode = 0;
if (!bPollEnable)
if(!bPollEnable)
return 0;
if (qNextPollTime <= millis())
{
if(qNextPollTime <= millis()) {
qNextPollTime = millis() + 10;
const uint8_t const_buff_len = 16;
uint8_t buf[const_buff_len];
uint16_t read = (uint16_t)epInfo[epInterruptInIndex].maxPktSize;
uint16_t read = (uint16_t) epInfo[epInterruptInIndex].maxPktSize;
uint8_t rcode = pUsb->inTransfer(bAddress, epInfo[epInterruptInIndex].epAddr, &read, buf);
if (rcode)
{
if (rcode != hrNAK)
if(rcode) {
if(rcode != hrNAK)
USBTRACE2("Poll:", rcode);
return rcode;
}
@ -485,8 +484,8 @@ uint8_t HIDBoot<BOOT_PROTOCOL>::Poll()
//if (read)
// Serial.println("");
if (pRptParser)
pRptParser->Parse((HID*)this, 0, (uint8_t)read, buf);
if(pRptParser)
pRptParser->Parse((HID*)this, 0, (uint8_t) read, buf);
}
return rcode;
}

File diff suppressed because it is too large Load diff

View file

@ -13,7 +13,7 @@ Contact information
Circuits At Home, LTD
Web : http://www.circuitsathome.com
e-mail : support@circuitsathome.com
*/
*/
#if !defined(__HIDDESCRIPTORPARSER_H__)
#define __HIDDESCRIPTORPARSER_H__
@ -37,8 +37,7 @@ e-mail : support@circuitsathome.com
#include "confdescparser.h"
#include "hid.h"
class ReportDescParserBase : public USBReadParser
{
class ReportDescParserBase : public USBReadParser {
public:
typedef void (*UsagePageFunc)(uint16_t usage);
@ -62,57 +61,57 @@ public:
static void PrintItemTitle(uint8_t prefix);
static const char *usagePageTitles0[];
static const char *usagePageTitles1[];
static const char *genDesktopTitles0[];
static const char *genDesktopTitles1[];
static const char *genDesktopTitles2[];
static const char *genDesktopTitles3[];
static const char *genDesktopTitles4[];
static const char *simuTitles0[];
static const char *simuTitles1[];
static const char *simuTitles2[];
static const char *vrTitles0[];
static const char *vrTitles1[];
static const char *sportsCtrlTitles0[];
static const char *sportsCtrlTitles1[];
static const char *sportsCtrlTitles2[];
static const char *gameTitles0[];
static const char *gameTitles1[];
static const char *genDevCtrlTitles[];
static const char *ledTitles[];
static const char *telTitles0[];
static const char *telTitles1[];
static const char *telTitles2[];
static const char *telTitles3[];
static const char *telTitles4[];
static const char *telTitles5[];
static const char *consTitles0[];
static const char *consTitles1[];
static const char *consTitles2[];
static const char *consTitles3[];
static const char *consTitles4[];
static const char *consTitles5[];
static const char *consTitles6[];
static const char *consTitles7[];
static const char *consTitles8[];
static const char *consTitles9[];
static const char *consTitlesA[];
static const char *consTitlesB[];
static const char *consTitlesC[];
static const char *consTitlesD[];
static const char *consTitlesE[];
static const char *digitTitles0[];
static const char *digitTitles1[];
static const char *digitTitles2[];
static const char *aplphanumTitles0[];
static const char *aplphanumTitles1[];
static const char *aplphanumTitles2[];
static const char *medInstrTitles0[];
static const char *medInstrTitles1[];
static const char *medInstrTitles2[];
static const char *medInstrTitles3[];
static const char *medInstrTitles4[];
static const char * const usagePageTitles0[];
static const char * const usagePageTitles1[];
static const char * const genDesktopTitles0[];
static const char * const genDesktopTitles1[];
static const char * const genDesktopTitles2[];
static const char * const genDesktopTitles3[];
static const char * const genDesktopTitles4[];
static const char * const simuTitles0[];
static const char * const simuTitles1[];
static const char * const simuTitles2[];
static const char * const vrTitles0[];
static const char * const vrTitles1[];
static const char * const sportsCtrlTitles0[];
static const char * const sportsCtrlTitles1[];
static const char * const sportsCtrlTitles2[];
static const char * const gameTitles0[];
static const char * const gameTitles1[];
static const char * const genDevCtrlTitles[];
static const char * const ledTitles[];
static const char * const telTitles0[];
static const char * const telTitles1[];
static const char * const telTitles2[];
static const char * const telTitles3[];
static const char * const telTitles4[];
static const char * const telTitles5[];
static const char * const consTitles0[];
static const char * const consTitles1[];
static const char * const consTitles2[];
static const char * const consTitles3[];
static const char * const consTitles4[];
static const char * const consTitles5[];
static const char * const consTitles6[];
static const char * const consTitles7[];
static const char * const consTitles8[];
static const char * const consTitles9[];
static const char * const consTitlesA[];
static const char * const consTitlesB[];
static const char * const consTitlesC[];
static const char * const consTitlesD[];
static const char * const consTitlesE[];
static const char * const digitTitles0[];
static const char * const digitTitles1[];
static const char * const digitTitles2[];
static const char * const aplphanumTitles0[];
static const char * const aplphanumTitles1[];
static const char * const aplphanumTitles2[];
static const char * const medInstrTitles0[];
static const char * const medInstrTitles1[];
static const char * const medInstrTitles2[];
static const char * const medInstrTitles3[];
static const char * const medInstrTitles4[];
protected:
static UsagePageFunc usagePageFunctions[];
@ -138,14 +137,14 @@ protected:
void SetUsagePage(uint16_t page);
public:
ReportDescParserBase() :
itemParseState(0),
itemSize(0),
itemPrefix(0),
rptSize(0),
rptCount(0),
pfUsage(NULL)
{
pfUsage(NULL) {
theBuffer.pValue = varBuffer;
valParser.Initialize(&theBuffer);
theSkipper.Initialize(&theBuffer);
@ -153,20 +152,17 @@ public:
virtual void Parse(const uint16_t len, const uint8_t *pbuf, const uint16_t &offset);
enum
{
enum {
enErrorSuccess = 0
, enErrorIncomplete // value or record is partialy read in buffer
, enErrorBufferTooSmall
};
};
class ReportDescParser : public ReportDescParserBase
{
class ReportDescParser : public ReportDescParserBase {
};
class ReportDescParser2 : public ReportDescParserBase
{
class ReportDescParser2 : public ReportDescParserBase {
uint8_t rptId; // Report ID
uint8_t useMin; // Usage Minimum
uint8_t useMax; // Usage Maximum
@ -181,13 +177,13 @@ protected:
virtual uint8_t ParseItem(uint8_t **pp, uint16_t *pcntdn);
public:
ReportDescParser2(uint16_t len, uint8_t *pbuf) :
ReportDescParserBase(), bLen(len), pBuf(pbuf), rptId(0), useMin(0), useMax(0), fieldCount(0)
{};
ReportDescParserBase(), rptId(0), useMin(0), useMax(0), fieldCount(0), pBuf(pbuf), bLen(len) {
};
};
class UniversalReportParser : public HIDReportParser
{
class UniversalReportParser : public HIDReportParser {
public:
virtual void Parse(HID *hid, bool is_rpt_id, uint8_t len, uint8_t *buf);
};

View file

@ -1,53 +1,44 @@
#include "hiduniversal.h"
HIDUniversal::HIDUniversal(USB *p) :
HID(p),
qNextPollTime(0),
bPollEnable(false),
bHasReportId(false)
{
HID(p),
qNextPollTime(0),
bPollEnable(false),
bHasReportId(false) {
Initialize();
if (pUsb)
pUsb->RegisterDeviceClass(this);
}
uint16_t HIDUniversal::GetHidClassDescrLen(uint8_t type, uint8_t num)
{
for (uint8_t i=0, n=0; i<HID_MAX_HID_CLASS_DESCRIPTORS; i++)
{
if (descrInfo[i].bDescrType == type)
{
uint16_t HIDUniversal::GetHidClassDescrLen(uint8_t type, uint8_t num) {
for (uint8_t i = 0, n = 0; i < HID_MAX_HID_CLASS_DESCRIPTORS; i++) {
if (descrInfo[i].bDescrType == type) {
if (n == num)
return descrInfo[i].wDescriptorLength;
n ++;
n++;
}
}
return 0;
}
void HIDUniversal::Initialize()
{
for (uint8_t i=0; i<MAX_REPORT_PARSERS; i++)
{
void HIDUniversal::Initialize() {
for (uint8_t i = 0; i < MAX_REPORT_PARSERS; i++) {
rptParsers[i].rptId = 0;
rptParsers[i].rptParser = NULL;
}
for (uint8_t i=0; i<HID_MAX_HID_CLASS_DESCRIPTORS; i++)
{
for (uint8_t i = 0; i < HID_MAX_HID_CLASS_DESCRIPTORS; i++) {
descrInfo[i].bDescrType = 0;
descrInfo[i].wDescriptorLength = 0;
}
for (uint8_t i=0; i<maxHidInterfaces; i++)
{
for (uint8_t i = 0; i < maxHidInterfaces; i++) {
hidInterfaces[i].bmInterface = 0;
hidInterfaces[i].bmProtocol = 0;
for (uint8_t j=0; j<maxEpPerInterface; j++)
for (uint8_t j = 0; j < maxEpPerInterface; j++)
hidInterfaces[i].epIndex[j] = 0;
}
for(uint8_t i=0; i<totalEndpoints; i++)
{
for (uint8_t i = 0; i < totalEndpoints; i++) {
epInfo[i].epAddr = 0;
epInfo[i].maxPktSize = (i) ? 0 : 8;
epInfo[i].epAttribs = 0;
@ -60,12 +51,9 @@ void HIDUniversal::Initialize()
ZeroMemory(constBuffLen, prevBuf);
}
bool HIDUniversal::SetReportParser(uint8_t id, HIDReportParser *prs)
{
for (uint8_t i=0; i<MAX_REPORT_PARSERS; i++)
{
if (rptParsers[i].rptId == 0 && rptParsers[i].rptParser == NULL)
{
bool HIDUniversal::SetReportParser(uint8_t id, HIDReportParser *prs) {
for (uint8_t i = 0; i < MAX_REPORT_PARSERS; i++) {
if (rptParsers[i].rptId == 0 && rptParsers[i].rptParser == NULL) {
rptParsers[i].rptId = id;
rptParsers[i].rptParser = prs;
return true;
@ -74,22 +62,19 @@ bool HIDUniversal::SetReportParser(uint8_t id, HIDReportParser *prs)
return false;
}
HIDReportParser* HIDUniversal::GetReportParser(uint8_t id)
{
HIDReportParser* HIDUniversal::GetReportParser(uint8_t id) {
if (!bHasReportId)
return ((rptParsers[0].rptParser) ? rptParsers[0].rptParser : NULL);
for (uint8_t i=0; i<MAX_REPORT_PARSERS; i++)
{
for (uint8_t i = 0; i < MAX_REPORT_PARSERS; i++) {
if (rptParsers[i].rptId == id)
return rptParsers[i].rptParser;
}
return NULL;
}
uint8_t HIDUniversal::Init(uint8_t parent, uint8_t port, bool lowspeed)
{
const uint8_t constBufSize = sizeof(USB_DEVICE_DESCRIPTOR);
uint8_t HIDUniversal::Init(uint8_t parent, uint8_t port, bool lowspeed) {
const uint8_t constBufSize = sizeof (USB_DEVICE_DESCRIPTOR);
uint8_t buf[constBufSize];
uint8_t rcode;
@ -98,7 +83,7 @@ uint8_t HIDUniversal::Init(uint8_t parent, uint8_t port, bool lowspeed)
uint8_t len = 0;
uint8_t num_of_conf; // number of configurations
uint8_t num_of_intf; // number of interfaces
//uint8_t num_of_intf; // number of interfaces
AddressPool &addrPool = pUsb->GetAddressPool();
@ -113,8 +98,7 @@ uint8_t HIDUniversal::Init(uint8_t parent, uint8_t port, bool lowspeed)
if (!p)
return USB_ERROR_ADDRESS_NOT_FOUND_IN_POOL;
if (!p->epinfo)
{
if (!p->epinfo) {
USBTRACE("epinfo\r\n");
return USB_ERROR_EPINFO_IS_NULL;
}
@ -127,16 +111,13 @@ uint8_t HIDUniversal::Init(uint8_t parent, uint8_t port, bool lowspeed)
p->lowspeed = lowspeed;
//delay(200);
// Get device descriptor
rcode = pUsb->getDevDescr( 0, 0, 8, (uint8_t*)buf );
rcode = pUsb->getDevDescr(0, 0, 8, (uint8_t*)buf);
if (!rcode)
len = (buf[0] > constBufSize) ? constBufSize : buf[0];
if( rcode )
{
if (rcode) {
// Restore p->epinfo
p->epinfo = oldep_ptr;
@ -156,14 +137,13 @@ uint8_t HIDUniversal::Init(uint8_t parent, uint8_t port, bool lowspeed)
epInfo[0].maxPktSize = (uint8_t)((USB_DEVICE_DESCRIPTOR*)buf)->bMaxPacketSize0;
// Assign new address to the device
rcode = pUsb->setAddr( 0, 0, bAddress );
rcode = pUsb->setAddr(0, 0, bAddress);
if (rcode)
{
if (rcode) {
p->lowspeed = false;
addrPool.FreeAddress(bAddress);
bAddress = 0;
USBTRACE2("setAddr:",rcode);
USBTRACE2("setAddr:", rcode);
return rcode;
}
@ -178,12 +158,10 @@ uint8_t HIDUniversal::Init(uint8_t parent, uint8_t port, bool lowspeed)
p->lowspeed = lowspeed;
delay(500);
if (len)
rcode = pUsb->getDevDescr( bAddress, 0, len, (uint8_t*)buf );
rcode = pUsb->getDevDescr(bAddress, 0, len, (uint8_t*)buf);
if(rcode)
if (rcode)
goto FailGetDevDescr;
num_of_conf = ((USB_DEVICE_DESCRIPTOR*)buf)->bNumConfigurations;
@ -196,9 +174,7 @@ uint8_t HIDUniversal::Init(uint8_t parent, uint8_t port, bool lowspeed)
USBTRACE2("NC:", num_of_conf);
for (uint8_t i=0; i<num_of_conf; i++)
{
//delay(1000);
for (uint8_t i = 0; i < num_of_conf; i++) {
//HexDumper<USBReadParser, uint16_t, uint16_t> HexDump;
ConfigDescParser<USB_CLASS_HID, 0, 0,
CP_MASK_COMPARE_CLASS> confDescrParser(this);
@ -206,6 +182,9 @@ uint8_t HIDUniversal::Init(uint8_t parent, uint8_t port, bool lowspeed)
//rcode = pUsb->getConfDescr(bAddress, 0, i, &HexDump);
rcode = pUsb->getConfDescr(bAddress, 0, i, &confDescrParser);
if (rcode)
goto FailGetConfDescr;
if (bNumEP > 1)
break;
} // for
@ -224,8 +203,7 @@ uint8_t HIDUniversal::Init(uint8_t parent, uint8_t port, bool lowspeed)
if (rcode)
goto FailSetConfDescr;
for (uint8_t i=0; i<bNumIface; i++)
{
for (uint8_t i = 0; i < bNumIface; i++) {
if (hidInterfaces[i].epIndex[epInterruptInIndex] == 0)
continue;
@ -258,35 +236,27 @@ FailSetConfDescr:
USBTRACE("setConf:");
goto Fail;
FailSetProtocol:
USBTRACE("SetProto:");
goto Fail;
FailSetIdle:
USBTRACE("SetIdle:");
goto Fail;
FailGetReportDescr:
USBTRACE("GetReportDescr:");
goto Fail;
Fail:
Serial.println(rcode, HEX);
PrintHex<uint8_t > (rcode, 0x80);
Notify(PSTR("\r\n"), 0x80);
//Serial.println(rcode, HEX);
Release();
return rcode;
}
HIDUniversal::HIDInterface* HIDUniversal::FindInterface(uint8_t iface, uint8_t alt, uint8_t proto)
{
for (uint8_t i=0; i<bNumIface && i<maxHidInterfaces; i++)
HIDUniversal::HIDInterface* HIDUniversal::FindInterface(uint8_t iface, uint8_t alt, uint8_t proto) {
for (uint8_t i = 0; i < bNumIface && i < maxHidInterfaces; i++)
if (hidInterfaces[i].bmInterface == iface && hidInterfaces[i].bmAltSet == alt
&& hidInterfaces[i].bmProtocol == proto)
return hidInterfaces + i;
return NULL;
}
void HIDUniversal::EndpointXtract(uint8_t conf, uint8_t iface, uint8_t alt, uint8_t proto, const USB_ENDPOINT_DESCRIPTOR *pep)
{
void HIDUniversal::EndpointXtract(uint8_t conf, uint8_t iface, uint8_t alt, uint8_t proto, const USB_ENDPOINT_DESCRIPTOR *pep) {
// If the first configuration satisfies, the others are not concidered.
if (bNumEP > 1 && conf != bConfNum)
return;
@ -301,13 +271,12 @@ void HIDUniversal::EndpointXtract(uint8_t conf, uint8_t iface, uint8_t alt, uint
HIDInterface *piface = FindInterface(iface, alt, proto);
// Fill in interface structure in case of new interface
if (!piface)
{
if (!piface) {
piface = hidInterfaces + bNumIface;
piface->bmInterface = iface;
piface->bmAltSet = alt;
piface->bmProtocol = proto;
bNumIface ++;
bNumIface++;
}
if ((pep->bmAttributes & 0x03) == 3 && (pep->bEndpointAddress & 0x80) == 0x80)
@ -315,8 +284,7 @@ void HIDUniversal::EndpointXtract(uint8_t conf, uint8_t iface, uint8_t alt, uint
else
index = epInterruptOutIndex;
if (index)
{
if (index) {
// Fill in the endpoint info structure
epInfo[bNumEP].epAddr = (pep->bEndpointAddress & 0x0F);
epInfo[bNumEP].maxPktSize = (uint8_t)pep->wMaxPacketSize;
@ -326,14 +294,12 @@ void HIDUniversal::EndpointXtract(uint8_t conf, uint8_t iface, uint8_t alt, uint
// Fill in the endpoint index list
piface->epIndex[index] = bNumEP; //(pep->bEndpointAddress & 0x0F);
bNumEP ++;
bNumEP++;
}
//PrintEndpointDescriptor(pep);
}
uint8_t HIDUniversal::Release()
{
uint8_t HIDUniversal::Release() {
pUsb->GetAddressPool().FreeAddress(bAddress);
bNumEP = 1;
@ -343,40 +309,35 @@ uint8_t HIDUniversal::Release()
return 0;
}
bool HIDUniversal::BuffersIdentical(uint8_t len, uint8_t *buf1, uint8_t *buf2)
{
for (uint8_t i=0; i<len; i++)
bool HIDUniversal::BuffersIdentical(uint8_t len, uint8_t *buf1, uint8_t *buf2) {
for (uint8_t i = 0; i < len; i++)
if (buf1[i] != buf2[i])
return false;
return true;
}
void HIDUniversal::ZeroMemory(uint8_t len, uint8_t *buf)
{
for (uint8_t i=0; i<len; i++)
void HIDUniversal::ZeroMemory(uint8_t len, uint8_t *buf) {
for (uint8_t i = 0; i < len; i++)
buf[i] = 0;
}
void HIDUniversal::SaveBuffer(uint8_t len, uint8_t *src, uint8_t *dest)
{
for (uint8_t i=0; i<len; i++)
void HIDUniversal::SaveBuffer(uint8_t len, uint8_t *src, uint8_t *dest) {
for (uint8_t i = 0; i < len; i++)
dest[i] = src[i];
}
uint8_t HIDUniversal::Poll()
{
uint8_t HIDUniversal::Poll() {
uint8_t rcode = 0;
if (!bPollEnable)
return 0;
if (qNextPollTime <= millis())
{
if (qNextPollTime <= millis()) {
qNextPollTime = millis() + 50;
uint8_t buf[constBuffLen];
for (uint8_t i=0; i<bNumIface; i++)
{
for (uint8_t i = 0; i < bNumIface; i++) {
uint8_t index = hidInterfaces[i].epIndex[epInterruptInIndex];
uint16_t read = (uint16_t)epInfo[index].maxPktSize;
@ -384,8 +345,7 @@ uint8_t HIDUniversal::Poll()
uint8_t rcode = pUsb->inTransfer(bAddress, epInfo[index].epAddr, &read, buf);
if (rcode)
{
if (rcode) {
if (rcode != hrNAK)
USBTRACE2("Poll:", rcode);
return rcode;
@ -401,14 +361,14 @@ uint8_t HIDUniversal::Poll()
if (identical)
return 0;
Serial.print("\r\nBuf: ");
Notify(PSTR("\r\nBuf: "), 0x80);
for (uint8_t i=0; i<read; i++)
PrintHex<uint8_t>(buf[i]);
for (uint8_t i = 0; i < read; i++)
PrintHex<uint8_t > (buf[i], 0x80);
Serial.println("");
Notify(PSTR("\r\n"), 0x80);
HIDReportParser *prs = GetReportParser( ((bHasReportId) ? *buf : 0) );
HIDReportParser *prs = GetReportParser(((bHasReportId) ? *buf : 0));
if (prs)
prs->Parse(this, bHasReportId, (uint8_t)read, buf);

View file

@ -4,10 +4,9 @@
#include "hid.h"
//#include "hidescriptorparser.h"
class HIDUniversal : public HID
{
struct ReportParser
{
class HIDUniversal : public HID {
struct ReportParser {
uint8_t rptId;
HIDReportParser *rptParser;
} rptParsers[MAX_REPORT_PARSERS];
@ -20,10 +19,9 @@ class HIDUniversal : public HID
EpInfo epInfo[totalEndpoints];
struct HIDInterface
{
struct
{
struct HIDInterface {
struct {
uint8_t bmInterface : 3;
uint8_t bmAltSet : 3;
uint8_t bmProtocol : 2;
@ -54,7 +52,10 @@ protected:
// HID implementation
virtual HIDReportParser* GetReportParser(uint8_t id);
virtual uint8_t OnInitSuccessful() { return 0; };
virtual uint8_t OnInitSuccessful() {
return 0;
};
public:
HIDUniversal(USB *p);
@ -66,7 +67,10 @@ public:
virtual uint8_t Init(uint8_t parent, uint8_t port, bool lowspeed);
virtual uint8_t Release();
virtual uint8_t Poll();
virtual uint8_t GetAddress() { return bAddress; };
virtual uint8_t GetAddress() {
return bAddress;
};
// UsbConfigXtracter implementation
virtual void EndpointXtract(uint8_t conf, uint8_t iface, uint8_t alt, uint8_t proto, const USB_ENDPOINT_DESCRIPTOR *ep);

View file

@ -13,7 +13,7 @@ Contact information
Circuits At Home, LTD
Web : http://www.circuitsathome.com
e-mail : support@circuitsathome.com
*/
*/
#if !defined( __HIDUSAGESTR_H__)
#define __HIDUSAGESTR_H__

View file

@ -13,7 +13,7 @@ Contact information
Circuits At Home, LTD
Web : http://www.circuitsathome.com
e-mail : support@circuitsathome.com
*/
*/
#if !defined(__HIDUSAGETITLEARRAYS_H__)
#define __HIDUSAGETITLEARRAYS_H__

File diff suppressed because it is too large Load diff

View file

@ -2,8 +2,8 @@
#define __MASSTORAGE_H__
#include <inttypes.h>
#include <avr/pgmspace.h>
#include "avrpins.h"
#include <avr/pgmspace.h>
#include "max3421e.h"
#include "usbhost.h"
#include "usb_ch9.h"
@ -19,7 +19,7 @@
#include "hexdump.h"
#include "message.h"
#include "confdescparser.h"
#include <confdescparser.h>
#define SWAP(a, b) (((a) ^= (b)), ((b) ^= (a)), ((a) ^= (b)))
@ -69,27 +69,44 @@
#define SCSI_CMD_WRITE_10 0x2A
#define SCSI_CMD_MODE_SENSE_6 0x1A
#define SCSI_CMD_MODE_SENSE_10 0x5A
#define SCSI_CMD_START_STOP_UNIT 0x1B
#define SCSI_S_NOT_READY 0x02
#define SCSI_S_MEDIUM_ERROR 0x03
#define SCSI_S_ILLEGAL_REQUEST 0x05
#define SCSI_S_UNIT_ATTENTION 0x06
#define SCSI_ASC_MEDIUM_NOT_PRESENT 0x3A
#define SCSI_ASC_LBA_OUT_OF_RANGE 0x21
#define MASS_ERR_SUCCESS 0x00
#define MASS_ERR_PHASE_ERROR 0x01
#define MASS_ERR_PHASE_ERROR 0x02
#define MASS_ERR_UNIT_NOT_READY 0x03
#define MASS_ERR_UNIT_BUSY 0x04
#define MASS_ERR_STALL 0x05
#define MASS_ERR_CMD_NOT_SUPPORTED 0x06
#define MASS_ERR_INVALID_CSW 0x07
#define MASS_ERR_NO_MEDIA 0x08
#define MASS_ERR_BAD_LBA 0x09
#define MASS_ERR_DEVICE_DISCONNECTED 0x11
#define MASS_ERR_UNABLE_TO_RECOVER 0x12 // Reset recovery error
#define MASS_ERR_INVALID_LUN 0x13
#define MASS_ERR_GENERAL_SCSI_ERROR 0xFE
#define MASS_ERR_GENERAL_USB_ERROR 0xFF
#define MASS_ERR_USER 0xA0 // For subclasses to define their own error codes
#define MASS_TRANS_FLG_CALLBACK 0x01 // Callback is involved
#define MASS_TRANS_FLG_NO_STALL_CHECK 0x02 // STALL condition is not checked
#define MASS_TRANS_FLG_NO_PHASE_CHECK 0x04 // PHASE_ERROR is not checked
struct Capacity
{
struct Capacity {
uint8_t data[8];
//uint32_t dwBlockAddress;
//uint32_t dwBlockLength;
};
} __attribute__((packed));
struct InquiryResponse
{
struct InquiryResponse {
uint8_t DeviceType : 5;
uint8_t PeripheralQualifier : 3;
@ -119,39 +136,38 @@ struct InquiryResponse
uint8_t VendorID[8];
uint8_t ProductID[16];
uint8_t RevisionID[4];
};
} __attribute__((packed));
struct CommandBlockWrapper
{
struct CommandBlockWrapperBase {
uint32_t dCBWSignature;
uint32_t dCBWTag;
uint32_t dCBWDataTransferLength;
uint8_t bmCBWFlags;
} __attribute__((packed));
struct
{
struct CommandBlockWrapper : public CommandBlockWrapperBase {
struct {
uint8_t bmCBWLUN : 4;
uint8_t bmReserved1 : 4;
};
struct
{
struct {
uint8_t bmCBWCBLength : 4;
uint8_t bmReserved2 : 4;
};
uint8_t CBWCB[16];
} ;
} __attribute__((packed));
struct CommandStatusWrapper
{
struct CommandStatusWrapper {
uint32_t dCSWSignature;
uint32_t dCSWTag;
uint32_t dCSWDataResidue;
uint8_t bCSWStatus;
};
} __attribute__((packed));
struct RequestSenseResponce
{
struct RequestSenseResponce {
uint8_t bResponseCode;
uint8_t bSegmentNumber;
@ -168,22 +184,11 @@ struct RequestSenseResponce
uint8_t bAdditionalSenseQualifier;
uint8_t bFieldReplaceableUnitCode;
uint8_t SenseKeySpecific[3];
};
//class BulkReadParser : public USBReadParser
//{
//protected:
// bool IsValidCSW(uint8_t size, uint8_t *pcsw);
// bool IsMeaningfulCSW(uint8_t size, uint8_t *pcsw);
//
//public:
// virtual void Parse(const uint16_t len, const uint8_t *pbuf, const uint16_t &offset) = 0;
//};
} __attribute__((packed));
#define MASS_MAX_ENDPOINTS 3
class BulkOnly : public USBDeviceConfig, public UsbConfigXtracter
{
class BulkOnly : public USBDeviceConfig, public UsbConfigXtracter {
protected:
static const uint8_t epDataInIndex; // DataIn endpoint index
static const uint8_t epDataOutIndex; // DataOUT endpoint index
@ -201,52 +206,71 @@ protected:
uint32_t dCBWTag; // Tag
uint32_t dCBWDataTransferLength; // Data Transfer Length
uint8_t bMaxLUN; // Max LUN
uint8_t bLastUsbError; // Last USB error
uint8_t bMaxLUN; // Max LUN
uint8_t bTheLUN; // Active LUN
protected:
//union TransFlags
//{
// uint8_t nValue;
// struct {
// uint8_t bmCallback : 1;
// uint8_t bmCheckPhaseErr : 1;
// uint8_t bmDummy : 6;
// };
//};
void PrintEndpointDescriptor(const USB_ENDPOINT_DESCRIPTOR* ep_ptr);
bool IsValidCBW(uint8_t size, uint8_t *pcbw);
bool IsMeaningfulCBW(uint8_t size, uint8_t *pcbw);
bool IsValidCSW(CommandStatusWrapper *pcsw, CommandBlockWrapperBase *pcbw);
uint8_t ClearEpHalt(uint8_t index);
uint8_t Transaction(CommandBlockWrapper *cbw, uint16_t bsize, void *buf, uint8_t flags);
uint8_t HandleUsbError(uint8_t index);
uint8_t HandleUsbError(uint8_t error, uint8_t index);
uint8_t HandleSCSIError(uint8_t status);
public:
BulkOnly(USB *p);
uint8_t GetLastUsbError() { return bLastUsbError; };
uint8_t GetLastUsbError() {
return bLastUsbError;
};
uint8_t GetbMaxLUN() {
return bMaxLUN; // Max LUN
}
uint8_t GetbTheLUN() {
return bTheLUN; // Active LUN
}
uint8_t Reset();
uint8_t GetMaxLUN(uint8_t *max_lun);
uint8_t SetCurLUN(uint8_t lun);
uint8_t ResetRecovery();
uint8_t Inquiry(uint8_t lun, uint16_t size, uint8_t *buf);
uint8_t TestUnitReady(uint8_t lun);
uint8_t ReadCapacity(uint8_t lun, uint16_t size, uint8_t *buf);
uint8_t RequestSense(uint8_t lun, uint16_t size, uint8_t *buf);
//uint8_t Read(uint8_t lun, uint32_t addr, uint16_t bsize, uint8_t *buf);
uint8_t Read(uint8_t lun, uint32_t addr, uint16_t bsize, USBReadParser *prs);
uint8_t ModeSense(uint8_t lun, uint8_t pc, uint8_t page, uint8_t subpage, uint8_t len, uint8_t *buf);
uint8_t MediaCTL(uint8_t lun, uint8_t ctl);
uint8_t Read(uint8_t lun, uint32_t addr, uint16_t bsize, uint8_t blocks, uint8_t *buf);
uint8_t Read(uint8_t lun, uint32_t addr, uint16_t bsize, uint8_t blocks, USBReadParser *prs);
uint8_t Write(uint8_t lun, uint32_t addr, uint16_t bsize, uint8_t blocks, const uint8_t *buf);
// USBDeviceConfig implementation
virtual uint8_t Init(uint8_t parent, uint8_t port, bool lowspeed);
virtual uint8_t Release();
virtual uint8_t Poll();
virtual uint8_t GetAddress() { return bAddress; };
virtual uint8_t GetAddress() {
return bAddress;
};
// UsbConfigXtracter implementation
virtual void EndpointXtract(uint8_t conf, uint8_t iface, uint8_t alt, uint8_t proto, const USB_ENDPOINT_DESCRIPTOR *ep);
protected:
// Additional Initialization Method for Subclasses
virtual uint8_t OnInit() {
return 0;
};
};
#endif // __MASSTORAGE_H__

View file

@ -13,7 +13,7 @@ Contact information
Circuits At Home, LTD
Web : http://www.circuitsathome.com
e-mail : support@circuitsathome.com
*/
*/
/* MAX3421E register/bit names and bitmasks */
#ifndef _max3421e_h_

View file

@ -13,7 +13,7 @@ Contact information
Circuits At Home, LTD
Web : http://www.circuitsathome.com
e-mail : support@circuitsathome.com
*/
*/
#include "max_LCD.h"
#include "max3421e.h"
@ -49,14 +49,11 @@ e-mail : support@circuitsathome.com
static byte lcdPins; //copy of LCD pins
Max_LCD::Max_LCD(USB *pusb) : pUsb(pusb)
{
Max_LCD::Max_LCD(USB *pusb) : pUsb(pusb) {
lcdPins = 0;
}
void Max_LCD::init()
{
void Max_LCD::init() {
_displayfunction = LCD_4BITMODE | LCD_1LINE | LCD_5x8DOTS;
// MAX3421E::gpioWr(0x55);
@ -124,43 +121,44 @@ void Max_LCD::begin(uint8_t cols, uint8_t lines, uint8_t dotsize) {
}
/********** high level commands, for the user! */
void Max_LCD::clear()
{
void Max_LCD::clear() {
command(LCD_CLEARDISPLAY); // clear display, set cursor position to zero
delayMicroseconds(2000); // this command takes a long time!
}
void Max_LCD::home()
{
void Max_LCD::home() {
command(LCD_RETURNHOME); // set cursor position to zero
delayMicroseconds(2000); // this command takes a long time!
}
void Max_LCD::setCursor(uint8_t col, uint8_t row)
{
int row_offsets[] = { 0x00, 0x40, 0x14, 0x54 };
if ( row > _numlines ) {
row = _numlines-1; // we count rows starting w/0
void Max_LCD::setCursor(uint8_t col, uint8_t row) {
int row_offsets[] = {0x00, 0x40, 0x14, 0x54};
if (row > _numlines) {
row = _numlines - 1; // we count rows starting w/0
}
command(LCD_SETDDRAMADDR | (col + row_offsets[row]));
}
// Turn the display on/off (quickly)
void Max_LCD::noDisplay() {
_displaycontrol &= ~LCD_DISPLAYON;
command(LCD_DISPLAYCONTROL | _displaycontrol);
}
void Max_LCD::display() {
_displaycontrol |= LCD_DISPLAYON;
command(LCD_DISPLAYCONTROL | _displaycontrol);
}
// Turns the underline cursor on/off
void Max_LCD::noCursor() {
_displaycontrol &= ~LCD_CURSORON;
command(LCD_DISPLAYCONTROL | _displaycontrol);
}
void Max_LCD::cursor() {
_displaycontrol |= LCD_CURSORON;
command(LCD_DISPLAYCONTROL | _displaycontrol);
@ -168,42 +166,50 @@ void Max_LCD::cursor() {
// Turn on and off the blinking cursor
void Max_LCD::noBlink() {
_displaycontrol &= ~LCD_BLINKON;
command(LCD_DISPLAYCONTROL | _displaycontrol);
}
void Max_LCD::blink() {
_displaycontrol |= LCD_BLINKON;
command(LCD_DISPLAYCONTROL | _displaycontrol);
}
// These commands scroll the display without changing the RAM
void Max_LCD::scrollDisplayLeft(void) {
command(LCD_CURSORSHIFT | LCD_DISPLAYMOVE | LCD_MOVELEFT);
}
void Max_LCD::scrollDisplayRight(void) {
command(LCD_CURSORSHIFT | LCD_DISPLAYMOVE | LCD_MOVERIGHT);
}
// This is for text that flows Left to Right
void Max_LCD::leftToRight(void) {
_displaymode |= LCD_ENTRYLEFT;
command(LCD_ENTRYMODESET | _displaymode);
}
// This is for text that flows Right to Left
void Max_LCD::rightToLeft(void) {
_displaymode &= ~LCD_ENTRYLEFT;
command(LCD_ENTRYMODESET | _displaymode);
}
// This will 'right justify' text from the cursor
void Max_LCD::autoscroll(void) {
_displaymode |= LCD_ENTRYSHIFTINCREMENT;
command(LCD_ENTRYMODESET | _displaymode);
}
// This will 'left justify' text from the cursor
void Max_LCD::noAutoscroll(void) {
_displaymode &= ~LCD_ENTRYSHIFTINCREMENT;
command(LCD_ENTRYMODESET | _displaymode);
@ -211,10 +217,11 @@ void Max_LCD::noAutoscroll(void) {
// Allows us to fill the first 8 CGRAM locations
// with custom characters
void Max_LCD::createChar(uint8_t location, uint8_t charmap[]) {
location &= 0x7; // we only have 8 locations 0-7
command(LCD_SETCGRAMADDR | (location << 3));
for (int i=0; i<8; i++) {
for (int i = 0; i < 8; i++) {
write(charmap[i]);
}
}
@ -230,10 +237,9 @@ inline void Max_LCD::write(uint8_t value) {
LCD_sendchar(value);
}
void Max_LCD::sendbyte( uint8_t val )
{
void Max_LCD::sendbyte(uint8_t val) {
lcdPins &= 0x0f; //prepare place for the upper nibble
lcdPins |= ( val & 0xf0 ); //copy upper nibble to LCD variable
lcdPins |= (val & 0xf0); //copy upper nibble to LCD variable
SET_E; //send
SENDlcdPins();
delayMicroseconds(2);
@ -241,7 +247,7 @@ void Max_LCD::sendbyte( uint8_t val )
delayMicroseconds(2);
SENDlcdPins();
lcdPins &= 0x0f; //prepare place for the lower nibble
lcdPins |= ( val << 4 ) & 0xf0; //copy lower nibble to LCD variable
lcdPins |= (val << 4) & 0xf0; //copy lower nibble to LCD variable
SET_E; //send
SENDlcdPins();
CLR_E;

View file

@ -13,7 +13,7 @@ Contact information
Circuits At Home, LTD
Web : http://www.circuitsathome.com
e-mail : support@circuitsathome.com
*/
*/
//HD44780 compatible LCD display via MAX3421E GPOUT support header
//pinout: D[4-7] -> GPOUT[4-7], RS-> GPOUT[2], E ->GPOUT[3]
//
@ -91,12 +91,12 @@ public:
void command(uint8_t);
private:
void sendbyte( uint8_t val );
void sendbyte(uint8_t val);
uint8_t _displayfunction; //tokill
uint8_t _displaycontrol;
uint8_t _displaymode;
uint8_t _initialized;
uint8_t _numlines,_currline;
uint8_t _numlines, _currline;
};
#endif

View file

@ -13,19 +13,35 @@ Contact information
Circuits At Home, LTD
Web : http://www.circuitsathome.com
e-mail : support@circuitsathome.com
*/
*/
#include "message.h"
// 0x80 is the default (i.e. trace) to turn off set this global to something lower.
// this allows for 126 other debugging levels.
// TO-DO: Allow assignment to a different serial port
int UsbDEBUGlvl = 0x80;
void Notify(char const * msg)
//void Notify(const char* msg)
{
if(!msg) return;
char c;
while((c = pgm_read_byte(msg++)))
void Notifyc(char c, int lvl) {
if (UsbDEBUGlvl < lvl) return;
#if defined(ARDUINO) && ARDUINO >=100
Serial.print(c);
#else
Serial.print(c,BYTE);
Serial.print(c, BYTE);
#endif
Serial.flush();
}
void Notify(char const * msg, int lvl) {
if (UsbDEBUGlvl < lvl) return;
if (!msg) return;
char c;
while ((c = pgm_read_byte(msg++))) Notifyc(c, lvl);
}
void NotifyStr(char const * msg, int lvl) {
if (UsbDEBUGlvl < lvl) return;
if (!msg) return;
char c;
while (c = *msg++) Notifyc(c, lvl);
}

View file

@ -13,24 +13,26 @@ Contact information
Circuits At Home, LTD
Web : http://www.circuitsathome.com
e-mail : support@circuitsathome.com
*/
*/
#if !defined(__MESSAGE_H__)
#define __MESSAGE_H__
#include <inttypes.h>
#include <avr/pgmspace.h>
void Notify(char const * msg, int lvl);
void NotifyStr(char const * msg, int lvl);
#include "printhex.h"
void Notify(char const * msg);
//void Notify(const char* msg);
template <class ERROR_TYPE>
void ErrorMessage(char const * msg, ERROR_TYPE rcode = 0)
{
Notify(msg);
Notify(PSTR(": "));
PrintHex<ERROR_TYPE>(rcode);
Notify(PSTR("\r\n"));
void ErrorMessage(char const * msg, ERROR_TYPE rcode = 0) {
Notify(msg, 0x80);
Notify(PSTR(": "), 0x80);
PrintHex<ERROR_TYPE > (rcode, 0x80);
Notify(PSTR("\r\n"), 0x80);
}

View file

@ -13,18 +13,16 @@ Contact information
Circuits At Home, LTD
Web : http://www.circuitsathome.com
e-mail : support@circuitsathome.com
*/
*/
#include "parsetools.h"
bool MultiByteValueParser::Parse(uint8_t **pp, uint16_t *pcntdn)
{
if (!pBuf)
{
Notify(PSTR("Buffer pointer is NULL!\r\n"));
bool MultiByteValueParser::Parse(uint8_t **pp, uint16_t *pcntdn) {
if (!pBuf) {
Notify(PSTR("Buffer pointer is NULL!\r\n"), 0x80);
return false;
}
for (; countDown && (*pcntdn); countDown--, (*pcntdn)--, (*pp)++)
pBuf[valueSize-countDown] = (**pp);
pBuf[valueSize - countDown] = (**pp);
if (countDown)
return false;
@ -33,10 +31,8 @@ bool MultiByteValueParser::Parse(uint8_t **pp, uint16_t *pcntdn)
return true;
}
bool PTPListParser::Parse(uint8_t **pp, uint16_t *pcntdn, PTP_ARRAY_EL_FUNC pf, const void *me)
{
switch (nStage)
{
bool PTPListParser::Parse(uint8_t **pp, uint16_t *pcntdn, PTP_ARRAY_EL_FUNC pf, const void *me) {
switch (nStage) {
case 0:
pBuf->valueSize = lenSize;
theParser.Initialize(pBuf);
@ -57,8 +53,7 @@ bool PTPListParser::Parse(uint8_t **pp, uint16_t *pcntdn, PTP_ARRAY_EL_FUNC pf,
nStage = 3;
case 3:
for (; arLenCntdn; arLenCntdn--)
{
for (; arLenCntdn; arLenCntdn--) {
if (!theParser.Parse(pp, pcntdn))
return false;

View file

@ -13,7 +13,7 @@ Contact information
Circuits At Home, LTD
Web : http://www.circuitsathome.com
e-mail : support@circuitsathome.com
*/
*/
#if !defined(__PARSETOOLS_H__)
#define __PARSETOOLS_H__
@ -29,71 +29,72 @@ e-mail : support@circuitsathome.com
#include <WProgram.h>
#endif
struct MultiValueBuffer
{
struct MultiValueBuffer {
uint8_t valueSize;
void *pValue;
};
} __attribute__((packed));
class MultiByteValueParser
{
class MultiByteValueParser {
uint8_t * pBuf;
uint8_t countDown;
uint8_t valueSize;
public:
MultiByteValueParser() : pBuf(NULL), countDown(0), valueSize(0) {};
const uint8_t* GetBuffer() { return pBuf; };
MultiByteValueParser() : pBuf(NULL), countDown(0), valueSize(0) {
};
void Initialize(MultiValueBuffer * const pbuf)
{
pBuf = (uint8_t*)pbuf->pValue;
const uint8_t* GetBuffer() {
return pBuf;
};
void Initialize(MultiValueBuffer * const pbuf) {
pBuf = (uint8_t*) pbuf->pValue;
countDown = valueSize = pbuf->valueSize;
};
bool Parse(uint8_t **pp, uint16_t *pcntdn);
};
class ByteSkipper
{
class ByteSkipper {
uint8_t *pBuf;
uint8_t nStage;
uint16_t countDown;
public:
ByteSkipper() : pBuf(NULL), nStage(0), countDown(0) {};
void Initialize(MultiValueBuffer *pbuf)
{
pBuf = (uint8_t*)pbuf->pValue;
ByteSkipper() : pBuf(NULL), nStage(0), countDown(0) {
};
void Initialize(MultiValueBuffer *pbuf) {
pBuf = (uint8_t*) pbuf->pValue;
countDown = 0;
};
bool Skip(uint8_t **pp, uint16_t *pcntdn, uint16_t bytes_to_skip)
{
switch (nStage)
{
bool Skip(uint8_t **pp, uint16_t *pcntdn, uint16_t bytes_to_skip) {
switch(nStage) {
case 0:
countDown = bytes_to_skip;
nStage ++;
nStage++;
case 1:
for (; countDown && (*pcntdn); countDown--, (*pp)++, (*pcntdn)--);
for(; countDown && (*pcntdn); countDown--, (*pp)++, (*pcntdn)--);
if (!countDown)
if(!countDown)
nStage = 0;
};
return (!countDown);
return(!countDown);
};
};
// Pointer to a callback function triggered for each element of PTP array when used with PTPArrayParser
typedef void (*PTP_ARRAY_EL_FUNC)(const MultiValueBuffer * const p, uint32_t count, const void *me);
class PTPListParser
{
class PTPListParser {
public:
enum ParseMode { modeArray, modeRange/*, modeEnum*/ };
enum ParseMode {
modeArray, modeRange/*, modeEnum*/
};
private:
uint8_t nStage;
@ -113,31 +114,28 @@ private:
uint8_t /*ParseMode*/ prsMode;
public:
PTPListParser() :
pBuf(NULL),
nStage(0),
enStage(0),
arLenCntdn(0),
arLen(0),
arLenCntdn(0),
lenSize(0),
valSize(0),
prsMode(modeArray)
{};
pBuf(NULL),
prsMode(modeArray) {
};
void Initialize(const uint8_t len_size, const uint8_t val_size, MultiValueBuffer * const p, const uint8_t mode = modeArray)
{
void Initialize(const uint8_t len_size, const uint8_t val_size, MultiValueBuffer * const p, const uint8_t mode = modeArray) {
pBuf = p;
lenSize = len_size;
valSize = val_size;
prsMode = mode;
if (prsMode == modeRange)
{
if(prsMode == modeRange) {
arLenCntdn = arLen = 3;
nStage = 2;
}
else
{
} else {
arLenCntdn = arLen = 0;
nStage = 0;
}

View file

@ -13,7 +13,7 @@ Contact information
Circuits At Home, LTD
Web : http://www.circuitsathome.com
e-mail : support@circuitsathome.com
*/
*/
#if !defined(__PRINTHEX_H__)
#define __PRINTHEX_H__
@ -22,45 +22,50 @@ e-mail : support@circuitsathome.com
#else
#include <WProgram.h>
#endif
void Notifyc(char c, int lvl);
template <class T>
void PrintHex(T val)
{
T mask = (((T)1) << (((sizeof(T) << 1) - 1) << 2));
void PrintHex(T val, int lvl) {
int num_nibbles = sizeof(T) * 2;
while (mask > 1)
{
if (val < mask)
Serial.print("0");
mask >>= 4;
}
Serial.print((T)val, HEX);
do {
char v = 48 + (((val >> (num_nibbles - 1) * 4)) & 0x0f);
if(v > 57) v += 7;
Notifyc(v, lvl);
} while(--num_nibbles);
}
template <class T>
void PrintHex2(Print *prn, T val)
{
T mask = (((T)1) << (((sizeof(T) << 1) - 1) << 2));
void PrintBin(T val, int lvl) {
for(T mask = (((T) 1) << ((sizeof(T) << 3) - 1)); mask; mask >>= 1)
if(val & mask)
Notifyc('1', lvl);
else
Notifyc('0', lvl);
}
while (mask > 1)
{
if (val < mask)
template <class T>
void SerialPrintHex(T val) {
int num_nibbles = sizeof(T) * 2;
do {
char v = 48 + (((val >> (num_nibbles - 1) * 4)) & 0x0f);
if(v > 57) v += 7;
Serial.print(v);
} while(--num_nibbles);
}
template <class T>
void PrintHex2(Print *prn, T val) {
T mask = (((T) 1) << (((sizeof(T) << 1) - 1) << 2));
while(mask > 1) {
if(val < mask)
prn->print("0");
mask >>= 4;
}
prn->print((T)val, HEX);
}
template <class T>
void PrintBin(T val)
{
for (T mask = (((T)1) << (sizeof(T) << 3)-1); mask; mask>>=1)
if (val & mask)
Serial.print("1");
else
Serial.print("0");
prn->print((T) val, HEX);
}
#endif // __PRINTHEX_H__

View file

@ -13,7 +13,7 @@ Contact information
Circuits At Home, LTD
Web : http://www.circuitsathome.com
e-mail : support@circuitsathome.com
*/
*/
/* USB chapter 9 structures */
#ifndef _ch9_h_
#define _ch9_h_
@ -108,11 +108,10 @@ typedef struct {
uint8_t iProduct; // Index of String Descriptor describing the product.
uint8_t iSerialNumber; // Index of String Descriptor with the device's serial number.
uint8_t bNumConfigurations; // Number of possible configurations.
} USB_DEVICE_DESCRIPTOR;
} __attribute__((packed)) USB_DEVICE_DESCRIPTOR;
/* Configuration descriptor structure */
typedef struct
{
typedef struct {
uint8_t bLength; // Length of this descriptor.
uint8_t bDescriptorType; // CONFIGURATION descriptor type (USB_DESCRIPTOR_CONFIGURATION).
uint16_t wTotalLength; // Total length of all descriptors for this configuration.
@ -121,11 +120,10 @@ typedef struct
uint8_t iConfiguration; // Index of String Descriptor describing the configuration.
uint8_t bmAttributes; // Configuration characteristics.
uint8_t bMaxPower; // Maximum power consumed by this configuration.
} USB_CONFIGURATION_DESCRIPTOR;
} __attribute__((packed)) USB_CONFIGURATION_DESCRIPTOR;
/* Interface descriptor structure */
typedef struct
{
typedef struct {
uint8_t bLength; // Length of this descriptor.
uint8_t bDescriptorType; // INTERFACE descriptor type (USB_DESCRIPTOR_INTERFACE).
uint8_t bInterfaceNumber; // Number of this interface (0 based).
@ -135,23 +133,20 @@ typedef struct
uint8_t bInterfaceSubClass; // Subclass code (assigned by the USB-IF).
uint8_t bInterfaceProtocol; // Protocol code (assigned by the USB-IF). 0xFF-Vendor specific.
uint8_t iInterface; // Index of String Descriptor describing the interface.
} USB_INTERFACE_DESCRIPTOR;
} __attribute__((packed)) USB_INTERFACE_DESCRIPTOR;
/* Endpoint descriptor structure */
typedef struct
{
typedef struct {
uint8_t bLength; // Length of this descriptor.
uint8_t bDescriptorType; // ENDPOINT descriptor type (USB_DESCRIPTOR_ENDPOINT).
uint8_t bEndpointAddress; // Endpoint address. Bit 7 indicates direction (0=OUT, 1=IN).
uint8_t bmAttributes; // Endpoint transfer type.
uint16_t wMaxPacketSize; // Maximum packet size.
uint8_t bInterval; // Polling interval in frames.
} USB_ENDPOINT_DESCRIPTOR;
} __attribute__((packed)) USB_ENDPOINT_DESCRIPTOR;
/* HID descriptor */
typedef struct
{
typedef struct {
uint8_t bLength;
uint8_t bDescriptorType;
uint16_t bcdHID; // HID class specification release
@ -159,12 +154,11 @@ typedef struct
uint8_t bNumDescriptors; // Number of additional class specific descriptors
uint8_t bDescrType; // Type of class descriptor
uint16_t wDescriptorLength; // Total size of the Report descriptor
} USB_HID_DESCRIPTOR;
} __attribute__((packed)) USB_HID_DESCRIPTOR;
typedef struct
{
typedef struct {
uint8_t bDescrType; // Type of class descriptor
uint16_t wDescriptorLength; // Total size of the Report descriptor
} HID_CLASS_DESCRIPTOR_LEN_AND_TYPE;
} __attribute__((packed)) HID_CLASS_DESCRIPTOR_LEN_AND_TYPE;
#endif // _ch9_h_

220
usbhost.h
View file

@ -13,7 +13,7 @@ Contact information
Circuits At Home, LTD
Web : http://www.circuitsathome.com
e-mail : support@circuitsathome.com
*/
*/
/* MAX3421E-based USB Host Library header file */
#ifndef _USBHOST_H_
#define _USBHOST_H_
@ -22,13 +22,12 @@ e-mail : support@circuitsathome.com
#include "max3421e.h"
#include "usb_ch9.h"
/* SPI initialization */
template< typename CLK, typename MOSI, typename MISO, typename SPI_SS > class SPi
{
public:
template< typename CLK, typename MOSI, typename MISO, typename SPI_SS > class SPi {
public:
static void init() {
uint8_t tmp;
//uint8_t tmp;
CLK::SetDirWrite();
MOSI::SetDirWrite();
MISO::SetDirRead();
@ -37,8 +36,8 @@ template< typename CLK, typename MOSI, typename MISO, typename SPI_SS > class SP
SPCR = 0x50;
SPSR = 0x01;
/**/
tmp = SPSR;
tmp = SPDR;
//tmp = SPSR;
//tmp = SPDR;
}
};
@ -53,21 +52,23 @@ typedef SPi< Pb5, Pb3, Pb4, Pb2 > spi;
typedef SPi< Pb7, Pb5, Pb6, Pb4 > spi;
#endif
template< typename SS, typename INTR > class MAX3421e /* : public spi */
{
template< typename SS, typename INTR > class MAX3421e /* : public spi */ {
static uint8_t vbusState;
public:
public:
MAX3421e();
void regWr( uint8_t reg, uint8_t data );
uint8_t* bytesWr( uint8_t reg, uint8_t nbytes, uint8_t* data_p );
void gpioWr( uint8_t data );
uint8_t regRd( uint8_t reg );
uint8_t* bytesRd( uint8_t reg, uint8_t nbytes, uint8_t* data_p );
void regWr(uint8_t reg, uint8_t data);
uint8_t* bytesWr(uint8_t reg, uint8_t nbytes, uint8_t* data_p);
void gpioWr(uint8_t data);
uint8_t regRd(uint8_t reg);
uint8_t* bytesRd(uint8_t reg, uint8_t nbytes, uint8_t* data_p);
uint8_t gpioRd();
uint16_t reset();
int8_t Init();
uint8_t getVbusState( void ) { return vbusState; };
uint8_t getVbusState(void) {
return vbusState;
};
void busprobe();
uint8_t GpxHandler();
uint8_t IntHandler();
@ -75,121 +76,114 @@ template< typename SS, typename INTR > class MAX3421e /* : public spi */
};
template< typename SS, typename INTR >
uint8_t MAX3421e< SS, INTR >::vbusState = 0;
uint8_t MAX3421e< SS, INTR >::vbusState = 0;
/* constructor */
template< typename SS, typename INTR >
MAX3421e< SS, INTR >::MAX3421e()
{
MAX3421e< SS, INTR >::MAX3421e() {
/* pin and peripheral setup */
SS::SetDirWrite();
SS::Set();
spi::init();
INTR::SetDirRead();
#ifdef BOARD_MEGA_ADK
/* For Mega ADK, which has Max3421e on-board, set MAX_RESET to Output mode, and pull Reset to HIGH */
DDRJ |= _BV(PJ2);
PORTJ &= ~_BV(PJ2);
PORTJ |= _BV(PJ2);
#endif
/* MAX3421E - full-duplex SPI, level interrupt */
regWr( rPINCTL,( bmFDUPSPI + bmINTLEVEL ));
regWr(rPINCTL, (bmFDUPSPI + bmINTLEVEL));
};
/* write single byte into MAX3421 register */
template< typename SS, typename INTR >
void MAX3421e< SS, INTR >::regWr( uint8_t reg, uint8_t data )
{
void MAX3421e< SS, INTR >::regWr(uint8_t reg, uint8_t data) {
SS::Clear();
SPDR = ( reg | 0x02 );
while(!( SPSR & ( 1 << SPIF )));
SPDR = (reg | 0x02);
while(!(SPSR & (1 << SPIF)));
SPDR = data;
while(!( SPSR & ( 1 << SPIF )));
while(!(SPSR & (1 << SPIF)));
SS::Set();
return;
};
/* multiple-byte write */
/* returns a pointer to memory position after last written */
template< typename SS, typename INTR >
uint8_t* MAX3421e< SS, INTR >::bytesWr( uint8_t reg, uint8_t nbytes, uint8_t* data_p )
{
uint8_t* MAX3421e< SS, INTR >::bytesWr(uint8_t reg, uint8_t nbytes, uint8_t* data_p) {
SS::Clear();
SPDR = ( reg | 0x02 ); //set WR bit and send register number
while( nbytes-- ) {
while(!( SPSR & ( 1 << SPIF ))); //check if previous byte was sent
SPDR = ( *data_p ); // send next data byte
SPDR = (reg | 0x02); //set WR bit and send register number
while(nbytes--) {
while(!(SPSR & (1 << SPIF))); //check if previous byte was sent
SPDR = (*data_p); // send next data byte
data_p++; // advance data pointer
}
while(!( SPSR & ( 1 << SPIF )));
while(!(SPSR & (1 << SPIF)));
SS::Set();
return( data_p );
return( data_p);
}
/* GPIO write */
/*GPIO byte is split between 2 registers, so two writes are needed to write one byte */
/* GPOUT bits are in the low nibble. 0-3 in IOPINS1, 4-7 in IOPINS2 */
template< typename SS, typename INTR >
void MAX3421e< SS, INTR >::gpioWr( uint8_t data )
{
regWr( rIOPINS1, data );
void MAX3421e< SS, INTR >::gpioWr(uint8_t data) {
regWr(rIOPINS1, data);
data >>= 4;
regWr( rIOPINS2, data );
regWr(rIOPINS2, data);
return;
}
/* single host register read */
template< typename SS, typename INTR >
uint8_t MAX3421e< SS, INTR >::regRd( uint8_t reg )
{
uint8_t MAX3421e< SS, INTR >::regRd(uint8_t reg) {
SS::Clear();
SPDR = reg;
while(!( SPSR & ( 1 << SPIF )));
while(!(SPSR & (1 << SPIF)));
SPDR = 0; //send empty byte
while(!( SPSR & ( 1 << SPIF )));
while(!(SPSR & (1 << SPIF)));
SS::Set();
return( SPDR );
return( SPDR);
}
/* multiple-byte register read */
/* returns a pointer to a memory position after last read */
template< typename SS, typename INTR >
uint8_t* MAX3421e< SS, INTR >::bytesRd( uint8_t reg, uint8_t nbytes, uint8_t* data_p )
{
uint8_t* MAX3421e< SS, INTR >::bytesRd(uint8_t reg, uint8_t nbytes, uint8_t* data_p) {
SS::Clear();
SPDR = reg;
while(!( SPSR & ( 1 << SPIF ))); //wait
while( nbytes ) {
while(!(SPSR & (1 << SPIF))); //wait
while(nbytes) {
SPDR = 0; //send empty byte
nbytes--;
while(!( SPSR & ( 1 << SPIF )));
while(!(SPSR & (1 << SPIF)));
*data_p = SPDR;
data_p++;
}
SS::Set();
return( data_p );
return( data_p);
}
/* GPIO read. See gpioWr for explanation */
/* GPIN pins are in high nibbles of IOPINS1, IOPINS2 */
template< typename SS, typename INTR >
uint8_t MAX3421e< SS, INTR >::gpioRd()
{
uint8_t MAX3421e< SS, INTR >::gpioRd() {
uint8_t gpin = 0;
gpin = regRd( rIOPINS2 ); //pins 4-7
gpin = regRd(rIOPINS2); //pins 4-7
gpin &= 0xf0; //clean lower nibble
gpin |= ( regRd( rIOPINS1 ) >>4 ) ; //shift low bits and OR with upper from previous operation.
return( gpin );
gpin |= (regRd(rIOPINS1) >> 4); //shift low bits and OR with upper from previous operation.
return( gpin);
}
/* reset MAX3421E. Returns number of cycles it took for PLL to stabilize after reset
or zero if PLL haven't stabilized in 65535 cycles */
template< typename SS, typename INTR >
uint16_t MAX3421e< SS, INTR >::reset()
{
uint16_t MAX3421e< SS, INTR >::reset() {
uint16_t i = 0;
regWr( rUSBCTL, bmCHIPRES );
regWr( rUSBCTL, 0x00 );
while( ++i ) {
if(( regRd( rUSBIRQ ) & bmOSCOKIRQ )) {
regWr(rUSBCTL, bmCHIPRES);
regWr(rUSBCTL, 0x00);
while(++i) {
if((regRd(rUSBIRQ) & bmOSCOKIRQ)) {
break;
}
}
return( i );
return( i);
}
///* initialize MAX3421E. Set Host mode, pullups, and stuff. Returns 0 if success, -1 if not */
//template< typename SS, typename INTR >
@ -202,102 +196,98 @@ uint16_t MAX3421e< SS, INTR >::reset()
//
// return( 0 );
//}
/* initialize MAX3421E. Set Host mode, pullups, and stuff. Returns 0 if success, -1 if not */
template< typename SS, typename INTR >
int8_t MAX3421e< SS, INTR >::Init()
{
if( reset() == 0 )
{ //OSCOKIRQ hasn't asserted in time
return ( -1 );
int8_t MAX3421e< SS, INTR >::Init() {
if(reset() == 0) { //OSCOKIRQ hasn't asserted in time
return( -1);
}
regWr( rMODE, bmDPPULLDN|bmDMPULLDN|bmHOST ); // set pull-downs, Host
regWr(rMODE, bmDPPULLDN | bmDMPULLDN | bmHOST); // set pull-downs, Host
regWr( rHIEN, bmCONDETIE|bmFRAMEIE ); //connection detection
regWr(rHIEN, bmCONDETIE | bmFRAMEIE); //connection detection
/* check if device is connected */
regWr( rHCTL,bmSAMPLEBUS ); // sample USB bus
while(!(regRd( rHCTL ) & bmSAMPLEBUS )); //wait for sample operation to finish
regWr(rHCTL, bmSAMPLEBUS); // sample USB bus
while(!(regRd(rHCTL) & bmSAMPLEBUS)); //wait for sample operation to finish
busprobe(); //check if anything is connected
regWr( rHIRQ, bmCONDETIRQ ); //clear connection detect interrupt
regWr( rCPUCTL, 0x01 ); //enable interrupt pin
return( 0 );
regWr(rHIRQ, bmCONDETIRQ); //clear connection detect interrupt
regWr(rCPUCTL, 0x01); //enable interrupt pin
return( 0);
}
/* probe bus to determine device presense and speed and switch host to this speed */
/* probe bus to determine device presence and speed and switch host to this speed */
template< typename SS, typename INTR >
void MAX3421e< SS, INTR >::busprobe()
{
void MAX3421e< SS, INTR >::busprobe() {
uint8_t bus_sample;
bus_sample = regRd( rHRSL ); //Get J,K status
bus_sample &= ( bmJSTATUS|bmKSTATUS ); //zero the rest of the byte
switch( bus_sample ) { //start full-speed or low-speed host
case( bmJSTATUS ):
if(( regRd( rMODE ) & bmLOWSPEED ) == 0 ) {
regWr( rMODE, MODE_FS_HOST ); //start full-speed host
bus_sample = regRd(rHRSL); //Get J,K status
bus_sample &= (bmJSTATUS | bmKSTATUS); //zero the rest of the byte
switch(bus_sample) { //start full-speed or low-speed host
case( bmJSTATUS):
if((regRd(rMODE) & bmLOWSPEED) == 0) {
regWr(rMODE, MODE_FS_HOST); //start full-speed host
vbusState = FSHOST;
}
else {
regWr( rMODE, MODE_LS_HOST); //start low-speed host
} else {
regWr(rMODE, MODE_LS_HOST); //start low-speed host
vbusState = LSHOST;
}
break;
case( bmKSTATUS ):
if(( regRd( rMODE ) & bmLOWSPEED ) == 0 ) {
regWr( rMODE, MODE_LS_HOST ); //start low-speed host
case( bmKSTATUS):
if((regRd(rMODE) & bmLOWSPEED) == 0) {
regWr(rMODE, MODE_LS_HOST); //start low-speed host
vbusState = LSHOST;
}
else {
regWr( rMODE, MODE_FS_HOST ); //start full-speed host
} else {
regWr(rMODE, MODE_FS_HOST); //start full-speed host
vbusState = FSHOST;
}
break;
case( bmSE1 ): //illegal state
case( bmSE1): //illegal state
vbusState = SE1;
break;
case( bmSE0 ): //disconnected state
regWr( rMODE, bmDPPULLDN|bmDMPULLDN|bmHOST|bmSEPIRQ);
case( bmSE0): //disconnected state
regWr(rMODE, bmDPPULLDN | bmDMPULLDN | bmHOST | bmSEPIRQ);
vbusState = SE0;
break;
}//end switch( bus_sample )
}
/* MAX3421 state change task and interrupt handler */
template< typename SS, typename INTR >
uint8_t MAX3421e< SS, INTR >::Task( void )
{
uint8_t MAX3421e< SS, INTR >::Task(void) {
uint8_t rcode = 0;
uint8_t pinvalue;
//Serial.print("Vbus state: ");
//Serial.println( vbusState, HEX );
pinvalue = INTR::IsSet(); //Read();
//pinvalue = digitalRead( MAX_INT );
if( pinvalue == 0 ) {
if(pinvalue == 0) {
rcode = IntHandler();
}
// pinvalue = digitalRead( MAX_GPX );
// if( pinvalue == LOW ) {
// GpxHandler();
// }
// usbSM(); //USB state machine
return( rcode );
// pinvalue = digitalRead( MAX_GPX );
// if( pinvalue == LOW ) {
// GpxHandler();
// }
// usbSM(); //USB state machine
return( rcode);
}
template< typename SS, typename INTR >
uint8_t MAX3421e< SS, INTR >::IntHandler()
{
uint8_t MAX3421e< SS, INTR >::IntHandler() {
uint8_t HIRQ;
uint8_t HIRQ_sendback = 0x00;
HIRQ = regRd( rHIRQ ); //determine interrupt source
HIRQ = regRd(rHIRQ); //determine interrupt source
//if( HIRQ & bmFRAMEIRQ ) { //->1ms SOF interrupt handler
// HIRQ_sendback |= bmFRAMEIRQ;
//}//end FRAMEIRQ handling
if( HIRQ & bmCONDETIRQ ) {
if(HIRQ & bmCONDETIRQ) {
busprobe();
HIRQ_sendback |= bmCONDETIRQ;
}
/* End HIRQ interrupts handling, clear serviced IRQs */
regWr( rHIRQ, HIRQ_sendback );
return( HIRQ_sendback );
regWr(rHIRQ, HIRQ_sendback);
return( HIRQ_sendback);
}
//template< typename SS, typename INTR >
//uint8_t MAX3421e< SS, INTR >::GpxHandler()

View file

@ -13,19 +13,18 @@ Contact information
Circuits At Home, LTD
Web : http://www.circuitsathome.com
e-mail : support@circuitsathome.com
*/
*/
#include "usbhub.h"
bool USBHub::bResetInitiated = false;
USBHub::USBHub(USB *p) :
pUsb(p),
bAddress(0),
bNbrPorts(0),
bInitState(0),
qNextPollTime(0),
bPollEnable(false)
{
pUsb(p),
bAddress(0),
bNbrPorts(0),
bInitState(0),
qNextPollTime(0),
bPollEnable(false) {
epInfo[0].epAddr = 0;
epInfo[0].maxPktSize = 8;
epInfo[0].epAttribs = 0;
@ -40,8 +39,7 @@ USBHub::USBHub(USB *p) :
pUsb->RegisterDeviceClass(this);
}
uint8_t USBHub::Init(uint8_t parent, uint8_t port, bool lowspeed)
{
uint8_t USBHub::Init(uint8_t parent, uint8_t port, bool lowspeed) {
uint8_t buf[32];
uint8_t rcode;
UsbDevice *p = NULL;
@ -53,8 +51,7 @@ uint8_t USBHub::Init(uint8_t parent, uint8_t port, bool lowspeed)
AddressPool &addrPool = pUsb->GetAddressPool();
switch (bInitState)
{
switch (bInitState) {
case 0:
if (bAddress)
return USB_ERROR_CLASS_INSTANCE_ALREADY_IN_USE;
@ -77,15 +74,14 @@ uint8_t USBHub::Init(uint8_t parent, uint8_t port, bool lowspeed)
p->lowspeed = lowspeed;
// Get device descriptor
rcode = pUsb->getDevDescr( 0, 0, 8, (uint8_t*)buf );
rcode = pUsb->getDevDescr(0, 0, 8, (uint8_t*)buf);
p->lowspeed = false;
if (!rcode)
len = (buf[0] > 32) ? 32 : buf[0];
if( rcode )
{
if (rcode) {
// Restore p->epinfo
p->epinfo = oldep_ptr;
return rcode;
@ -106,10 +102,9 @@ uint8_t USBHub::Init(uint8_t parent, uint8_t port, bool lowspeed)
epInfo[0].maxPktSize = ((USB_DEVICE_DESCRIPTOR*)buf)->bMaxPacketSize0;
// Assign new address to the device
rcode = pUsb->setAddr( 0, 0, bAddress );
rcode = pUsb->setAddr(0, 0, bAddress);
if (rcode)
{
if (rcode) {
// Restore p->epinfo
p->epinfo = oldep_ptr;
addrPool.FreeAddress(bAddress);
@ -123,9 +118,9 @@ uint8_t USBHub::Init(uint8_t parent, uint8_t port, bool lowspeed)
p->epinfo = oldep_ptr;
if (len)
rcode = pUsb->getDevDescr( bAddress, 0, len, (uint8_t*)buf );
rcode = pUsb->getDevDescr(bAddress, 0, len, (uint8_t*)buf);
if(rcode)
if (rcode)
goto FailGetDevDescr;
// Assign epInfo to epinfo pointer
@ -152,8 +147,7 @@ uint8_t USBHub::Init(uint8_t parent, uint8_t port, bool lowspeed)
// Read configuration Descriptor in Order To Obtain Proper Configuration Value
rcode = pUsb->getConfDescr(bAddress, 0, 8, 0, buf);
if (!rcode)
{
if (!rcode) {
cd_len = ((USB_CONFIGURATION_DESCRIPTOR*)buf)->wTotalLength;
rcode = pUsb->getConfDescr(bAddress, 0, cd_len, 0, buf);
}
@ -181,7 +175,7 @@ uint8_t USBHub::Init(uint8_t parent, uint8_t port, bool lowspeed)
case 3:
// Power on all ports
for (uint8_t j=1; j<=bNbrPorts; j++)
for (uint8_t j = 1; j <= bNbrPorts; j++)
SetPortFeature(HUB_FEATURE_PORT_POWER, j, 0); //HubPortPowerOn(j);
pUsb->SetHubPreMask();
@ -206,15 +200,11 @@ FailGetConfDescr:
FailSetConfDescr:
goto Fail;
FailGetPortStatus:
goto Fail;
Fail:
return rcode;
}
uint8_t USBHub::Release()
{
uint8_t USBHub::Release() {
pUsb->GetAddressPool().FreeAddress(bAddress);
if (bAddress == 0x41)
@ -227,23 +217,20 @@ uint8_t USBHub::Release()
return 0;
}
uint8_t USBHub::Poll()
{
uint8_t USBHub::Poll() {
uint8_t rcode = 0;
if (!bPollEnable)
return 0;
if (qNextPollTime <= millis())
{
if (qNextPollTime <= millis()) {
rcode = CheckHubStatus();
qNextPollTime = millis() + 100;
}
return rcode;
}
uint8_t USBHub::CheckHubStatus()
{
uint8_t USBHub::CheckHubStatus() {
uint8_t rcode;
uint8_t buf[8];
uint16_t read = 1;
@ -264,10 +251,8 @@ uint8_t USBHub::CheckHubStatus()
// return rcode;
//}
}
for (uint8_t port=1,mask=0x02; port<8; mask<<=1, port++)
{
if (buf[0] & mask)
{
for (uint8_t port = 1, mask = 0x02; port < 8; mask <<= 1, port++) {
if (buf[0] & mask) {
HubEvent evt;
evt.bmEvent = 0;
@ -286,8 +271,7 @@ uint8_t USBHub::CheckHubStatus()
}
} // for
for (uint8_t port=1; port<=bNbrPorts; port++)
{
for (uint8_t port = 1; port <= bNbrPorts; port++) {
HubEvent evt;
evt.bmEvent = 0;
@ -313,10 +297,8 @@ uint8_t USBHub::CheckHubStatus()
return 0;
}
uint8_t USBHub::PortStatusChange(uint8_t port, HubEvent &evt)
{
switch (evt.bmEvent)
{
uint8_t USBHub::PortStatusChange(uint8_t port, HubEvent &evt) {
switch (evt.bmEvent) {
// Device connected event
case bmHUB_PORT_EVENT_CONNECT:
case bmHUB_PORT_EVENT_LS_CONNECT:
@ -352,7 +334,7 @@ uint8_t USBHub::PortStatusChange(uint8_t port, HubEvent &evt)
a.devAddress = bAddress;
pUsb->Configuring(a.bmAddress, port, (evt.bmStatus & bmHUB_PORT_STATUS_PORT_LOW_SPEED) );
pUsb->Configuring(a.bmAddress, port, (evt.bmStatus & bmHUB_PORT_STATUS_PORT_LOW_SPEED));
bResetInitiated = false;
break;
@ -360,15 +342,13 @@ uint8_t USBHub::PortStatusChange(uint8_t port, HubEvent &evt)
return 0;
}
void PrintHubPortStatus(USBHub *hubptr, uint8_t addr, uint8_t port, bool print_changes)
{
void PrintHubPortStatus(USBHub *hubptr, uint8_t addr, uint8_t port, bool print_changes) {
uint8_t rcode = 0;
HubEvent evt;
rcode = hubptr->GetPortStatus(port, 4, evt.evtBuff);
if (rcode)
{
if (rcode) {
Serial.println("ERROR!");
return;
}
@ -400,7 +380,7 @@ void PrintHubPortStatus(USBHub *hubptr, uint8_t addr, uint8_t port, bool print_c
if (!print_changes)
return;
Serial.println("\nChange");
Serial.println("\r\nChange");
Serial.print("CONNECTION:\t");
Serial.println((evt.bmChange & bmHUB_PORT_STATUS_C_PORT_CONNECTION) > 0, DEC);
Serial.print("ENABLE:\t\t");

100
usbhub.h
View file

@ -13,7 +13,7 @@ Contact information
Circuits At Home, LTD
Web : http://www.circuitsathome.com
e-mail : support@circuitsathome.com
*/
*/
#if !defined(__USBHUB_H__)
#define __USBHUB_H__
@ -25,6 +25,7 @@ e-mail : support@circuitsathome.com
#include "usb_ch9.h"
#include "Usb.h"
#if defined(ARDUINO) && ARDUINO >=100
#include "Arduino.h"
#else
@ -142,42 +143,38 @@ e-mail : support@circuitsathome.com
#define bmHUB_PORT_EVENT_LS_RESET_COMPLETE (((0UL | bmHUB_PORT_STATUS_C_PORT_RESET) << 16) | bmHUB_PORT_STATUS_PORT_POWER | bmHUB_PORT_STATUS_PORT_ENABLE | bmHUB_PORT_STATUS_PORT_CONNECTION | bmHUB_PORT_STATUS_PORT_LOW_SPEED)
#define bmHUB_PORT_EVENT_LS_PORT_ENABLED (((0UL | bmHUB_PORT_STATUS_C_PORT_CONNECTION | bmHUB_PORT_STATUS_C_PORT_ENABLE) << 16) | bmHUB_PORT_STATUS_PORT_POWER | bmHUB_PORT_STATUS_PORT_ENABLE | bmHUB_PORT_STATUS_PORT_CONNECTION | bmHUB_PORT_STATUS_PORT_LOW_SPEED)
struct HubDescriptor
{
struct HubDescriptor {
uint8_t bDescLength; // descriptor length
uint8_t bDescriptorType; // descriptor type
uint8_t bNbrPorts; // number of ports a hub equiped with
struct
{
struct {
uint16_t LogPwrSwitchMode : 2;
uint16_t CompoundDevice : 1;
uint16_t OverCurrentProtectMode : 2;
uint16_t TTThinkTime : 2;
uint16_t PortIndicatorsSupported : 1;
uint16_t Reserved : 8;
};
} __attribute__((packed));
uint8_t bPwrOn2PwrGood;
uint8_t bHubContrCurrent;
};
} __attribute__((packed));
struct HubEvent
{
union
{
struct
{
struct HubEvent {
union {
struct {
uint16_t bmStatus; // port status bits
uint16_t bmChange; // port status change bits
};
} __attribute__((packed));
uint32_t bmEvent;
uint8_t evtBuff[4];
};
};
} __attribute__((packed));
class USBHub : USBDeviceConfig
{
class USBHub : USBDeviceConfig {
static bool bResetInitiated; // True when reset is triggered
USB *pUsb; // USB class instance pointer
@ -196,62 +193,65 @@ class USBHub : USBDeviceConfig
public:
USBHub(USB *p);
uint8_t ClearHubFeature( uint8_t fid );
uint8_t ClearPortFeature( uint8_t fid, uint8_t port, uint8_t sel = 0 );
uint8_t GetHubDescriptor( uint8_t index, uint16_t nbytes, uint8_t *dataptr );
uint8_t GetHubStatus( uint16_t nbytes, uint8_t* dataptr );
uint8_t GetPortStatus( uint8_t port, uint16_t nbytes, uint8_t* dataptr );
uint8_t SetHubDescriptor( uint8_t port, uint16_t nbytes, uint8_t* dataptr );
uint8_t SetHubFeature( uint8_t fid );
uint8_t SetPortFeature( uint8_t fid, uint8_t port, uint8_t sel = 0 );
uint8_t ClearHubFeature(uint8_t fid);
uint8_t ClearPortFeature(uint8_t fid, uint8_t port, uint8_t sel = 0);
uint8_t GetHubDescriptor(uint8_t index, uint16_t nbytes, uint8_t *dataptr);
uint8_t GetHubStatus(uint16_t nbytes, uint8_t* dataptr);
uint8_t GetPortStatus(uint8_t port, uint16_t nbytes, uint8_t* dataptr);
uint8_t SetHubDescriptor(uint8_t port, uint16_t nbytes, uint8_t* dataptr);
uint8_t SetHubFeature(uint8_t fid);
uint8_t SetPortFeature(uint8_t fid, uint8_t port, uint8_t sel = 0);
void PrintHubStatus();
virtual uint8_t Init(uint8_t parent, uint8_t port, bool lowspeed);
virtual uint8_t Release();
virtual uint8_t Poll();
virtual uint8_t GetAddress() { return bAddress; };
virtual uint8_t GetAddress() {
return bAddress;
};
};
// Clear Hub Feature
inline uint8_t USBHub::ClearHubFeature( uint8_t fid )
{
return( pUsb->ctrlReq( bAddress, 0, bmREQ_CLEAR_HUB_FEATURE, USB_REQUEST_CLEAR_FEATURE, fid, 0, 0, 0, 0, NULL, NULL ));
inline uint8_t USBHub::ClearHubFeature(uint8_t fid) {
return( pUsb->ctrlReq(bAddress, 0, bmREQ_CLEAR_HUB_FEATURE, USB_REQUEST_CLEAR_FEATURE, fid, 0, 0, 0, 0, NULL, NULL));
}
// Clear Port Feature
inline uint8_t USBHub::ClearPortFeature( uint8_t fid, uint8_t port, uint8_t sel )
{
return( pUsb->ctrlReq( bAddress, 0, bmREQ_CLEAR_PORT_FEATURE, USB_REQUEST_CLEAR_FEATURE, fid, 0, ((0x0000|port)|(sel<<8)), 0, 0, NULL, NULL ));
inline uint8_t USBHub::ClearPortFeature(uint8_t fid, uint8_t port, uint8_t sel) {
return( pUsb->ctrlReq(bAddress, 0, bmREQ_CLEAR_PORT_FEATURE, USB_REQUEST_CLEAR_FEATURE, fid, 0, ((0x0000 | port) | (sel << 8)), 0, 0, NULL, NULL));
}
// Get Hub Descriptor
inline uint8_t USBHub::GetHubDescriptor( uint8_t index, uint16_t nbytes, uint8_t *dataptr )
{
return( pUsb->ctrlReq( bAddress, 0, bmREQ_GET_HUB_DESCRIPTOR, USB_REQUEST_GET_DESCRIPTOR, index, 0x29, 0, nbytes, nbytes, dataptr, NULL ));
inline uint8_t USBHub::GetHubDescriptor(uint8_t index, uint16_t nbytes, uint8_t *dataptr) {
return( pUsb->ctrlReq(bAddress, 0, bmREQ_GET_HUB_DESCRIPTOR, USB_REQUEST_GET_DESCRIPTOR, index, 0x29, 0, nbytes, nbytes, dataptr, NULL));
}
// Get Hub Status
inline uint8_t USBHub::GetHubStatus( uint16_t nbytes, uint8_t* dataptr )
{
return( pUsb->ctrlReq( bAddress, 0, bmREQ_GET_HUB_STATUS, USB_REQUEST_GET_STATUS, 0, 0, 0x0000, nbytes, nbytes, dataptr, NULL ));
inline uint8_t USBHub::GetHubStatus(uint16_t nbytes, uint8_t* dataptr) {
return( pUsb->ctrlReq(bAddress, 0, bmREQ_GET_HUB_STATUS, USB_REQUEST_GET_STATUS, 0, 0, 0x0000, nbytes, nbytes, dataptr, NULL));
}
// Get Port Status
inline uint8_t USBHub::GetPortStatus( uint8_t port, uint16_t nbytes, uint8_t* dataptr )
{
return( pUsb->ctrlReq( bAddress, 0, bmREQ_GET_PORT_STATUS, USB_REQUEST_GET_STATUS, 0, 0, port, nbytes, nbytes, dataptr, NULL ));
inline uint8_t USBHub::GetPortStatus(uint8_t port, uint16_t nbytes, uint8_t* dataptr) {
return( pUsb->ctrlReq(bAddress, 0, bmREQ_GET_PORT_STATUS, USB_REQUEST_GET_STATUS, 0, 0, port, nbytes, nbytes, dataptr, NULL));
}
// Set Hub Descriptor
inline uint8_t USBHub::SetHubDescriptor( uint8_t port, uint16_t nbytes, uint8_t* dataptr )
{
return( pUsb->ctrlReq( bAddress, 0, bmREQ_SET_HUB_DESCRIPTOR, USB_REQUEST_SET_DESCRIPTOR, 0, 0, port, nbytes, nbytes, dataptr, NULL ));
inline uint8_t USBHub::SetHubDescriptor(uint8_t port, uint16_t nbytes, uint8_t* dataptr) {
return( pUsb->ctrlReq(bAddress, 0, bmREQ_SET_HUB_DESCRIPTOR, USB_REQUEST_SET_DESCRIPTOR, 0, 0, port, nbytes, nbytes, dataptr, NULL));
}
// Set Hub Feature
inline uint8_t USBHub::SetHubFeature( uint8_t fid )
{
return( pUsb->ctrlReq( bAddress, 0, bmREQ_SET_HUB_FEATURE, USB_REQUEST_SET_FEATURE, fid, 0, 0, 0, 0, NULL, NULL ));
inline uint8_t USBHub::SetHubFeature(uint8_t fid) {
return( pUsb->ctrlReq(bAddress, 0, bmREQ_SET_HUB_FEATURE, USB_REQUEST_SET_FEATURE, fid, 0, 0, 0, 0, NULL, NULL));
}
// Set Port Feature
inline uint8_t USBHub::SetPortFeature( uint8_t fid, uint8_t port, uint8_t sel )
{
return( pUsb->ctrlReq( bAddress, 0, bmREQ_SET_PORT_FEATURE, USB_REQUEST_SET_FEATURE, fid, 0, (((0x0000|sel)<<8)|port), 0, 0, NULL, NULL ));
inline uint8_t USBHub::SetPortFeature(uint8_t fid, uint8_t port, uint8_t sel) {
return( pUsb->ctrlReq(bAddress, 0, bmREQ_SET_PORT_FEATURE, USB_REQUEST_SET_FEATURE, fid, 0, (((0x0000 | sel) << 8) | port), 0, 0, NULL, NULL));
}
void PrintHubPortStatus(USB *usbptr, uint8_t addr, uint8_t port, bool print_changes = false);

View file

@ -35,7 +35,7 @@ const uint8_t XBOXLEDS[] PROGMEM = {
0x04, // LED3
0x05, // LED4
0x01 // ALL - Used to blink all LEDs
};
};
/** Buttons on the controllers */
const uint16_t XBOXBUTTONS[] PROGMEM = {
0x0100, // UP
@ -48,7 +48,7 @@ const uint16_t XBOXBUTTONS[] PROGMEM = {
0x4000, // L3
0x8000, // R3
0,0, // Skip L2 and R2 as these are analog buttons
0, 0, // Skip L2 and R2 as these are analog buttons
0x0001, // L1
0x0002, // R1