mirror of
https://github.com/felis/USB_Host_Shield_2.0.git
synced 2024-03-22 11:31:26 +01:00
commit
67d245107b
56 changed files with 17499 additions and 17445 deletions
581
BTD.h
581
BTD.h
|
@ -134,17 +134,17 @@
|
|||
/** All Bluetooth services should include this class. */
|
||||
class BluetoothService {
|
||||
public:
|
||||
/**
|
||||
* Used to pass acldata to the Bluetooth service.
|
||||
* @param ACLData Pointer to the incoming acldata.
|
||||
*/
|
||||
virtual void ACLData(uint8_t* ACLData);
|
||||
/** Used to run the different state machines in the Bluetooth service. */
|
||||
virtual void Run();
|
||||
/** Used to reset the Bluetooth service. */
|
||||
virtual void Reset();
|
||||
/** Used to disconnect both the L2CAP Channel and the HCI Connection for the Bluetooth service. */
|
||||
virtual void disconnect();
|
||||
/**
|
||||
* Used to pass acldata to the Bluetooth service.
|
||||
* @param ACLData Pointer to the incoming acldata.
|
||||
*/
|
||||
virtual void ACLData(uint8_t* ACLData);
|
||||
/** Used to run the different state machines in the Bluetooth service. */
|
||||
virtual void Run();
|
||||
/** Used to reset the Bluetooth service. */
|
||||
virtual void Reset();
|
||||
/** Used to disconnect both the L2CAP Channel and the HCI Connection for the Bluetooth service. */
|
||||
virtual void disconnect();
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -153,299 +153,312 @@ public:
|
|||
*/
|
||||
class BTD : public USBDeviceConfig, public UsbConfigXtracter {
|
||||
public:
|
||||
/**
|
||||
* Constructor for the BTD class.
|
||||
* @param p Pointer to USB class instance.
|
||||
*/
|
||||
BTD(USB *p);
|
||||
/**
|
||||
* Constructor for the BTD class.
|
||||
* @param p Pointer to USB class instance.
|
||||
*/
|
||||
BTD(USB *p);
|
||||
|
||||
/** @name USBDeviceConfig implementation */
|
||||
/**
|
||||
* Initialize the Bluetooth dongle.
|
||||
* @param parent Hub number.
|
||||
* @param port Port number on the hub.
|
||||
* @param lowspeed Speed of the device.
|
||||
* @return 0 on success.
|
||||
*/
|
||||
virtual uint8_t Init(uint8_t parent, uint8_t port, bool lowspeed);
|
||||
/**
|
||||
* Release the USB device.
|
||||
* @return 0 on success.
|
||||
*/
|
||||
virtual uint8_t Release();
|
||||
/**
|
||||
* Poll the USB Input endpoins and run the state machines.
|
||||
* @return 0 on success.
|
||||
*/
|
||||
virtual uint8_t Poll();
|
||||
/**
|
||||
* Get the device address.
|
||||
* @return The device address.
|
||||
*/
|
||||
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; };
|
||||
/**@}*/
|
||||
/** @name USBDeviceConfig implementation */
|
||||
/**
|
||||
* Initialize the Bluetooth dongle.
|
||||
* @param parent Hub number.
|
||||
* @param port Port number on the hub.
|
||||
* @param lowspeed Speed of the device.
|
||||
* @return 0 on success.
|
||||
*/
|
||||
virtual uint8_t Init(uint8_t parent, uint8_t port, bool lowspeed);
|
||||
/**
|
||||
* Release the USB device.
|
||||
* @return 0 on success.
|
||||
*/
|
||||
virtual uint8_t Release();
|
||||
/**
|
||||
* Poll the USB Input endpoins and run the state machines.
|
||||
* @return 0 on success.
|
||||
*/
|
||||
virtual uint8_t Poll();
|
||||
|
||||
/** @name UsbConfigXtracter implementation */
|
||||
/**
|
||||
* UsbConfigXtracter implementation, used to extract endpoint information.
|
||||
* @param conf Configuration value.
|
||||
* @param iface Interface number.
|
||||
* @param alt Alternate setting.
|
||||
* @param proto Interface Protocol.
|
||||
* @param ep Endpoint Descriptor.
|
||||
*/
|
||||
virtual void EndpointXtract(uint8_t conf, uint8_t iface, uint8_t alt, uint8_t proto, const USB_ENDPOINT_DESCRIPTOR *ep);
|
||||
/**@}*/
|
||||
/**
|
||||
* Get the device address.
|
||||
* @return The device address.
|
||||
*/
|
||||
virtual uint8_t GetAddress() {
|
||||
return bAddress;
|
||||
};
|
||||
|
||||
/** 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])
|
||||
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]) {
|
||||
btService[i] = pService;
|
||||
return i; // Return ID
|
||||
}
|
||||
}
|
||||
return -1; // ErrorregisterServiceClass
|
||||
};
|
||||
/**
|
||||
* Used to check if the dongle has been initialized.
|
||||
* @return True if it's ready.
|
||||
*/
|
||||
virtual bool isReady() {
|
||||
return bPollEnable;
|
||||
};
|
||||
/**@}*/
|
||||
|
||||
/** @name HCI Commands */
|
||||
/**
|
||||
* Used to send a HCI Command.
|
||||
* @param data Data to send.
|
||||
* @param nbytes Number of bytes to send.
|
||||
*/
|
||||
void HCI_Command(uint8_t* data, uint16_t nbytes);
|
||||
/** Reset the Bluetooth dongle. */
|
||||
void hci_reset();
|
||||
/** Read the Bluetooth address of the dongle. */
|
||||
void hci_read_bdaddr();
|
||||
/** Read the HCI Version of the Bluetooth dongle. */
|
||||
void hci_read_local_version_information();
|
||||
/**
|
||||
* Set the local name of the Bluetooth dongle.
|
||||
* @param name Desired name.
|
||||
*/
|
||||
void hci_set_local_name(const char* name);
|
||||
/** Enable visibility to other Bluetooth devices. */
|
||||
void hci_write_scan_enable();
|
||||
/** Disable visibility to other Bluetooth devices. */
|
||||
void hci_write_scan_disable();
|
||||
/** Read the remote devices name. */
|
||||
void hci_remote_name();
|
||||
/** Accept the connection with the Bluetooth device. */
|
||||
void hci_accept_connection();
|
||||
/**
|
||||
* Disconnect the HCI connection.
|
||||
* @param handle The HCI Handle for the connection.
|
||||
*/
|
||||
void hci_disconnect(uint16_t handle);
|
||||
/**
|
||||
* Respond with the pin for the connection.
|
||||
* The pin is automatically set for the Wii library,
|
||||
* but can be customized for the SPP library.
|
||||
*/
|
||||
void hci_pin_code_request_reply();
|
||||
/** Respons when no pin was set. */
|
||||
void hci_pin_code_negative_request_reply();
|
||||
/**
|
||||
* Command is used to reply to a Link Key Request event from the BR/EDR Controller
|
||||
* if the Host does not have a stored Link Key for the connection.
|
||||
*/
|
||||
void hci_link_key_request_negative_reply();
|
||||
/** Used to try to authenticate with the remote device. */
|
||||
void hci_authentication_request();
|
||||
/** Start a HCI inquiry. */
|
||||
void hci_inquiry();
|
||||
/** Cancel a HCI inquiry. */
|
||||
void hci_inquiry_cancel();
|
||||
/** Connect to a device. */
|
||||
void hci_connect();
|
||||
/** Used to a set the class of the device. */
|
||||
void hci_write_class_of_device();
|
||||
/**@}*/
|
||||
/** @name UsbConfigXtracter implementation */
|
||||
/**
|
||||
* UsbConfigXtracter implementation, used to extract endpoint information.
|
||||
* @param conf Configuration value.
|
||||
* @param iface Interface number.
|
||||
* @param alt Alternate setting.
|
||||
* @param proto Interface Protocol.
|
||||
* @param ep Endpoint Descriptor.
|
||||
*/
|
||||
virtual void EndpointXtract(uint8_t conf, uint8_t iface, uint8_t alt, uint8_t proto, const USB_ENDPOINT_DESCRIPTOR *ep);
|
||||
/**@}*/
|
||||
|
||||
/** @name L2CAP Commands */
|
||||
/**
|
||||
* Used to send L2CAP Commands.
|
||||
* @param handle HCI Handle.
|
||||
* @param data Data to send.
|
||||
* @param nbytes Number of bytes to send.
|
||||
* @param channelLow,channelHigh Low and high byte of channel to send to.
|
||||
* If argument is omitted then the Standard L2CAP header: Channel ID (0x01) for ACL-U will be used.
|
||||
*/
|
||||
void L2CAP_Command(uint16_t handle, uint8_t* data, uint8_t nbytes, uint8_t channelLow = 0x01, uint8_t channelHigh = 0x00);
|
||||
/**
|
||||
* L2CAP Connection Request.
|
||||
* @param handle HCI handle.
|
||||
* @param rxid Identifier.
|
||||
* @param scid Source Channel Identifier.
|
||||
* @param psm Protocol/Service Multiplexer - see: https://www.bluetooth.org/Technical/AssignedNumbers/logical_link.htm.
|
||||
*/
|
||||
void l2cap_connection_request(uint16_t handle, uint8_t rxid, uint8_t* scid, uint16_t psm);
|
||||
/**
|
||||
* L2CAP Connection Response.
|
||||
* @param handle HCI handle.
|
||||
* @param rxid Identifier.
|
||||
* @param dcid Destination Channel Identifier.
|
||||
* @param scid Source Channel Identifier.
|
||||
* @param result Result - First send ::PENDING and then ::SUCCESSFUL.
|
||||
*/
|
||||
void l2cap_connection_response(uint16_t handle, uint8_t rxid, uint8_t* dcid, uint8_t* scid, uint8_t result);
|
||||
/**
|
||||
* L2CAP Config Request.
|
||||
* @param handle HCI Handle.
|
||||
* @param rxid Identifier.
|
||||
* @param dcid Destination Channel Identifier.
|
||||
*/
|
||||
void l2cap_config_request(uint16_t handle, uint8_t rxid, uint8_t* dcid);
|
||||
/**
|
||||
* L2CAP Config Response.
|
||||
* @param handle HCI Handle.
|
||||
* @param rxid Identifier.
|
||||
* @param scid Source Channel Identifier.
|
||||
*/
|
||||
void l2cap_config_response(uint16_t handle, uint8_t rxid, uint8_t* scid);
|
||||
/**
|
||||
* L2CAP Disconnection Request.
|
||||
* @param handle HCI Handle.
|
||||
* @param rxid Identifier.
|
||||
* @param dcid Device Channel Identifier.
|
||||
* @param scid Source Channel Identifier.
|
||||
*/
|
||||
void l2cap_disconnection_request(uint16_t handle, uint8_t rxid, uint8_t* dcid, uint8_t* scid);
|
||||
/**
|
||||
* L2CAP Disconnection Response.
|
||||
* @param handle HCI Handle.
|
||||
* @param rxid Identifier.
|
||||
* @param dcid Device Channel Identifier.
|
||||
* @param scid Source Channel Identifier.
|
||||
*/
|
||||
void l2cap_disconnection_response(uint16_t handle, uint8_t rxid, uint8_t* dcid, uint8_t* scid);
|
||||
/**
|
||||
* L2CAP Information Response.
|
||||
* @param handle HCI Handle.
|
||||
* @param rxid Identifier.
|
||||
* @param infoTypeLow,infoTypeHigh Infotype.
|
||||
*/
|
||||
void l2cap_information_response(uint16_t handle, uint8_t rxid, uint8_t infoTypeLow, uint8_t infoTypeHigh);
|
||||
/**@}*/
|
||||
/** 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])
|
||||
btService[i]->disconnect();
|
||||
};
|
||||
|
||||
/** Use this to see if it is waiting for a incoming connection. */
|
||||
bool watingForConnection;
|
||||
/** This is used by the service to know when to store the device information. */
|
||||
bool l2capConnectionClaimed;
|
||||
/** This is used by the SPP library to claim the current SDP incoming request. */
|
||||
bool sdpConnectionClaimed;
|
||||
/** This is used by the SPP library to claim the current RFCOMM incoming request. */
|
||||
bool rfcommConnectionClaimed;
|
||||
/**
|
||||
* 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]) {
|
||||
btService[i] = pService;
|
||||
return i; // Return ID
|
||||
}
|
||||
}
|
||||
return -1; // ErrorregisterServiceClass
|
||||
};
|
||||
|
||||
/** The name you wish to make the dongle show up as. It is set automatically by the SPP library. */
|
||||
const char* btdName;
|
||||
/** The pin you wish to make the dongle use for authentication. It is set automatically by the SPP library. */
|
||||
const char* btdPin;
|
||||
/** @name HCI Commands */
|
||||
/**
|
||||
* Used to send a HCI Command.
|
||||
* @param data Data to send.
|
||||
* @param nbytes Number of bytes to send.
|
||||
*/
|
||||
void HCI_Command(uint8_t* data, uint16_t nbytes);
|
||||
/** Reset the Bluetooth dongle. */
|
||||
void hci_reset();
|
||||
/** Read the Bluetooth address of the dongle. */
|
||||
void hci_read_bdaddr();
|
||||
/** Read the HCI Version of the Bluetooth dongle. */
|
||||
void hci_read_local_version_information();
|
||||
/**
|
||||
* Set the local name of the Bluetooth dongle.
|
||||
* @param name Desired name.
|
||||
*/
|
||||
void hci_set_local_name(const char* name);
|
||||
/** Enable visibility to other Bluetooth devices. */
|
||||
void hci_write_scan_enable();
|
||||
/** Disable visibility to other Bluetooth devices. */
|
||||
void hci_write_scan_disable();
|
||||
/** Read the remote devices name. */
|
||||
void hci_remote_name();
|
||||
/** Accept the connection with the Bluetooth device. */
|
||||
void hci_accept_connection();
|
||||
/**
|
||||
* Disconnect the HCI connection.
|
||||
* @param handle The HCI Handle for the connection.
|
||||
*/
|
||||
void hci_disconnect(uint16_t handle);
|
||||
/**
|
||||
* Respond with the pin for the connection.
|
||||
* The pin is automatically set for the Wii library,
|
||||
* but can be customized for the SPP library.
|
||||
*/
|
||||
void hci_pin_code_request_reply();
|
||||
/** Respons when no pin was set. */
|
||||
void hci_pin_code_negative_request_reply();
|
||||
/**
|
||||
* Command is used to reply to a Link Key Request event from the BR/EDR Controller
|
||||
* if the Host does not have a stored Link Key for the connection.
|
||||
*/
|
||||
void hci_link_key_request_negative_reply();
|
||||
/** Used to try to authenticate with the remote device. */
|
||||
void hci_authentication_request();
|
||||
/** Start a HCI inquiry. */
|
||||
void hci_inquiry();
|
||||
/** Cancel a HCI inquiry. */
|
||||
void hci_inquiry_cancel();
|
||||
/** Connect to a device. */
|
||||
void hci_connect();
|
||||
/** Used to a set the class of the device. */
|
||||
void hci_write_class_of_device();
|
||||
/**@}*/
|
||||
|
||||
/** The bluetooth dongles Bluetooth address. */
|
||||
uint8_t my_bdaddr[6];
|
||||
/** HCI handle for the last connection. */
|
||||
uint16_t hci_handle;
|
||||
/** Last incoming devices Bluetooth address. */
|
||||
uint8_t disc_bdaddr[6];
|
||||
/** First 30 chars of last remote name. */
|
||||
uint8_t remote_name[30];
|
||||
/**
|
||||
* The supported HCI Version read from the Bluetooth dongle.
|
||||
* Used by the PS3BT library to check the HCI Version of the Bluetooth dongle,
|
||||
* 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; };
|
||||
/** Used to only send the ACL data to the wiimote. */
|
||||
bool connectToWii;
|
||||
/** True if a Wiimote is connecting. */
|
||||
bool incomingWii;
|
||||
/** True when it should pair with the incoming Wiimote. */
|
||||
bool pairWithWii;
|
||||
/** True if it's the new Wiimote with the Motion Plus Inside or a Wii U Pro Controller. */
|
||||
bool motionPlusInside;
|
||||
/** True if it's a Wii U Pro Controller. */
|
||||
bool wiiUProController;
|
||||
/** @name L2CAP Commands */
|
||||
/**
|
||||
* Used to send L2CAP Commands.
|
||||
* @param handle HCI Handle.
|
||||
* @param data Data to send.
|
||||
* @param nbytes Number of bytes to send.
|
||||
* @param channelLow,channelHigh Low and high byte of channel to send to.
|
||||
* If argument is omitted then the Standard L2CAP header: Channel ID (0x01) for ACL-U will be used.
|
||||
*/
|
||||
void L2CAP_Command(uint16_t handle, uint8_t* data, uint8_t nbytes, uint8_t channelLow = 0x01, uint8_t channelHigh = 0x00);
|
||||
/**
|
||||
* L2CAP Connection Request.
|
||||
* @param handle HCI handle.
|
||||
* @param rxid Identifier.
|
||||
* @param scid Source Channel Identifier.
|
||||
* @param psm Protocol/Service Multiplexer - see: https://www.bluetooth.org/Technical/AssignedNumbers/logical_link.htm.
|
||||
*/
|
||||
void l2cap_connection_request(uint16_t handle, uint8_t rxid, uint8_t* scid, uint16_t psm);
|
||||
/**
|
||||
* L2CAP Connection Response.
|
||||
* @param handle HCI handle.
|
||||
* @param rxid Identifier.
|
||||
* @param dcid Destination Channel Identifier.
|
||||
* @param scid Source Channel Identifier.
|
||||
* @param result Result - First send ::PENDING and then ::SUCCESSFUL.
|
||||
*/
|
||||
void l2cap_connection_response(uint16_t handle, uint8_t rxid, uint8_t* dcid, uint8_t* scid, uint8_t result);
|
||||
/**
|
||||
* L2CAP Config Request.
|
||||
* @param handle HCI Handle.
|
||||
* @param rxid Identifier.
|
||||
* @param dcid Destination Channel Identifier.
|
||||
*/
|
||||
void l2cap_config_request(uint16_t handle, uint8_t rxid, uint8_t* dcid);
|
||||
/**
|
||||
* L2CAP Config Response.
|
||||
* @param handle HCI Handle.
|
||||
* @param rxid Identifier.
|
||||
* @param scid Source Channel Identifier.
|
||||
*/
|
||||
void l2cap_config_response(uint16_t handle, uint8_t rxid, uint8_t* scid);
|
||||
/**
|
||||
* L2CAP Disconnection Request.
|
||||
* @param handle HCI Handle.
|
||||
* @param rxid Identifier.
|
||||
* @param dcid Device Channel Identifier.
|
||||
* @param scid Source Channel Identifier.
|
||||
*/
|
||||
void l2cap_disconnection_request(uint16_t handle, uint8_t rxid, uint8_t* dcid, uint8_t* scid);
|
||||
/**
|
||||
* L2CAP Disconnection Response.
|
||||
* @param handle HCI Handle.
|
||||
* @param rxid Identifier.
|
||||
* @param dcid Device Channel Identifier.
|
||||
* @param scid Source Channel Identifier.
|
||||
*/
|
||||
void l2cap_disconnection_response(uint16_t handle, uint8_t rxid, uint8_t* dcid, uint8_t* scid);
|
||||
/**
|
||||
* L2CAP Information Response.
|
||||
* @param handle HCI Handle.
|
||||
* @param rxid Identifier.
|
||||
* @param infoTypeLow,infoTypeHigh Infotype.
|
||||
*/
|
||||
void l2cap_information_response(uint16_t handle, uint8_t rxid, uint8_t infoTypeLow, uint8_t infoTypeHigh);
|
||||
/**@}*/
|
||||
|
||||
/**
|
||||
* Read the poll interval taken from the endpoint descriptors.
|
||||
* @return The poll interval in ms.
|
||||
*/
|
||||
uint8_t readPollInterval() { return pollInterval; };
|
||||
/** Use this to see if it is waiting for a incoming connection. */
|
||||
bool watingForConnection;
|
||||
/** This is used by the service to know when to store the device information. */
|
||||
bool l2capConnectionClaimed;
|
||||
/** This is used by the SPP library to claim the current SDP incoming request. */
|
||||
bool sdpConnectionClaimed;
|
||||
/** This is used by the SPP library to claim the current RFCOMM incoming request. */
|
||||
bool rfcommConnectionClaimed;
|
||||
|
||||
/** The name you wish to make the dongle show up as. It is set automatically by the SPP library. */
|
||||
const char* btdName;
|
||||
/** The pin you wish to make the dongle use for authentication. It is set automatically by the SPP library. */
|
||||
const char* btdPin;
|
||||
|
||||
/** The bluetooth dongles Bluetooth address. */
|
||||
uint8_t my_bdaddr[6];
|
||||
/** HCI handle for the last connection. */
|
||||
uint16_t hci_handle;
|
||||
/** Last incoming devices Bluetooth address. */
|
||||
uint8_t disc_bdaddr[6];
|
||||
/** First 30 chars of last remote name. */
|
||||
uint8_t remote_name[30];
|
||||
/**
|
||||
* The supported HCI Version read from the Bluetooth dongle.
|
||||
* Used by the PS3BT library to check the HCI Version of the Bluetooth dongle,
|
||||
* 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;
|
||||
};
|
||||
/** Used to only send the ACL data to the wiimote. */
|
||||
bool connectToWii;
|
||||
/** True if a Wiimote is connecting. */
|
||||
bool incomingWii;
|
||||
/** True when it should pair with the incoming Wiimote. */
|
||||
bool pairWithWii;
|
||||
/** True if it's the new Wiimote with the Motion Plus Inside or a Wii U Pro Controller. */
|
||||
bool motionPlusInside;
|
||||
/** True if it's a Wii U Pro Controller. */
|
||||
bool wiiUProController;
|
||||
|
||||
/**
|
||||
* Read the poll interval taken from the endpoint descriptors.
|
||||
* @return The poll interval in ms.
|
||||
*/
|
||||
uint8_t readPollInterval() {
|
||||
return pollInterval;
|
||||
};
|
||||
|
||||
protected:
|
||||
/** Pointer to USB class instance. */
|
||||
USB *pUsb;
|
||||
/** Device address. */
|
||||
uint8_t bAddress;
|
||||
/** Endpoint info structure. */
|
||||
EpInfo epInfo[BTD_MAX_ENDPOINTS];
|
||||
/** Pointer to USB class instance. */
|
||||
USB *pUsb;
|
||||
/** Device address. */
|
||||
uint8_t bAddress;
|
||||
/** Endpoint info structure. */
|
||||
EpInfo epInfo[BTD_MAX_ENDPOINTS];
|
||||
|
||||
/** Configuration number. */
|
||||
uint8_t bConfNum;
|
||||
/** Total number of endpoints in the configuration. */
|
||||
uint8_t bNumEP;
|
||||
/** Next poll time based on poll interval taken from the USB descriptor. */
|
||||
uint32_t qNextPollTime;
|
||||
/** Configuration number. */
|
||||
uint8_t bConfNum;
|
||||
/** Total number of endpoints in the configuration. */
|
||||
uint8_t bNumEP;
|
||||
/** Next poll time based on poll interval taken from the USB descriptor. */
|
||||
uint32_t qNextPollTime;
|
||||
|
||||
/** Bluetooth dongle control endpoint. */
|
||||
static const uint8_t BTD_CONTROL_PIPE;
|
||||
/** HCI event endpoint index. */
|
||||
static const uint8_t BTD_EVENT_PIPE;
|
||||
/** ACL In endpoint index. */
|
||||
static const uint8_t BTD_DATAIN_PIPE;
|
||||
/** ACL Out endpoint index. */
|
||||
static const uint8_t BTD_DATAOUT_PIPE;
|
||||
/** Bluetooth dongle control endpoint. */
|
||||
static const uint8_t BTD_CONTROL_PIPE;
|
||||
/** HCI event endpoint index. */
|
||||
static const uint8_t BTD_EVENT_PIPE;
|
||||
/** ACL In endpoint index. */
|
||||
static const uint8_t BTD_DATAIN_PIPE;
|
||||
/** ACL Out endpoint index. */
|
||||
static const uint8_t BTD_DATAOUT_PIPE;
|
||||
|
||||
/**
|
||||
* Used to print the USB Endpoint Descriptor.
|
||||
* @param ep_ptr Pointer to USB Endpoint Descriptor.
|
||||
*/
|
||||
void PrintEndpointDescriptor(const USB_ENDPOINT_DESCRIPTOR* ep_ptr);
|
||||
/**
|
||||
* Used to print the USB Endpoint Descriptor.
|
||||
* @param ep_ptr Pointer to USB Endpoint Descriptor.
|
||||
*/
|
||||
void PrintEndpointDescriptor(const USB_ENDPOINT_DESCRIPTOR* ep_ptr);
|
||||
|
||||
private:
|
||||
BluetoothService* btService[BTD_NUMSERVICES];
|
||||
BluetoothService* btService[BTD_NUMSERVICES];
|
||||
|
||||
bool bPollEnable;
|
||||
uint8_t pollInterval;
|
||||
bool bPollEnable;
|
||||
uint8_t pollInterval;
|
||||
|
||||
/* Variables used by high level HCI task */
|
||||
uint8_t hci_state; //current state of bluetooth hci connection
|
||||
uint16_t hci_counter; // counter used for bluetooth hci reset loops
|
||||
uint8_t hci_num_reset_loops; // this value indicate how many times it should read before trying to reset
|
||||
uint16_t hci_event_flag; // hci flags of received bluetooth events
|
||||
uint8_t inquiry_counter;
|
||||
/* Variables used by high level HCI task */
|
||||
uint8_t hci_state; //current state of bluetooth hci connection
|
||||
uint16_t hci_counter; // counter used for bluetooth hci reset loops
|
||||
uint8_t hci_num_reset_loops; // this value indicate how many times it should read before trying to reset
|
||||
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
|
||||
void HCI_task(); // HCI state machine
|
||||
void ACL_event_task(); // ACL input pipe
|
||||
/* State machines */
|
||||
void HCI_event_task(); // Poll the HCI event pipe
|
||||
void HCI_task(); // HCI state machine
|
||||
void ACL_event_task(); // ACL input pipe
|
||||
|
||||
/* Used to set the Bluetooth Address internally to the PS3 Controllers */
|
||||
void setBdaddr(uint8_t* BDADDR);
|
||||
void setMoveBdaddr(uint8_t* BDADDR);
|
||||
/* Used to set the Bluetooth Address internally to the PS3 Controllers */
|
||||
void setBdaddr(uint8_t* BDADDR);
|
||||
void setMoveBdaddr(uint8_t* BDADDR);
|
||||
};
|
||||
#endif
|
||||
|
|
330
PS3BT.h
330
PS3BT.h
|
@ -65,182 +65,190 @@
|
|||
*/
|
||||
class PS3BT : public BluetoothService {
|
||||
public:
|
||||
/**
|
||||
* Constructor for the PS3BT class.
|
||||
* @param pBtd Pointer to BTD class instance.
|
||||
* @param btadr5,btadr4,btadr3,btadr2,btadr1,btadr0
|
||||
* 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);
|
||||
/**
|
||||
* Constructor for the PS3BT class.
|
||||
* @param pBtd Pointer to BTD class instance.
|
||||
* @param btadr5,btadr4,btadr3,btadr2,btadr1,btadr0
|
||||
* 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);
|
||||
|
||||
/** @name BluetoothService implementation */
|
||||
/**
|
||||
* Used to pass acldata to the services.
|
||||
* @param ACLData Incoming acldata.
|
||||
*/
|
||||
virtual void ACLData(uint8_t* ACLData);
|
||||
/** Used to run part of the state maschine. */
|
||||
virtual void Run();
|
||||
/** Use this to reset the service. */
|
||||
virtual void Reset();
|
||||
/** Used this to disconnect any of the controllers. */
|
||||
virtual void disconnect();
|
||||
/**@}*/
|
||||
/** @name BluetoothService implementation */
|
||||
/**
|
||||
* Used to pass acldata to the services.
|
||||
* @param ACLData Incoming acldata.
|
||||
*/
|
||||
virtual void ACLData(uint8_t* ACLData);
|
||||
/** Used to run part of the state maschine. */
|
||||
virtual void Run();
|
||||
/** Use this to reset the service. */
|
||||
virtual void Reset();
|
||||
/** Used this to disconnect any of the controllers. */
|
||||
virtual void disconnect();
|
||||
/**@}*/
|
||||
|
||||
/** @name PS3 Controller functions */
|
||||
/**
|
||||
* getButtonPress(Button b) will return true as long as the button is held down.
|
||||
*
|
||||
* While getButtonClick(Button b) will only return it once.
|
||||
*
|
||||
* So you instance if you need to increase a variable once you would use getButtonClick(Button b),
|
||||
* but if you need to drive a robot forward you would use getButtonPress(Button b).
|
||||
*/
|
||||
bool getButtonPress(Button b);
|
||||
bool getButtonClick(Button b);
|
||||
/**@}*/
|
||||
/** @name PS3 Controller functions */
|
||||
/**
|
||||
* Used to get the analog value from button presses.
|
||||
* @param a The ::Button to read.
|
||||
* The supported buttons are:
|
||||
* ::UP, ::RIGHT, ::DOWN, ::LEFT, ::L1, ::L2, ::R1, ::R2,
|
||||
* ::TRIANGLE, ::CIRCLE, ::CROSS, ::SQUARE, and ::T.
|
||||
* @return Analog value in the range of 0-255.
|
||||
*/
|
||||
uint8_t getAnalogButton(Button a);
|
||||
/**
|
||||
* Used to read the analog joystick.
|
||||
* @param a ::LeftHatX, ::LeftHatY, ::RightHatX, and ::RightHatY.
|
||||
* @return Return the analog value in the range of 0-255.
|
||||
*/
|
||||
uint8_t getAnalogHat(AnalogHat a);
|
||||
/**
|
||||
* Used to read the sensors inside the Dualshock 3 and Move controller.
|
||||
* @param a
|
||||
* The Dualshock 3 has a 3-axis accelerometer and a 1-axis gyro inside.
|
||||
* The Move controller has a 3-axis accelerometer, a 3-axis gyro, a 3-axis magnetometer
|
||||
* and a temperature sensor inside.
|
||||
* @return Return the raw sensor value.
|
||||
*/
|
||||
int16_t getSensor(Sensor a);
|
||||
/**
|
||||
* Use this to get ::Pitch and ::Roll calculated using the accelerometer.
|
||||
* @param a Either ::Pitch or ::Roll.
|
||||
* @return Return the angle in the range of 0-360.
|
||||
*/
|
||||
double getAngle(Angle a);
|
||||
/**
|
||||
* Read the sensors inside the Move controller.
|
||||
* @param a ::aXmove, ::aYmove, ::aZmove, ::gXmove, ::gYmove, ::gZmove, ::mXmove, ::mYmove, and ::mXmove.
|
||||
* @return The value in SI units.
|
||||
*/
|
||||
double get9DOFValues(Sensor a);
|
||||
/**
|
||||
* Get the ::Status from the controller.
|
||||
* @param c The ::Status you want to read.
|
||||
* @return True if correct and false if not.
|
||||
*/
|
||||
bool getStatus(Status c);
|
||||
/**
|
||||
* Read all the available ::Status from the controller.
|
||||
* @return One large string with all the information.
|
||||
*/
|
||||
String getStatusString();
|
||||
/**
|
||||
* Read the temperature from the Move controller.
|
||||
* @return The temperature in degrees celsius.
|
||||
*/
|
||||
String getTemperature();
|
||||
/** @name PS3 Controller functions */
|
||||
/**
|
||||
* getButtonPress(Button b) will return true as long as the button is held down.
|
||||
*
|
||||
* While getButtonClick(Button b) will only return it once.
|
||||
*
|
||||
* So you instance if you need to increase a variable once you would use getButtonClick(Button b),
|
||||
* but if you need to drive a robot forward you would use getButtonPress(Button b).
|
||||
*/
|
||||
bool getButtonPress(Button b);
|
||||
bool getButtonClick(Button b);
|
||||
/**@}*/
|
||||
/** @name PS3 Controller functions */
|
||||
/**
|
||||
* Used to get the analog value from button presses.
|
||||
* @param a The ::Button to read.
|
||||
* The supported buttons are:
|
||||
* ::UP, ::RIGHT, ::DOWN, ::LEFT, ::L1, ::L2, ::R1, ::R2,
|
||||
* ::TRIANGLE, ::CIRCLE, ::CROSS, ::SQUARE, and ::T.
|
||||
* @return Analog value in the range of 0-255.
|
||||
*/
|
||||
uint8_t getAnalogButton(Button a);
|
||||
/**
|
||||
* Used to read the analog joystick.
|
||||
* @param a ::LeftHatX, ::LeftHatY, ::RightHatX, and ::RightHatY.
|
||||
* @return Return the analog value in the range of 0-255.
|
||||
*/
|
||||
uint8_t getAnalogHat(AnalogHat a);
|
||||
/**
|
||||
* Used to read the sensors inside the Dualshock 3 and Move controller.
|
||||
* @param a
|
||||
* The Dualshock 3 has a 3-axis accelerometer and a 1-axis gyro inside.
|
||||
* The Move controller has a 3-axis accelerometer, a 3-axis gyro, a 3-axis magnetometer
|
||||
* and a temperature sensor inside.
|
||||
* @return Return the raw sensor value.
|
||||
*/
|
||||
int16_t getSensor(Sensor a);
|
||||
/**
|
||||
* Use this to get ::Pitch and ::Roll calculated using the accelerometer.
|
||||
* @param a Either ::Pitch or ::Roll.
|
||||
* @return Return the angle in the range of 0-360.
|
||||
*/
|
||||
double getAngle(Angle a);
|
||||
/**
|
||||
* Read the sensors inside the Move controller.
|
||||
* @param a ::aXmove, ::aYmove, ::aZmove, ::gXmove, ::gYmove, ::gZmove, ::mXmove, ::mYmove, and ::mXmove.
|
||||
* @return The value in SI units.
|
||||
*/
|
||||
double get9DOFValues(Sensor a);
|
||||
/**
|
||||
* Get the ::Status from the controller.
|
||||
* @param c The ::Status you want to read.
|
||||
* @return True if correct and false if not.
|
||||
*/
|
||||
bool getStatus(Status c);
|
||||
/**
|
||||
* Read all the available ::Status from the controller.
|
||||
* @return One large string with all the information.
|
||||
*/
|
||||
String getStatusString();
|
||||
/**
|
||||
* Read the temperature from the Move controller.
|
||||
* @return The temperature in degrees celsius.
|
||||
*/
|
||||
String getTemperature();
|
||||
|
||||
/** Used to set all LEDs and ::Rumble off. */
|
||||
void setAllOff();
|
||||
/** Turn off ::Rumble. */
|
||||
void setRumbleOff();
|
||||
/**
|
||||
* Turn on ::Rumble.
|
||||
* @param mode Either ::RumbleHigh or ::RumbleLow.
|
||||
*/
|
||||
void setRumbleOn(Rumble mode);
|
||||
/**
|
||||
* Turn the specific ::LED off.
|
||||
* @param a The ::LED to turn off.
|
||||
*/
|
||||
void setLedOff(LED a);
|
||||
/**
|
||||
* Turn the specific ::LED on.
|
||||
* @param a The ::LED to turn on.
|
||||
*/
|
||||
void setLedOn(LED a);
|
||||
/**
|
||||
* Toggle the specific ::LED.
|
||||
* @param a The ::LED to toggle.
|
||||
*/
|
||||
void setLedToggle(LED a);
|
||||
/** Used to set all LEDs and ::Rumble off. */
|
||||
void setAllOff();
|
||||
/** Turn off ::Rumble. */
|
||||
void setRumbleOff();
|
||||
/**
|
||||
* Turn on ::Rumble.
|
||||
* @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.
|
||||
*/
|
||||
void setLedOff(LED a);
|
||||
/**
|
||||
* Turn the specific ::LED on.
|
||||
* @param a The ::LED to turn on.
|
||||
*/
|
||||
void setLedOn(LED a);
|
||||
/**
|
||||
* Toggle the specific ::LED.
|
||||
* @param a The ::LED to toggle.
|
||||
*/
|
||||
void setLedToggle(LED a);
|
||||
|
||||
/**
|
||||
* Use this to set the Color using RGB values.
|
||||
* @param r,g,b RGB value.
|
||||
*/
|
||||
void moveSetBulb(uint8_t r, uint8_t g, uint8_t b);
|
||||
/**
|
||||
* Use this to set the color using the predefined colors in ::Colors.
|
||||
* @param color The desired color.
|
||||
*/
|
||||
void moveSetBulb(Colors color);
|
||||
/**
|
||||
* Set the rumble value inside the Move controller.
|
||||
* @param rumble The desired value in the range from 64-255.
|
||||
*/
|
||||
void moveSetRumble(uint8_t rumble);
|
||||
/**@}*/
|
||||
/**
|
||||
* Use this to set the Color using RGB values.
|
||||
* @param r,g,b RGB value.
|
||||
*/
|
||||
void moveSetBulb(uint8_t r, uint8_t g, uint8_t b);
|
||||
/**
|
||||
* Use this to set the color using the predefined colors in ::Colors.
|
||||
* @param color The desired color.
|
||||
*/
|
||||
void moveSetBulb(Colors color);
|
||||
/**
|
||||
* Set the rumble value inside the Move controller.
|
||||
* @param rumble The desired value in the range from 64-255.
|
||||
*/
|
||||
void moveSetRumble(uint8_t rumble);
|
||||
/**@}*/
|
||||
|
||||
/** Variable used to indicate if the normal playstation controller is successfully connected. */
|
||||
bool PS3Connected;
|
||||
/** Variable used to indicate if the move controller is successfully connected. */
|
||||
bool PS3MoveConnected;
|
||||
/** Variable used to indicate if the navigation controller is successfully connected. */
|
||||
bool PS3NavigationConnected;
|
||||
/** Variable used to indicate if the normal playstation controller is successfully connected. */
|
||||
bool PS3Connected;
|
||||
/** Variable used to indicate if the move controller is successfully connected. */
|
||||
bool PS3MoveConnected;
|
||||
/** Variable used to indicate if the navigation controller is successfully connected. */
|
||||
bool PS3NavigationConnected;
|
||||
|
||||
private:
|
||||
/* mandatory members */
|
||||
BTD *pBtd;
|
||||
/* mandatory members */
|
||||
BTD *pBtd;
|
||||
|
||||
void L2CAP_task(); // L2CAP state machine
|
||||
void L2CAP_task(); // L2CAP state machine
|
||||
|
||||
/* Variables filled from HCI event management */
|
||||
int16_t hci_handle;
|
||||
uint8_t remote_name[30]; // First 30 chars of remote name
|
||||
bool activeConnection; // Used to indicate if it's already has established a connection
|
||||
/* Variables filled from HCI event management */
|
||||
int16_t hci_handle;
|
||||
uint8_t remote_name[30]; // First 30 chars of remote name
|
||||
bool activeConnection; // Used to indicate if it's already has established a connection
|
||||
|
||||
/* variables used by high level L2CAP task */
|
||||
uint8_t l2cap_state;
|
||||
uint16_t l2cap_event_flag; // L2CAP flags of received bluetooth events
|
||||
/* variables used by high level L2CAP task */
|
||||
uint8_t l2cap_state;
|
||||
uint16_t l2cap_event_flag; // L2CAP flags of received bluetooth events
|
||||
|
||||
unsigned long timer;
|
||||
unsigned long timer;
|
||||
|
||||
uint32_t ButtonState;
|
||||
uint32_t OldButtonState;
|
||||
uint32_t ButtonClickState;
|
||||
uint32_t ButtonState;
|
||||
uint32_t OldButtonState;
|
||||
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 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
|
||||
|
||||
uint8_t l2capinbuf[BULK_MAXPKTSIZE]; // General purpose buffer for L2CAP in data
|
||||
uint8_t HIDBuffer[HID_BUFFERSIZE]; // Used to store HID commands
|
||||
uint8_t HIDMoveBuffer[HID_BUFFERSIZE]; // Used to store HID commands for the Move controller
|
||||
uint8_t l2capinbuf[BULK_MAXPKTSIZE]; // General purpose buffer for L2CAP in data
|
||||
uint8_t HIDBuffer[HID_BUFFERSIZE]; // Used to store HID commands
|
||||
uint8_t HIDMoveBuffer[HID_BUFFERSIZE]; // Used to store HID commands for the Move controller
|
||||
|
||||
/* L2CAP Channels */
|
||||
uint8_t control_scid[2]; // L2CAP source CID for HID_Control
|
||||
uint8_t control_dcid[2]; // 0x0040
|
||||
uint8_t interrupt_scid[2]; // L2CAP source CID for HID_Interrupt
|
||||
uint8_t interrupt_dcid[2]; // 0x0041
|
||||
uint8_t identifier; // Identifier for connection
|
||||
/* L2CAP Channels */
|
||||
uint8_t control_scid[2]; // L2CAP source CID for HID_Control
|
||||
uint8_t control_dcid[2]; // 0x0040
|
||||
uint8_t interrupt_scid[2]; // L2CAP source CID for HID_Interrupt
|
||||
uint8_t interrupt_dcid[2]; // 0x0041
|
||||
uint8_t identifier; // Identifier for connection
|
||||
|
||||
/* HID Commands */
|
||||
void HID_Command(uint8_t* data, uint8_t nbytes);
|
||||
void HIDMove_Command(uint8_t* data, uint8_t nbytes);
|
||||
void enable_sixaxis(); // Command used to enable the Dualshock 3 and Navigation controller to send data via Bluetooth
|
||||
/* HID Commands */
|
||||
void HID_Command(uint8_t* data, uint8_t nbytes);
|
||||
void HIDMove_Command(uint8_t* data, uint8_t nbytes);
|
||||
void enable_sixaxis(); // Command used to enable the Dualshock 3 and Navigation controller to send data via Bluetooth
|
||||
};
|
||||
#endif
|
233
PS3Enums.h
233
PS3Enums.h
|
@ -22,17 +22,17 @@
|
|||
|
||||
/** Used to set the LEDs on the controllers */
|
||||
const uint8_t LEDS[] PROGMEM = {
|
||||
0x01, // LED1
|
||||
0x02, // LED2
|
||||
0x04, // LED3
|
||||
0x08, // LED4
|
||||
0x01, // LED1
|
||||
0x02, // LED2
|
||||
0x04, // LED3
|
||||
0x08, // LED4
|
||||
|
||||
0x09, // LED5
|
||||
0x0A, // LED6
|
||||
0x0C, // LED7
|
||||
0x0D, // LED8
|
||||
0x0E, // LED9
|
||||
0x0F // LED10
|
||||
0x09, // LED5
|
||||
0x0A, // LED6
|
||||
0x0C, // LED7
|
||||
0x0D, // LED8
|
||||
0x0E, // LED9
|
||||
0x0F // LED10
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -41,29 +41,29 @@ const uint8_t LEDS[] PROGMEM = {
|
|||
* <B>Note:</B> that the location is shiftet 9 when it's connected via USB.
|
||||
*/
|
||||
const uint32_t BUTTONS[] PROGMEM = {
|
||||
0x10, // UP
|
||||
0x20, // RIGHT
|
||||
0x40, // DOWN
|
||||
0x80, // LEFT
|
||||
0x10, // UP
|
||||
0x20, // RIGHT
|
||||
0x40, // DOWN
|
||||
0x80, // LEFT
|
||||
|
||||
0x01, // SELECT
|
||||
0x08, // START
|
||||
0x02, // L3
|
||||
0x04, // R3
|
||||
0x01, // SELECT
|
||||
0x08, // START
|
||||
0x02, // L3
|
||||
0x04, // R3
|
||||
|
||||
0x0100, // L2
|
||||
0x0200, // R2
|
||||
0x0400, // L1
|
||||
0x0800, // R1
|
||||
0x0100, // L2
|
||||
0x0200, // R2
|
||||
0x0400, // L1
|
||||
0x0800, // R1
|
||||
|
||||
0x1000, // TRIANGLE
|
||||
0x2000, // CIRCLE
|
||||
0x4000, // CROSS
|
||||
0x8000, // SQUARE
|
||||
0x1000, // TRIANGLE
|
||||
0x2000, // CIRCLE
|
||||
0x4000, // CROSS
|
||||
0x8000, // SQUARE
|
||||
|
||||
0x010000, // PS
|
||||
0x080000, // MOVE - covers 12 bits - we only need to read the top 8
|
||||
0x100000 // T - covers 12 bits - we only need to read the top 8
|
||||
0x010000, // PS
|
||||
0x080000, // MOVE - covers 12 bits - we only need to read the top 8
|
||||
0x100000 // T - covers 12 bits - we only need to read the top 8
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -72,46 +72,46 @@ const uint32_t BUTTONS[] PROGMEM = {
|
|||
* <B>Note:</B> that the location is shiftet 9 when it's connected via USB.
|
||||
*/
|
||||
const uint8_t ANALOGBUTTONS[] PROGMEM = {
|
||||
23, // UP_ANALOG
|
||||
24, // RIGHT_ANALOG
|
||||
25, // DOWN_ANALOG
|
||||
26, // LEFT_ANALOG
|
||||
0,0,0,0, // Skip SELECT, L3, R3 and START
|
||||
23, // UP_ANALOG
|
||||
24, // RIGHT_ANALOG
|
||||
25, // DOWN_ANALOG
|
||||
26, // LEFT_ANALOG
|
||||
0, 0, 0, 0, // Skip SELECT, L3, R3 and START
|
||||
|
||||
27, // L2_ANALOG
|
||||
28, // R2_ANALOG
|
||||
29, // L1_ANALOG
|
||||
30, // R1_ANALOG
|
||||
31, // TRIANGLE_ANALOG
|
||||
32, // CIRCLE_ANALOG
|
||||
33, // CROSS_ANALOG
|
||||
34, // SQUARE_ANALOG
|
||||
0,0, // Skip PS and MOVE
|
||||
27, // L2_ANALOG
|
||||
28, // R2_ANALOG
|
||||
29, // L1_ANALOG
|
||||
30, // R1_ANALOG
|
||||
31, // TRIANGLE_ANALOG
|
||||
32, // CIRCLE_ANALOG
|
||||
33, // CROSS_ANALOG
|
||||
34, // SQUARE_ANALOG
|
||||
0, 0, // Skip PS and MOVE
|
||||
|
||||
// Playstation Move Controller
|
||||
15 // T_ANALOG - Both at byte 14 (last reading) and byte 15 (current reading)
|
||||
// Playstation Move Controller
|
||||
15 // T_ANALOG - Both at byte 14 (last reading) and byte 15 (current reading)
|
||||
};
|
||||
|
||||
/** Used to set the colors of the move controller. */
|
||||
enum Colors {
|
||||
/** r = 255, g = 0, b = 0 */
|
||||
Red = 0xFF0000,
|
||||
/** r = 0, g = 255, b = 0 */
|
||||
Green = 0xFF00,
|
||||
/** r = 0, g = 0, b = 255 */
|
||||
Blue = 0xFF,
|
||||
/** r = 255, g = 0, b = 0 */
|
||||
Red = 0xFF0000,
|
||||
/** r = 0, g = 255, b = 0 */
|
||||
Green = 0xFF00,
|
||||
/** r = 0, g = 0, b = 255 */
|
||||
Blue = 0xFF,
|
||||
|
||||
/** r = 255, g = 235, b = 4 */
|
||||
Yellow = 0xFFEB04,
|
||||
/** r = 0, g = 255, b = 255 */
|
||||
Lightblue = 0xFFFF,
|
||||
/** r = 255, g = 0, b = 255 */
|
||||
Purble = 0xFF00FF,
|
||||
/** r = 255, g = 235, b = 4 */
|
||||
Yellow = 0xFFEB04,
|
||||
/** r = 0, g = 255, b = 255 */
|
||||
Lightblue = 0xFFFF,
|
||||
/** r = 255, g = 0, b = 255 */
|
||||
Purble = 0xFF00FF,
|
||||
|
||||
/** r = 255, g = 255, b = 255 */
|
||||
White = 0xFFFFFF,
|
||||
/** r = 0, g = 0, b = 0 */
|
||||
Off = 0x00,
|
||||
/** r = 255, g = 255, b = 255 */
|
||||
White = 0xFFFFFF,
|
||||
/** r = 0, g = 0, b = 0 */
|
||||
Off = 0x00,
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -120,74 +120,77 @@ enum Colors {
|
|||
* <B>Note:</B> that the location is shiftet 9 when it's connected via USB.
|
||||
*/
|
||||
enum Sensor {
|
||||
/** Accelerometer x-axis */
|
||||
aX = 50,
|
||||
/** Accelerometer y-axis */
|
||||
aY = 52,
|
||||
/** Accelerometer z-axis */
|
||||
aZ = 54,
|
||||
/** Gyro z-axis */
|
||||
gZ = 56,
|
||||
/** Accelerometer x-axis */
|
||||
aX = 50,
|
||||
/** Accelerometer y-axis */
|
||||
aY = 52,
|
||||
/** Accelerometer z-axis */
|
||||
aZ = 54,
|
||||
/** Gyro z-axis */
|
||||
gZ = 56,
|
||||
|
||||
/** Accelerometer x-axis */
|
||||
aXmove = 28,
|
||||
/** Accelerometer z-axis */
|
||||
aZmove = 30,
|
||||
/** Accelerometer y-axis */
|
||||
aYmove = 32,
|
||||
/** Accelerometer x-axis */
|
||||
aXmove = 28,
|
||||
/** Accelerometer z-axis */
|
||||
aZmove = 30,
|
||||
/** Accelerometer y-axis */
|
||||
aYmove = 32,
|
||||
|
||||
/** Gyro x-axis */
|
||||
gXmove = 40,
|
||||
/** Gyro z-axis */
|
||||
gZmove = 42,
|
||||
/** Gyro y-axis */
|
||||
gYmove = 44,
|
||||
/** Gyro x-axis */
|
||||
gXmove = 40,
|
||||
/** Gyro z-axis */
|
||||
gZmove = 42,
|
||||
/** Gyro y-axis */
|
||||
gYmove = 44,
|
||||
|
||||
/** Temperature sensor */
|
||||
tempMove = 46,
|
||||
/** Temperature sensor */
|
||||
tempMove = 46,
|
||||
|
||||
/** Magnetometer x-axis */
|
||||
mXmove = 47,
|
||||
/** Magnetometer z-axis */
|
||||
mZmove = 49,
|
||||
/** Magnetometer y-axis */
|
||||
mYmove = 50,
|
||||
/** Magnetometer x-axis */
|
||||
mXmove = 47,
|
||||
/** Magnetometer z-axis */
|
||||
mZmove = 49,
|
||||
/** Magnetometer y-axis */
|
||||
mYmove = 50,
|
||||
};
|
||||
|
||||
/** Used to get the angle calculated using the accelerometer. */
|
||||
enum Angle {
|
||||
Pitch = 0x01,
|
||||
Roll = 0x02,
|
||||
Pitch = 0x01,
|
||||
Roll = 0x02,
|
||||
};
|
||||
|
||||
enum Status {
|
||||
// Note that the location is shiftet 9 when it's connected via USB
|
||||
// Byte location | bit location
|
||||
Plugged = (38 << 8) | 0x02,
|
||||
Unplugged = (38 << 8) | 0x03,
|
||||
// Note that the location is shiftet 9 when it's connected via USB
|
||||
// Byte location | bit location
|
||||
Plugged = (38 << 8) | 0x02,
|
||||
Unplugged = (38 << 8) | 0x03,
|
||||
|
||||
Charging = (39 << 8) | 0xEE,
|
||||
NotCharging = (39 << 8) | 0xF1,
|
||||
Shutdown = (39 << 8) | 0x01,
|
||||
Dying = (39 << 8) | 0x02,
|
||||
Low = (39 << 8) | 0x03,
|
||||
High = (39 << 8) | 0x04,
|
||||
Full = (39 << 8) | 0x05,
|
||||
Charging = (39 << 8) | 0xEE,
|
||||
NotCharging = (39 << 8) | 0xF1,
|
||||
Shutdown = (39 << 8) | 0x01,
|
||||
Dying = (39 << 8) | 0x02,
|
||||
Low = (39 << 8) | 0x03,
|
||||
High = (39 << 8) | 0x04,
|
||||
Full = (39 << 8) | 0x05,
|
||||
|
||||
MoveCharging = (21 << 8) | 0xEE,
|
||||
MoveNotCharging = (21 << 8) | 0xF1,
|
||||
MoveShutdown = (21 << 8) | 0x01,
|
||||
MoveDying = (21 << 8) | 0x02,
|
||||
MoveLow = (21 << 8) | 0x03,
|
||||
MoveHigh = (21 << 8) | 0x04,
|
||||
MoveFull = (21 << 8) | 0x05,
|
||||
MoveCharging = (21 << 8) | 0xEE,
|
||||
MoveNotCharging = (21 << 8) | 0xF1,
|
||||
MoveShutdown = (21 << 8) | 0x01,
|
||||
MoveDying = (21 << 8) | 0x02,
|
||||
MoveLow = (21 << 8) | 0x03,
|
||||
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,
|
||||
RumbleHigh = 0x10,
|
||||
RumbleLow = 0x20,
|
||||
};
|
||||
|
||||
#endif
|
806
PS3USB.cpp
806
PS3USB.cpp
|
@ -21,531 +21,545 @@
|
|||
//#define PRINTREPORT // Uncomment to print the report send by the PS3 Controllers
|
||||
|
||||
const uint8_t PS3_REPORT_BUFFER[] PROGMEM = {
|
||||
0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0xff, 0x27, 0x10, 0x00, 0x32,
|
||||
0xff, 0x27, 0x10, 0x00, 0x32,
|
||||
0xff, 0x27, 0x10, 0x00, 0x32,
|
||||
0xff, 0x27, 0x10, 0x00, 0x32,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
|
||||
0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0xff, 0x27, 0x10, 0x00, 0x32,
|
||||
0xff, 0x27, 0x10, 0x00, 0x32,
|
||||
0xff, 0x27, 0x10, 0x00, 0x32,
|
||||
0xff, 0x27, 0x10, 0x00, 0x32,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
|
||||
};
|
||||
const uint8_t MOVE_REPORT_BUFFER[] PROGMEM = {
|
||||
0x02, 0x00, // Always 0x02, 0x00,
|
||||
0x00, 0x00, 0x00, // r, g, b,
|
||||
0x00, // Always 0x00,
|
||||
0x00 // Rumble
|
||||
0x02, 0x00, // Always 0x02, 0x00,
|
||||
0x00, 0x00, 0x00, // r, g, b,
|
||||
0x00, // Always 0x00,
|
||||
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++) {
|
||||
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;
|
||||
}
|
||||
for (uint8_t i = 0; i < PS3_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;
|
||||
}
|
||||
|
||||
if (pUsb) // register in USB subsystem
|
||||
pUsb->RegisterDeviceClass(this); //set devConfig[] entry
|
||||
if (pUsb) // register in USB subsystem
|
||||
pUsb->RegisterDeviceClass(this); //set devConfig[] entry
|
||||
|
||||
my_bdaddr[5] = btadr5; // Change to your dongle's Bluetooth address instead
|
||||
my_bdaddr[4] = btadr4;
|
||||
my_bdaddr[3] = btadr3;
|
||||
my_bdaddr[2] = btadr2;
|
||||
my_bdaddr[1] = btadr1;
|
||||
my_bdaddr[0] = btadr0;
|
||||
my_bdaddr[5] = btadr5; // Change to your dongle's Bluetooth address instead
|
||||
my_bdaddr[4] = btadr4;
|
||||
my_bdaddr[3] = btadr3;
|
||||
my_bdaddr[2] = btadr2;
|
||||
my_bdaddr[1] = btadr1;
|
||||
my_bdaddr[0] = btadr0;
|
||||
}
|
||||
|
||||
uint8_t PS3USB::Init(uint8_t parent, uint8_t port, bool lowspeed) {
|
||||
uint8_t buf[sizeof(USB_DEVICE_DESCRIPTOR)];
|
||||
uint8_t rcode;
|
||||
UsbDevice *p = NULL;
|
||||
EpInfo *oldep_ptr = NULL;
|
||||
uint16_t PID;
|
||||
uint16_t VID;
|
||||
uint8_t buf[sizeof (USB_DEVICE_DESCRIPTOR)];
|
||||
uint8_t rcode;
|
||||
UsbDevice *p = NULL;
|
||||
EpInfo *oldep_ptr = NULL;
|
||||
uint16_t PID;
|
||||
uint16_t VID;
|
||||
|
||||
// get memory address of USB device address pool
|
||||
AddressPool &addrPool = pUsb->GetAddressPool();
|
||||
// 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) {
|
||||
// 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;
|
||||
}
|
||||
|
||||
// Get pointer to pseudo device with address 0 assigned
|
||||
p = addrPool.GetUsbDevicePtr(0);
|
||||
|
||||
if (!p) {
|
||||
#ifdef DEBUG
|
||||
Notify(PSTR("\r\nAddress not found"));
|
||||
#endif
|
||||
return USB_ERROR_ADDRESS_NOT_FOUND_IN_POOL;
|
||||
}
|
||||
|
||||
if (!p->epinfo) {
|
||||
#ifdef DEBUG
|
||||
Notify(PSTR("\r\nepinfo is null"));
|
||||
#endif
|
||||
return USB_ERROR_EPINFO_IS_NULL;
|
||||
}
|
||||
|
||||
// Save old pointer to EP_RECORD of address 0
|
||||
oldep_ptr = p->epinfo;
|
||||
|
||||
// Temporary assign new pointer to epInfo to p->epinfo in order to avoid toggle inconsistence
|
||||
p->epinfo = epInfo;
|
||||
|
||||
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
|
||||
// Restore p->epinfo
|
||||
p->epinfo = oldep_ptr;
|
||||
|
||||
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))
|
||||
goto FailUnknownDevice;
|
||||
|
||||
// Allocate new address according to device class
|
||||
bAddress = addrPool.AllocAddress(parent, false, port);
|
||||
|
||||
if (!bAddress)
|
||||
return USB_ERROR_OUT_OF_ADDRESS_SPACE_IN_POOL;
|
||||
|
||||
// Extract Max Packet Size from device descriptor
|
||||
epInfo[0].maxPktSize = (uint8_t)((USB_DEVICE_DESCRIPTOR*)buf)->bMaxPacketSize0;
|
||||
|
||||
// Assign new address to the device
|
||||
rcode = pUsb->setAddr( 0, 0, bAddress );
|
||||
if (rcode) {
|
||||
p->lowspeed = false;
|
||||
addrPool.FreeAddress(bAddress);
|
||||
bAddress = 0;
|
||||
#ifdef DEBUG
|
||||
Notify(PSTR("\r\nsetAddr: "));
|
||||
#endif
|
||||
PrintHex<uint8_t>(rcode);
|
||||
return rcode;
|
||||
}
|
||||
#ifdef EXTRADEBUG
|
||||
Notify(PSTR("\r\nAddr: "));
|
||||
PrintHex<uint8_t>(bAddress);
|
||||
#endif
|
||||
p->lowspeed = false;
|
||||
|
||||
//get pointer to assigned address record
|
||||
p = addrPool.GetUsbDevicePtr(bAddress);
|
||||
if (!p)
|
||||
return USB_ERROR_ADDRESS_NOT_FOUND_IN_POOL;
|
||||
|
||||
p->lowspeed = lowspeed;
|
||||
|
||||
// Assign epInfo to epinfo pointer - only EP0 is known
|
||||
rcode = pUsb->setEpInfoEntry(bAddress, 1, epInfo);
|
||||
if (rcode)
|
||||
goto FailSetDevTblEntry;
|
||||
|
||||
|
||||
/* The application will work in reduced host mode, so we can save program and data
|
||||
memory space. After verifying the PID and VID we will use known values for the
|
||||
configuration values for device, interface, endpoints and HID for the PS3 Controllers */
|
||||
|
||||
/* Initialize data structures for endpoints of device */
|
||||
epInfo[ PS3_OUTPUT_PIPE ].epAddr = 0x02; // PS3 output endpoint
|
||||
epInfo[ PS3_OUTPUT_PIPE ].epAttribs = EP_INTERRUPT;
|
||||
epInfo[ PS3_OUTPUT_PIPE ].bmNakPower = USB_NAK_NOWAIT; // Only poll once for interrupt endpoints
|
||||
epInfo[ PS3_OUTPUT_PIPE ].maxPktSize = EP_MAXPKTSIZE;
|
||||
epInfo[ PS3_OUTPUT_PIPE ].bmSndToggle = bmSNDTOG0;
|
||||
epInfo[ PS3_OUTPUT_PIPE ].bmRcvToggle = bmRCVTOG0;
|
||||
epInfo[ PS3_INPUT_PIPE ].epAddr = 0x01; // PS3 report endpoint
|
||||
epInfo[ PS3_INPUT_PIPE ].epAttribs = EP_INTERRUPT;
|
||||
epInfo[ PS3_INPUT_PIPE ].bmNakPower = USB_NAK_NOWAIT; // Only poll once for interrupt endpoints
|
||||
epInfo[ PS3_INPUT_PIPE ].maxPktSize = EP_MAXPKTSIZE;
|
||||
epInfo[ PS3_INPUT_PIPE ].bmSndToggle = bmSNDTOG0;
|
||||
epInfo[ PS3_INPUT_PIPE ].bmRcvToggle = bmRCVTOG0;
|
||||
|
||||
rcode = pUsb->setEpInfoEntry(bAddress, 3, epInfo);
|
||||
if( rcode )
|
||||
goto FailSetDevTblEntry;
|
||||
|
||||
delay(200);//Give time for address change
|
||||
|
||||
rcode = pUsb->setConf(bAddress, epInfo[ PS3_CONTROL_PIPE ].epAddr, 1);
|
||||
if( rcode )
|
||||
goto FailSetConf;
|
||||
|
||||
if(PID == PS3_PID || PID == PS3NAVIGATION_PID) {
|
||||
if(PID == PS3_PID) {
|
||||
#ifdef DEBUG
|
||||
Notify(PSTR("\r\nDualshock 3 Controller Connected"));
|
||||
#endif
|
||||
PS3Connected = true;
|
||||
} else { // must be a navigation controller
|
||||
#ifdef DEBUG
|
||||
Notify(PSTR("\r\nNavigation Controller Connected"));
|
||||
#endif
|
||||
PS3NavigationConnected = true;
|
||||
return USB_ERROR_CLASS_INSTANCE_ALREADY_IN_USE;
|
||||
}
|
||||
/* Set internal bluetooth address and request for data */
|
||||
setBdaddr(my_bdaddr);
|
||||
enable_sixaxis();
|
||||
setLedOn(LED1);
|
||||
|
||||
// Needed for PS3 Dualshock and Navigation commands to work
|
||||
for (uint8_t i = 0; i < PS3_REPORT_BUFFER_SIZE; i++)
|
||||
writeBuf[i] = pgm_read_byte(&PS3_REPORT_BUFFER[i]);
|
||||
// Get pointer to pseudo device with address 0 assigned
|
||||
p = addrPool.GetUsbDevicePtr(0);
|
||||
|
||||
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
|
||||
if (!p) {
|
||||
#ifdef DEBUG
|
||||
Notify(PSTR("\r\nMotion Controller Connected"));
|
||||
Notify(PSTR("\r\nAddress not found"), 0x80);
|
||||
#endif
|
||||
PS3MoveConnected = true;
|
||||
setMoveBdaddr(my_bdaddr); // Set internal bluetooth address
|
||||
moveSetBulb(Red);
|
||||
return USB_ERROR_ADDRESS_NOT_FOUND_IN_POOL;
|
||||
}
|
||||
|
||||
// Needed for Move commands to work
|
||||
for (uint8_t i = 0; i < MOVE_REPORT_BUFFER_SIZE; i++)
|
||||
writeBuf[i] = pgm_read_byte(&MOVE_REPORT_BUFFER[i]);
|
||||
}
|
||||
if (!p->epinfo) {
|
||||
#ifdef DEBUG
|
||||
Notify(PSTR("\r\nepinfo is null"), 0x80);
|
||||
#endif
|
||||
return USB_ERROR_EPINFO_IS_NULL;
|
||||
}
|
||||
|
||||
bPollEnable = true;
|
||||
Notify(PSTR("\r\n"));
|
||||
timer = millis();
|
||||
return 0; // successful configuration
|
||||
// Save old pointer to EP_RECORD of address 0
|
||||
oldep_ptr = p->epinfo;
|
||||
|
||||
/* diagnostic messages */
|
||||
// Temporary assign new pointer to epInfo to p->epinfo in order to avoid toggle inconsistence
|
||||
p->epinfo = epInfo;
|
||||
|
||||
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
|
||||
// Restore p->epinfo
|
||||
p->epinfo = oldep_ptr;
|
||||
|
||||
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))
|
||||
goto FailUnknownDevice;
|
||||
|
||||
// Allocate new address according to device class
|
||||
bAddress = addrPool.AllocAddress(parent, false, port);
|
||||
|
||||
if (!bAddress)
|
||||
return USB_ERROR_OUT_OF_ADDRESS_SPACE_IN_POOL;
|
||||
|
||||
// Extract Max Packet Size from device descriptor
|
||||
epInfo[0].maxPktSize = (uint8_t)((USB_DEVICE_DESCRIPTOR*)buf)->bMaxPacketSize0;
|
||||
|
||||
// Assign new address to the device
|
||||
rcode = pUsb->setAddr(0, 0, bAddress);
|
||||
if (rcode) {
|
||||
p->lowspeed = false;
|
||||
addrPool.FreeAddress(bAddress);
|
||||
bAddress = 0;
|
||||
#ifdef DEBUG
|
||||
Notify(PSTR("\r\nsetAddr: "), 0x80);
|
||||
#endif
|
||||
PrintHex<uint8_t > (rcode, 0x80);
|
||||
return rcode;
|
||||
}
|
||||
#ifdef EXTRADEBUG
|
||||
Notify(PSTR("\r\nAddr: "), 0x80);
|
||||
PrintHex<uint8_t > (bAddress, 0x80);
|
||||
#endif
|
||||
p->lowspeed = false;
|
||||
|
||||
//get pointer to assigned address record
|
||||
p = addrPool.GetUsbDevicePtr(bAddress);
|
||||
if (!p)
|
||||
return USB_ERROR_ADDRESS_NOT_FOUND_IN_POOL;
|
||||
|
||||
p->lowspeed = lowspeed;
|
||||
|
||||
// Assign epInfo to epinfo pointer - only EP0 is known
|
||||
rcode = pUsb->setEpInfoEntry(bAddress, 1, epInfo);
|
||||
if (rcode)
|
||||
goto FailSetDevTblEntry;
|
||||
|
||||
|
||||
/* The application will work in reduced host mode, so we can save program and data
|
||||
memory space. After verifying the PID and VID we will use known values for the
|
||||
configuration values for device, interface, endpoints and HID for the PS3 Controllers */
|
||||
|
||||
/* Initialize data structures for endpoints of device */
|
||||
epInfo[ PS3_OUTPUT_PIPE ].epAddr = 0x02; // PS3 output endpoint
|
||||
epInfo[ PS3_OUTPUT_PIPE ].epAttribs = EP_INTERRUPT;
|
||||
epInfo[ PS3_OUTPUT_PIPE ].bmNakPower = USB_NAK_NOWAIT; // Only poll once for interrupt endpoints
|
||||
epInfo[ PS3_OUTPUT_PIPE ].maxPktSize = EP_MAXPKTSIZE;
|
||||
epInfo[ PS3_OUTPUT_PIPE ].bmSndToggle = bmSNDTOG0;
|
||||
epInfo[ PS3_OUTPUT_PIPE ].bmRcvToggle = bmRCVTOG0;
|
||||
epInfo[ PS3_INPUT_PIPE ].epAddr = 0x01; // PS3 report endpoint
|
||||
epInfo[ PS3_INPUT_PIPE ].epAttribs = EP_INTERRUPT;
|
||||
epInfo[ PS3_INPUT_PIPE ].bmNakPower = USB_NAK_NOWAIT; // Only poll once for interrupt endpoints
|
||||
epInfo[ PS3_INPUT_PIPE ].maxPktSize = EP_MAXPKTSIZE;
|
||||
epInfo[ PS3_INPUT_PIPE ].bmSndToggle = bmSNDTOG0;
|
||||
epInfo[ PS3_INPUT_PIPE ].bmRcvToggle = bmRCVTOG0;
|
||||
|
||||
rcode = pUsb->setEpInfoEntry(bAddress, 3, epInfo);
|
||||
if (rcode)
|
||||
goto FailSetDevTblEntry;
|
||||
|
||||
delay(200); //Give time for address change
|
||||
|
||||
rcode = pUsb->setConf(bAddress, epInfo[ PS3_CONTROL_PIPE ].epAddr, 1);
|
||||
if (rcode)
|
||||
goto FailSetConf;
|
||||
|
||||
if (PID == PS3_PID || PID == PS3NAVIGATION_PID) {
|
||||
if (PID == PS3_PID) {
|
||||
#ifdef DEBUG
|
||||
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"), 0x80);
|
||||
#endif
|
||||
PS3NavigationConnected = true;
|
||||
}
|
||||
/* Set internal bluetooth address and request for data */
|
||||
setBdaddr(my_bdaddr);
|
||||
enable_sixaxis();
|
||||
setLedOn(LED1);
|
||||
|
||||
// Needed for PS3 Dualshock and Navigation commands to work
|
||||
for (uint8_t i = 0; i < PS3_REPORT_BUFFER_SIZE; i++)
|
||||
writeBuf[i] = pgm_read_byte(&PS3_REPORT_BUFFER[i]);
|
||||
|
||||
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
|
||||
#ifdef DEBUG
|
||||
Notify(PSTR("\r\nMotion Controller Connected"), 0x80);
|
||||
#endif
|
||||
PS3MoveConnected = true;
|
||||
setMoveBdaddr(my_bdaddr); // Set internal bluetooth address
|
||||
moveSetBulb(Red);
|
||||
|
||||
// Needed for Move commands to work
|
||||
for (uint8_t i = 0; i < MOVE_REPORT_BUFFER_SIZE; i++)
|
||||
writeBuf[i] = pgm_read_byte(&MOVE_REPORT_BUFFER[i]);
|
||||
}
|
||||
|
||||
bPollEnable = true;
|
||||
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;
|
||||
goto Fail;
|
||||
FailSetDevTblEntry:
|
||||
#ifdef DEBUG
|
||||
Notify(PSTR("\r\nsetDevTblEn:"));
|
||||
Notify(PSTR("\r\nsetDevTblEn:"), 0x80);
|
||||
#endif
|
||||
goto Fail;
|
||||
goto Fail;
|
||||
FailSetConf:
|
||||
#ifdef DEBUG
|
||||
Notify(PSTR("\r\nsetConf:"));
|
||||
Notify(PSTR("\r\nsetConf:"), 0x80);
|
||||
#endif
|
||||
goto Fail;
|
||||
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;
|
||||
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;
|
||||
Release();
|
||||
return rcode;
|
||||
}
|
||||
|
||||
/* Performs a cleanup after failed Init() attempt */
|
||||
uint8_t PS3USB::Release() {
|
||||
PS3Connected = false;
|
||||
PS3MoveConnected = false;
|
||||
PS3NavigationConnected = false;
|
||||
pUsb->GetAddressPool().FreeAddress(bAddress);
|
||||
bAddress = 0;
|
||||
bPollEnable = false;
|
||||
return 0;
|
||||
PS3Connected = false;
|
||||
PS3MoveConnected = false;
|
||||
PS3NavigationConnected = false;
|
||||
pUsb->GetAddressPool().FreeAddress(bAddress);
|
||||
bAddress = 0;
|
||||
bPollEnable = false;
|
||||
return 0;
|
||||
}
|
||||
uint8_t PS3USB::Poll() {
|
||||
if (!bPollEnable)
|
||||
return 0;
|
||||
|
||||
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
|
||||
readReport();
|
||||
uint8_t PS3USB::Poll() {
|
||||
if (!bPollEnable)
|
||||
return 0;
|
||||
|
||||
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
|
||||
readReport();
|
||||
#ifdef PRINTREPORT
|
||||
printReport(); // Uncomment "#define PRINTREPORT" to print the report send by the PS3 Controllers
|
||||
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
|
||||
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
|
||||
timer = millis();
|
||||
}
|
||||
}
|
||||
}
|
||||
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
|
||||
timer = millis();
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void PS3USB::readReport() {
|
||||
if (readBuf == NULL)
|
||||
return;
|
||||
if (readBuf == NULL)
|
||||
return;
|
||||
|
||||
ButtonState = (uint32_t)(readBuf[2] | ((uint16_t)readBuf[3] << 8) | ((uint32_t)readBuf[4] << 16));
|
||||
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) {
|
||||
ButtonClickState = ButtonState & ~OldButtonState; // Update click state variable
|
||||
OldButtonState = ButtonState;
|
||||
}
|
||||
if (ButtonState != OldButtonState) {
|
||||
ButtonClickState = ButtonState & ~OldButtonState; // Update click state variable
|
||||
OldButtonState = ButtonState;
|
||||
}
|
||||
}
|
||||
|
||||
void PS3USB::printReport() { //Uncomment "#define PRINTREPORT" to print the report send by the PS3 Controllers
|
||||
#ifdef PRINTREPORT
|
||||
if (readBuf == NULL)
|
||||
return;
|
||||
for(uint8_t i = 0; i < PS3_REPORT_BUFFER_SIZE;i++) {
|
||||
PrintHex<uint8_t>(readBuf[i]);
|
||||
Serial.print(" ");
|
||||
}
|
||||
Serial.println();
|
||||
if (readBuf == NULL)
|
||||
return;
|
||||
for (uint8_t i = 0; i < PS3_REPORT_BUFFER_SIZE; i++) {
|
||||
PrintHex<uint8_t > (readBuf[i], 0x80);
|
||||
Serial.print(" ");
|
||||
}
|
||||
Serial.println();
|
||||
#endif
|
||||
}
|
||||
|
||||
bool PS3USB::getButtonPress(Button b) {
|
||||
return (ButtonState & pgm_read_dword(&BUTTONS[(uint8_t)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;
|
||||
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]);
|
||||
if (readBuf == NULL)
|
||||
return 0;
|
||||
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)]);
|
||||
if (readBuf == NULL)
|
||||
return 0;
|
||||
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]);
|
||||
if (readBuf == NULL)
|
||||
return 0;
|
||||
return ((readBuf[((uint16_t)a) - 9] << 8) | readBuf[((uint16_t)a + 1) - 9]);
|
||||
}
|
||||
|
||||
double PS3USB::getAngle(Angle a) {
|
||||
if(PS3Connected) {
|
||||
double accXval;
|
||||
double accYval;
|
||||
double accZval;
|
||||
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);
|
||||
// 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);
|
||||
|
||||
// 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;
|
||||
return angle;
|
||||
} else {
|
||||
double angle = (atan2(accXval,accZval)+PI)*RAD_TO_DEG;
|
||||
return angle;
|
||||
}
|
||||
} else
|
||||
return 0;
|
||||
// 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;
|
||||
return angle;
|
||||
} else {
|
||||
double angle = (atan2(accXval, accZval) + PI) * RAD_TO_DEG;
|
||||
return angle;
|
||||
}
|
||||
} else
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool PS3USB::getStatus(Status c) {
|
||||
if (readBuf == NULL)
|
||||
if (readBuf == NULL)
|
||||
return false;
|
||||
if (readBuf[((uint16_t)c >> 8) - 9] == ((uint8_t)c & 0xff))
|
||||
return true;
|
||||
return false;
|
||||
if (readBuf[((uint16_t)c >> 8)-9] == ((uint8_t)c & 0xff))
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
String PS3USB::getStatusString() {
|
||||
if (PS3Connected || PS3NavigationConnected) {
|
||||
char statusOutput[100];
|
||||
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;
|
||||
}
|
||||
return statusOutput;
|
||||
}
|
||||
}
|
||||
|
||||
/* 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);
|
||||
//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);
|
||||
}
|
||||
|
||||
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
|
||||
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[3] = 0x00;
|
||||
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 == RumbleHigh) {
|
||||
writeBuf[2] = 0;//low mode off
|
||||
writeBuf[4] = 0xff;//high mode on
|
||||
}
|
||||
else {
|
||||
writeBuf[2] = 0xff;//low mode on
|
||||
writeBuf[4] = 0;//high mode off
|
||||
}
|
||||
PS3_Command(writeBuf, PS3_REPORT_BUFFER_SIZE);
|
||||
}
|
||||
}
|
||||
|
||||
void PS3USB::setRumbleOff() {
|
||||
writeBuf[1] = 0x00;
|
||||
writeBuf[2] = 0x00; //low mode off
|
||||
writeBuf[3] = 0x00;
|
||||
writeBuf[4] = 0x00; //high mode off
|
||||
|
||||
PS3_Command(writeBuf, PS3_REPORT_BUFFER_SIZE);
|
||||
}
|
||||
|
||||
void PS3USB::setRumbleOn(Rumble mode) {
|
||||
if ((mode & 0x30) > 0x00) {
|
||||
uint8_t power[2] = { 0xff, 0x00 }; // Defaults to RumbleLow
|
||||
if (mode == RumbleHigh) {
|
||||
power[0] = 0x00;
|
||||
power[1] = 0xff;
|
||||
}
|
||||
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);
|
||||
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);
|
||||
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);
|
||||
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
|
||||
/* 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
|
||||
|
||||
//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);
|
||||
//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);
|
||||
#ifdef DEBUG
|
||||
Notify(PSTR("\r\nBluetooth Address was set to: "));
|
||||
for(int8_t i = 5; i > 0; i--) {
|
||||
PrintHex<uint8_t>(my_bdaddr[i]);
|
||||
Serial.print(":");
|
||||
}
|
||||
PrintHex<uint8_t>(my_bdaddr[0]);
|
||||
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], 0x80);
|
||||
#endif
|
||||
return;
|
||||
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[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);
|
||||
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[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);
|
||||
}
|
||||
|
||||
/* Playstation Move Controller commands */
|
||||
void PS3USB::Move_Command(uint8_t* data, uint16_t nbytes) {
|
||||
pUsb->outTransfer(bAddress, epInfo[ PS3_OUTPUT_PIPE ].epAddr, nbytes, data);
|
||||
pUsb->outTransfer(bAddress, epInfo[ PS3_OUTPUT_PIPE ].epAddr, nbytes, data);
|
||||
}
|
||||
|
||||
void PS3USB::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
|
||||
writeBuf[2] = r;
|
||||
writeBuf[3] = g;
|
||||
writeBuf[4] = b;
|
||||
// set the Bulb's values into the write buffer
|
||||
writeBuf[2] = r;
|
||||
writeBuf[3] = g;
|
||||
writeBuf[4] = b;
|
||||
|
||||
Move_Command(writeBuf, MOVE_REPORT_BUFFER_SIZE);
|
||||
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;
|
||||
//set the rumble value into the write buffer
|
||||
writeBuf[6] = rumble;
|
||||
|
||||
Move_Command(writeBuf, MOVE_REPORT_BUFFER_SIZE);
|
||||
Move_Command(writeBuf, MOVE_REPORT_BUFFER_SIZE);
|
||||
}
|
||||
|
||||
void PS3USB::setMoveBdaddr(uint8_t* BDADDR) {
|
||||
/* Set the internal bluetooth address */
|
||||
uint8_t buf[11];
|
||||
buf[0] = 0x05;
|
||||
buf[7] = 0x10;
|
||||
buf[8] = 0x01;
|
||||
buf[9] = 0x02;
|
||||
buf[10] = 0x12;
|
||||
/* Set the internal bluetooth address */
|
||||
uint8_t buf[11];
|
||||
buf[0] = 0x05;
|
||||
buf[7] = 0x10;
|
||||
buf[8] = 0x01;
|
||||
buf[9] = 0x02;
|
||||
buf[10] = 0x12;
|
||||
|
||||
for (uint8_t i = 0; i < 6; i++)
|
||||
buf[i + 1] = BDADDR[i];
|
||||
for (uint8_t i = 0; i < 6; i++)
|
||||
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);
|
||||
//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);
|
||||
#ifdef DEBUG
|
||||
Notify(PSTR("\r\nBluetooth Address was set to: "));
|
||||
for(int8_t i = 5; i > 0; i--) {
|
||||
PrintHex<uint8_t>(my_bdaddr[i]);
|
||||
Serial.print(":");
|
||||
}
|
||||
PrintHex<uint8_t>(my_bdaddr[0]);
|
||||
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], 0x80);
|
||||
#endif
|
||||
return;
|
||||
return;
|
||||
}
|
346
PS3USB.h
346
PS3USB.h
|
@ -63,186 +63,200 @@
|
|||
*/
|
||||
class PS3USB : public USBDeviceConfig {
|
||||
public:
|
||||
/**
|
||||
* Constructor for the PS3USB class.
|
||||
* @param pUsb Pointer to USB class instance.
|
||||
* @param btadr5,btadr4,btadr3,btadr2,btadr1,btadr0
|
||||
* 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);
|
||||
/**
|
||||
* Constructor for the PS3USB class.
|
||||
* @param pUsb Pointer to USB class instance.
|
||||
* @param btadr5,btadr4,btadr3,btadr2,btadr1,btadr0
|
||||
* 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);
|
||||
|
||||
/** @name USBDeviceConfig implementation */
|
||||
/**
|
||||
* Initialize the PS3 Controller.
|
||||
* @param parent Hub number.
|
||||
* @param port Port number on the hub.
|
||||
* @param lowspeed Speed of the device.
|
||||
* @return 0 on success.
|
||||
*/
|
||||
virtual uint8_t Init(uint8_t parent, uint8_t port, bool lowspeed);
|
||||
/**
|
||||
* Release the USB device.
|
||||
* @return 0 on success.
|
||||
*/
|
||||
virtual uint8_t Release();
|
||||
/**
|
||||
* Poll the USB Input endpoins and run the state machines.
|
||||
* @return 0 on success.
|
||||
*/
|
||||
virtual uint8_t Poll();
|
||||
/**
|
||||
* Get the device address.
|
||||
* @return The device address.
|
||||
*/
|
||||
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; };
|
||||
/**@}*/
|
||||
/** @name USBDeviceConfig implementation */
|
||||
/**
|
||||
* Initialize the PS3 Controller.
|
||||
* @param parent Hub number.
|
||||
* @param port Port number on the hub.
|
||||
* @param lowspeed Speed of the device.
|
||||
* @return 0 on success.
|
||||
*/
|
||||
virtual uint8_t Init(uint8_t parent, uint8_t port, bool lowspeed);
|
||||
/**
|
||||
* Release the USB device.
|
||||
* @return 0 on success.
|
||||
*/
|
||||
virtual uint8_t Release();
|
||||
/**
|
||||
* Poll the USB Input endpoins and run the state machines.
|
||||
* @return 0 on success.
|
||||
*/
|
||||
virtual uint8_t Poll();
|
||||
|
||||
/**
|
||||
* Used to set the Bluetooth address inside the Dualshock 3 and Navigation controller.
|
||||
* @param BDADDR Your dongles Bluetooth address.
|
||||
*/
|
||||
void setBdaddr(uint8_t* BDADDR);
|
||||
/**
|
||||
* Used to set the Bluetooth address inside the Move controller.
|
||||
* @param BDADDR Your dongles Bluetooth address.
|
||||
*/
|
||||
void setMoveBdaddr(uint8_t* BDADDR);
|
||||
/**
|
||||
* Get the device address.
|
||||
* @return The device address.
|
||||
*/
|
||||
virtual uint8_t GetAddress() {
|
||||
return bAddress;
|
||||
};
|
||||
|
||||
/** @name PS3 Controller functions */
|
||||
/**
|
||||
* getButtonPress(Button b) will return true as long as the button is held down.
|
||||
*
|
||||
* While getButtonClick(Button b) will only return it once.
|
||||
*
|
||||
* So you instance if you need to increase a variable once you would use getButtonClick(Button b),
|
||||
* but if you need to drive a robot forward you would use getButtonPress(Button b).
|
||||
*/
|
||||
bool getButtonPress(Button b);
|
||||
bool getButtonClick(Button b);
|
||||
/**@}*/
|
||||
/** @name PS3 Controller functions */
|
||||
/**
|
||||
* Used to get the analog value from button presses.
|
||||
* @param a The ::Button to read.
|
||||
* The supported buttons are:
|
||||
* ::UP, ::RIGHT, ::DOWN, ::LEFT, ::L1, ::L2, ::R1, ::R2,
|
||||
* ::TRIANGLE, ::CIRCLE, ::CROSS, ::SQUARE, and ::T.
|
||||
* @return Analog value in the range of 0-255.
|
||||
*/
|
||||
uint8_t getAnalogButton(Button a);
|
||||
/**
|
||||
* Used to read the analog joystick.
|
||||
* @param a ::LeftHatX, ::LeftHatY, ::RightHatX, and ::RightHatY.
|
||||
* @return Return the analog value in the range of 0-255.
|
||||
*/
|
||||
uint8_t getAnalogHat(AnalogHat a);
|
||||
/**
|
||||
* Used to read the sensors inside the Dualshock 3 controller.
|
||||
* @param a
|
||||
* The Dualshock 3 has a 3-axis accelerometer and a 1-axis gyro inside.
|
||||
* @return Return the raw sensor value.
|
||||
*/
|
||||
uint16_t getSensor(Sensor a);
|
||||
/**
|
||||
* Use this to get ::Pitch and ::Roll calculated using the accelerometer.
|
||||
* @param a Either ::Pitch or ::Roll.
|
||||
* @return Return the angle in the range of 0-360.
|
||||
*/
|
||||
double getAngle(Angle a);
|
||||
/**
|
||||
* Get the ::Status from the controller.
|
||||
* @param c The ::Status you want to read.
|
||||
* @return True if correct and false if not.
|
||||
*/
|
||||
bool getStatus(Status c);
|
||||
/**
|
||||
* Read all the available ::Status from the controller.
|
||||
* @return One large string with all the information.
|
||||
*/
|
||||
String getStatusString();
|
||||
/**
|
||||
* Used to check if the controller has been initialized.
|
||||
* @return True if it's ready.
|
||||
*/
|
||||
virtual bool isReady() {
|
||||
return bPollEnable;
|
||||
};
|
||||
/**@}*/
|
||||
|
||||
/** Used to set all LEDs and ::Rumble off. */
|
||||
void setAllOff();
|
||||
/** Turn off ::Rumble. */
|
||||
void setRumbleOff();
|
||||
/**
|
||||
* Turn on ::Rumble.
|
||||
* @param mode Either ::RumbleHigh or ::RumbleLow.
|
||||
*/
|
||||
void setRumbleOn(Rumble mode);
|
||||
/**
|
||||
* Turn the specific ::LED off.
|
||||
* @param a The ::LED to turn off.
|
||||
*/
|
||||
void setLedOff(LED a);
|
||||
/**
|
||||
* Turn the specific ::LED on.
|
||||
* @param a The ::LED to turn on.
|
||||
*/
|
||||
void setLedOn(LED a);
|
||||
/**
|
||||
* Toggle the specific ::LED.
|
||||
* @param a The ::LED to toggle.
|
||||
*/
|
||||
void setLedToggle(LED a);
|
||||
/**
|
||||
* Used to set the Bluetooth address inside the Dualshock 3 and Navigation controller.
|
||||
* @param BDADDR Your dongles Bluetooth address.
|
||||
*/
|
||||
void setBdaddr(uint8_t* BDADDR);
|
||||
/**
|
||||
* Used to set the Bluetooth address inside the Move controller.
|
||||
* @param BDADDR Your dongles Bluetooth address.
|
||||
*/
|
||||
void setMoveBdaddr(uint8_t* BDADDR);
|
||||
|
||||
/**
|
||||
* Use this to set the Color using RGB values.
|
||||
* @param r,g,b RGB value.
|
||||
*/
|
||||
void moveSetBulb(uint8_t r, uint8_t g, uint8_t b);
|
||||
/**
|
||||
* Use this to set the color using the predefined colors in ::Colors.
|
||||
* @param color The desired color.
|
||||
*/
|
||||
void moveSetBulb(Colors color);
|
||||
/**
|
||||
* Set the rumble value inside the Move controller.
|
||||
* @param rumble The desired value in the range from 64-255.
|
||||
*/
|
||||
void moveSetRumble(uint8_t rumble);
|
||||
/**@}*/
|
||||
/** @name PS3 Controller functions */
|
||||
/**
|
||||
* getButtonPress(Button b) will return true as long as the button is held down.
|
||||
*
|
||||
* While getButtonClick(Button b) will only return it once.
|
||||
*
|
||||
* So you instance if you need to increase a variable once you would use getButtonClick(Button b),
|
||||
* but if you need to drive a robot forward you would use getButtonPress(Button b).
|
||||
*/
|
||||
bool getButtonPress(Button b);
|
||||
bool getButtonClick(Button b);
|
||||
/**@}*/
|
||||
/** @name PS3 Controller functions */
|
||||
/**
|
||||
* Used to get the analog value from button presses.
|
||||
* @param a The ::Button to read.
|
||||
* The supported buttons are:
|
||||
* ::UP, ::RIGHT, ::DOWN, ::LEFT, ::L1, ::L2, ::R1, ::R2,
|
||||
* ::TRIANGLE, ::CIRCLE, ::CROSS, ::SQUARE, and ::T.
|
||||
* @return Analog value in the range of 0-255.
|
||||
*/
|
||||
uint8_t getAnalogButton(Button a);
|
||||
/**
|
||||
* Used to read the analog joystick.
|
||||
* @param a ::LeftHatX, ::LeftHatY, ::RightHatX, and ::RightHatY.
|
||||
* @return Return the analog value in the range of 0-255.
|
||||
*/
|
||||
uint8_t getAnalogHat(AnalogHat a);
|
||||
/**
|
||||
* Used to read the sensors inside the Dualshock 3 controller.
|
||||
* @param a
|
||||
* The Dualshock 3 has a 3-axis accelerometer and a 1-axis gyro inside.
|
||||
* @return Return the raw sensor value.
|
||||
*/
|
||||
uint16_t getSensor(Sensor a);
|
||||
/**
|
||||
* Use this to get ::Pitch and ::Roll calculated using the accelerometer.
|
||||
* @param a Either ::Pitch or ::Roll.
|
||||
* @return Return the angle in the range of 0-360.
|
||||
*/
|
||||
double getAngle(Angle a);
|
||||
/**
|
||||
* Get the ::Status from the controller.
|
||||
* @param c The ::Status you want to read.
|
||||
* @return True if correct and false if not.
|
||||
*/
|
||||
bool getStatus(Status c);
|
||||
/**
|
||||
* Read all the available ::Status from the controller.
|
||||
* @return One large string with all the information.
|
||||
*/
|
||||
String getStatusString();
|
||||
|
||||
/** Variable used to indicate if the normal playstation controller is successfully connected. */
|
||||
bool PS3Connected;
|
||||
/** Variable used to indicate if the move controller is successfully connected. */
|
||||
bool PS3MoveConnected;
|
||||
/** Variable used to indicate if the navigation controller is successfully connected. */
|
||||
bool PS3NavigationConnected;
|
||||
/** Used to set all LEDs and ::Rumble off. */
|
||||
void setAllOff();
|
||||
/** Turn off ::Rumble. */
|
||||
void setRumbleOff();
|
||||
/**
|
||||
* Turn on ::Rumble.
|
||||
* @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.
|
||||
*/
|
||||
void setLedOff(LED a);
|
||||
/**
|
||||
* Turn the specific ::LED on.
|
||||
* @param a The ::LED to turn on.
|
||||
*/
|
||||
void setLedOn(LED a);
|
||||
/**
|
||||
* Toggle the specific ::LED.
|
||||
* @param a The ::LED to toggle.
|
||||
*/
|
||||
void setLedToggle(LED a);
|
||||
|
||||
/**
|
||||
* Use this to set the Color using RGB values.
|
||||
* @param r,g,b RGB value.
|
||||
*/
|
||||
void moveSetBulb(uint8_t r, uint8_t g, uint8_t b);
|
||||
/**
|
||||
* Use this to set the color using the predefined colors in ::Colors.
|
||||
* @param color The desired color.
|
||||
*/
|
||||
void moveSetBulb(Colors color);
|
||||
/**
|
||||
* Set the rumble value inside the Move controller.
|
||||
* @param rumble The desired value in the range from 64-255.
|
||||
*/
|
||||
void moveSetRumble(uint8_t rumble);
|
||||
/**@}*/
|
||||
|
||||
/** Variable used to indicate if the normal playstation controller is successfully connected. */
|
||||
bool PS3Connected;
|
||||
/** Variable used to indicate if the move controller is successfully connected. */
|
||||
bool PS3MoveConnected;
|
||||
/** Variable used to indicate if the navigation controller is successfully connected. */
|
||||
bool PS3NavigationConnected;
|
||||
|
||||
protected:
|
||||
/** Pointer to USB class instance. */
|
||||
USB *pUsb;
|
||||
/** Device address. */
|
||||
uint8_t bAddress;
|
||||
/** Endpoint info structure. */
|
||||
EpInfo epInfo[PS3_MAX_ENDPOINTS];
|
||||
/** Pointer to USB class instance. */
|
||||
USB *pUsb;
|
||||
/** Device address. */
|
||||
uint8_t bAddress;
|
||||
/** Endpoint info structure. */
|
||||
EpInfo epInfo[PS3_MAX_ENDPOINTS];
|
||||
|
||||
private:
|
||||
bool bPollEnable;
|
||||
bool bPollEnable;
|
||||
|
||||
uint32_t timer; // used to continuously set PS3 Move controller Bulb and rumble values
|
||||
uint32_t timer; // used to continuously set PS3 Move controller Bulb and rumble values
|
||||
|
||||
uint32_t ButtonState;
|
||||
uint32_t OldButtonState;
|
||||
uint32_t ButtonClickState;
|
||||
uint32_t ButtonState;
|
||||
uint32_t OldButtonState;
|
||||
uint32_t ButtonClickState;
|
||||
|
||||
uint8_t my_bdaddr[6]; // Change to your dongles Bluetooth address in the constructor
|
||||
uint8_t readBuf[EP_MAXPKTSIZE]; // General purpose buffer for input data
|
||||
uint8_t writeBuf[EP_MAXPKTSIZE]; // General purpose buffer for output data
|
||||
uint8_t my_bdaddr[6]; // Change to your dongles Bluetooth address in the constructor
|
||||
uint8_t readBuf[EP_MAXPKTSIZE]; // General purpose buffer for input data
|
||||
uint8_t writeBuf[EP_MAXPKTSIZE]; // General purpose buffer for output data
|
||||
|
||||
void readReport(); // read incoming data
|
||||
void printReport(); // print incoming date - Uncomment for debugging
|
||||
void readReport(); // read incoming data
|
||||
void printReport(); // print incoming date - Uncomment for debugging
|
||||
|
||||
/* Private commands */
|
||||
void PS3_Command(uint8_t* data, uint16_t nbytes);
|
||||
void enable_sixaxis(); // Command used to enable the Dualshock 3 and Navigation controller to send data via USB
|
||||
void Move_Command(uint8_t* data, uint16_t nbytes);
|
||||
/* Private commands */
|
||||
void PS3_Command(uint8_t* data, uint16_t nbytes);
|
||||
void enable_sixaxis(); // Command used to enable the Dualshock 3 and Navigation controller to send data via USB
|
||||
void Move_Command(uint8_t* data, uint16_t nbytes);
|
||||
};
|
||||
#endif
|
||||
|
|
508
SPP.h
508
SPP.h
|
@ -87,276 +87,310 @@
|
|||
#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 {
|
||||
public:
|
||||
/**
|
||||
* Constructor for the SPP class.
|
||||
* @param p Pointer to BTD class instance.
|
||||
* @param name Set the name to BTD#btdName. If argument is omitted, then "Arduino" will be used.
|
||||
* @param pin Write the pin to BTD#btdPin. If argument is omitted, then "1234" will be used.
|
||||
*/
|
||||
SPP(BTD *p, const char* name = "Arduino", const char* pin = "1234");
|
||||
/**
|
||||
* Constructor for the SPP class.
|
||||
* @param p Pointer to BTD class instance.
|
||||
* @param name Set the name to BTD#btdName. If argument is omitted, then "Arduino" will be used.
|
||||
* @param pin Write the pin to BTD#btdPin. If argument is omitted, then "1234" will be used.
|
||||
*/
|
||||
SPP(BTD *p, const char* name = "Arduino", const char* pin = "1234");
|
||||
|
||||
/** @name BluetoothService implementation */
|
||||
/**
|
||||
* Used to pass acldata to the services.
|
||||
* @param ACLData Incoming acldata.
|
||||
*/
|
||||
virtual void ACLData(uint8_t* ACLData);
|
||||
/** Used to establish the connection automatically. */
|
||||
virtual void Run();
|
||||
/** Use this to reset the service. */
|
||||
virtual void Reset();
|
||||
/** Used this to disconnect the virtual serial port. */
|
||||
virtual void disconnect();
|
||||
/**@}*/
|
||||
/** @name BluetoothService implementation */
|
||||
/**
|
||||
* Used to pass acldata to the services.
|
||||
* @param ACLData Incoming acldata.
|
||||
*/
|
||||
virtual void ACLData(uint8_t* ACLData);
|
||||
/** Used to establish the connection automatically. */
|
||||
virtual void Run();
|
||||
/** Use this to reset the service. */
|
||||
virtual void Reset();
|
||||
/** Used this to disconnect the virtual serial port. */
|
||||
virtual void disconnect();
|
||||
/**@}*/
|
||||
|
||||
/** Variable used to indicate if the connection is established. */
|
||||
bool connected;
|
||||
/** Variable used to indicate if the connection is established. */
|
||||
bool connected;
|
||||
|
||||
/** @name Serial port profile (SPP) Print functions */
|
||||
/**
|
||||
* Used to send Arduino String data type.
|
||||
* @param str String to send.
|
||||
*/
|
||||
void print(const String &str);
|
||||
/**
|
||||
* Same as print(const String &str), but will include newline and carriage return.
|
||||
* @param str String to send.
|
||||
*/
|
||||
void println(const String &str);
|
||||
/** @name Serial port profile (SPP) Print functions */
|
||||
/**
|
||||
* Used to send Arduino String data type.
|
||||
* @param str String to send.
|
||||
*/
|
||||
void print(const String &str);
|
||||
/**
|
||||
* Same as print(const String &str), but will include newline and carriage return.
|
||||
* @param str String to send.
|
||||
*/
|
||||
void println(const String &str);
|
||||
|
||||
/**
|
||||
* Used to send standard strings.
|
||||
* @param str String to send.
|
||||
*/
|
||||
void print(const char* str);
|
||||
/**
|
||||
* Same as print(const char* str), but will include newline and carriage return.
|
||||
* @param str String to send.
|
||||
*/
|
||||
void println(const char* str);
|
||||
/**
|
||||
* Used to send standard strings.
|
||||
* @param str String to send.
|
||||
*/
|
||||
void print(const char* str);
|
||||
/**
|
||||
* Same as print(const char* str), but will include newline and carriage return.
|
||||
* @param str String to send.
|
||||
*/
|
||||
void println(const char* str);
|
||||
|
||||
/**
|
||||
* Used to send single bytes.
|
||||
* @param data Data to send.
|
||||
*/
|
||||
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.
|
||||
*/
|
||||
void println(uint8_t data);
|
||||
/**
|
||||
* Used to send single bytes.
|
||||
* @param data Data to send.
|
||||
*/
|
||||
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.
|
||||
*/
|
||||
void println(uint8_t data);
|
||||
|
||||
/**
|
||||
* Used to send arrays.
|
||||
* @param array Array to send.
|
||||
* @param length Number of bytes to send.
|
||||
*/
|
||||
void print(uint8_t* array, uint8_t length);
|
||||
/**
|
||||
* Same as print(uint8_t* array, uint8_t length), but will include newline and carriage return.
|
||||
* @param array Array to send.
|
||||
* @param length Number of bytes to send.
|
||||
*/
|
||||
void println(uint8_t* array, uint8_t length);
|
||||
/**
|
||||
* Used to send arrays.
|
||||
* @param array Array to send.
|
||||
* @param length Number of bytes to send.
|
||||
*/
|
||||
void print(uint8_t* array, uint8_t length);
|
||||
/**
|
||||
* Same as print(uint8_t* array, uint8_t length), but will include newline and carriage return.
|
||||
* @param array Array to send.
|
||||
* @param length Number of bytes to send.
|
||||
*/
|
||||
void println(uint8_t* array, uint8_t length);
|
||||
|
||||
/**
|
||||
* Used to print strings stored in flash.
|
||||
* 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); };
|
||||
/**
|
||||
* 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); };
|
||||
/**
|
||||
* Helper function to print a string stored in flash.
|
||||
* @param ifsh String stored in flash you want to print.
|
||||
* @param newline Set this to true to include newline and carriage return.
|
||||
*/
|
||||
void printFlashString(const __FlashStringHelper *ifsh, bool newline);
|
||||
/**
|
||||
* Used to print strings stored in flash.
|
||||
* 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);
|
||||
};
|
||||
|
||||
/**
|
||||
* 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);
|
||||
};
|
||||
/**
|
||||
* Helper function to print a string stored in flash.
|
||||
* @param ifsh String stored in flash you want to print.
|
||||
* @param newline Set this to true to include newline and carriage return.
|
||||
*/
|
||||
void printFlashString(const __FlashStringHelper *ifsh, bool newline);
|
||||
|
||||
|
||||
/** Use this to print newline and carriage return. */
|
||||
void println(void);
|
||||
/** Use this to print newline and carriage return. */
|
||||
void println(void);
|
||||
|
||||
/**
|
||||
* Used to print unsigned integers.
|
||||
* @param n Unsigned integer to send.
|
||||
*/
|
||||
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); };
|
||||
/**
|
||||
* Used to print signed integers.
|
||||
* @param n Signed integer to send.
|
||||
*/
|
||||
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); };
|
||||
/**
|
||||
* Used to print unsigned integers.
|
||||
* @param n Unsigned integer to send.
|
||||
*/
|
||||
void printNumber(uint8_t n) {
|
||||
printNumber((uint32_t) n);
|
||||
};
|
||||
|
||||
/**
|
||||
* Used to print unsigned integers.
|
||||
* @param n Unsigned integer to send.
|
||||
*/
|
||||
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); };
|
||||
/**
|
||||
* Used to print signed integers.
|
||||
* @param n Signed integer to send.
|
||||
*/
|
||||
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); };
|
||||
/**
|
||||
* 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);
|
||||
};
|
||||
|
||||
/**
|
||||
* Used to print unsigned integers.
|
||||
* @param n Unsigned integer to send.
|
||||
*/
|
||||
void printNumber(uint32_t n);
|
||||
/**
|
||||
* Same as printNumber(uint32_t n), but will include newline and carriage return.
|
||||
* @param n Unsigned integer to send.
|
||||
*/
|
||||
void printNumberln(uint32_t n);
|
||||
/**
|
||||
* Used to print signed integers.
|
||||
* @param n Signed integer to send.
|
||||
*/
|
||||
void printNumber(int8_t n) {
|
||||
printNumber((int32_t) n);
|
||||
};
|
||||
|
||||
/**
|
||||
* Used to print signed integers.
|
||||
* @param n Signed integer to send.
|
||||
*/
|
||||
void printNumber(int32_t n);
|
||||
/**
|
||||
* Same as printNumber(int32_t n), but will include newline and carriage return.
|
||||
* @param n Signed integer to send.
|
||||
*/
|
||||
void printNumberln(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);
|
||||
};
|
||||
|
||||
/**
|
||||
* Helper function to convert from an unsigned integer to a string.
|
||||
* @param input Unsigned integer to convert.
|
||||
* @param output Output buffer.
|
||||
*/
|
||||
void intToString(int32_t input, char* output);
|
||||
/**
|
||||
* Helper function to convert from a signed integer to a string.
|
||||
* @param input Signed integer to convert.
|
||||
* @param output Output buffer.
|
||||
*/
|
||||
void intToString(uint32_t input, char* output);
|
||||
/**
|
||||
* Used to print unsigned integers.
|
||||
* @param n Unsigned integer to send.
|
||||
*/
|
||||
void printNumber(uint16_t n) {
|
||||
printNumber((uint32_t) n);
|
||||
};
|
||||
|
||||
/**
|
||||
* Used to print floating-point numbers.
|
||||
* @param n Floating-point number to print.
|
||||
* @param digits Number of digits to send. If argument is omitted, then 2 digits will be used.
|
||||
*/
|
||||
void printNumber(double n, uint8_t digits = 2);
|
||||
/**
|
||||
* Same as printNumber(double n, uint8_t digits), but will include newline and carriage return.
|
||||
* @param n Floating-point number to print.
|
||||
* @param digits Number of digits to send. If argument is omitted, then 2 digits will be used.
|
||||
*/
|
||||
void printNumberln(double n, uint8_t digits = 2);
|
||||
/**
|
||||
* Helper function to convert from a double to a string.
|
||||
* @param input Floating-point number to convert.
|
||||
* @param output Output buffer.
|
||||
* @param digits Number of digits to convert. If argument is omitted, then 2 digits will be used.
|
||||
*/
|
||||
void doubleToString(double input, char* output, uint8_t digits = 2);
|
||||
/**
|
||||
* 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);
|
||||
};
|
||||
|
||||
/**
|
||||
* Get number of bytes waiting to be read.
|
||||
* @return Return the number of bytes ready to be read.
|
||||
*/
|
||||
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; };
|
||||
/**@}*/
|
||||
/**
|
||||
* Used to print signed integers.
|
||||
* @param n Signed integer to send.
|
||||
*/
|
||||
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);
|
||||
};
|
||||
|
||||
/**
|
||||
* Used to print unsigned integers.
|
||||
* @param n Unsigned integer to send.
|
||||
*/
|
||||
void printNumber(uint32_t n);
|
||||
/**
|
||||
* Same as printNumber(uint32_t n), but will include newline and carriage return.
|
||||
* @param n Unsigned integer to send.
|
||||
*/
|
||||
void printNumberln(uint32_t n);
|
||||
|
||||
/**
|
||||
* Used to print signed integers.
|
||||
* @param n Signed integer to send.
|
||||
*/
|
||||
void printNumber(int32_t n);
|
||||
/**
|
||||
* Same as printNumber(int32_t n), but will include newline and carriage return.
|
||||
* @param n Signed integer to send.
|
||||
*/
|
||||
void printNumberln(int32_t n);
|
||||
|
||||
/**
|
||||
* Helper function to convert from an unsigned integer to a string.
|
||||
* @param input Unsigned integer to convert.
|
||||
* @param output Output buffer.
|
||||
*/
|
||||
void intToString(int32_t input, char* output);
|
||||
/**
|
||||
* Helper function to convert from a signed integer to a string.
|
||||
* @param input Signed integer to convert.
|
||||
* @param output Output buffer.
|
||||
*/
|
||||
void intToString(uint32_t input, char* output);
|
||||
|
||||
/**
|
||||
* Used to print floating-point numbers.
|
||||
* @param n Floating-point number to print.
|
||||
* @param digits Number of digits to send. If argument is omitted, then 2 digits will be used.
|
||||
*/
|
||||
void printNumber(double n, uint8_t digits = 2);
|
||||
/**
|
||||
* Same as printNumber(double n, uint8_t digits), but will include newline and carriage return.
|
||||
* @param n Floating-point number to print.
|
||||
* @param digits Number of digits to send. If argument is omitted, then 2 digits will be used.
|
||||
*/
|
||||
void printNumberln(double n, uint8_t digits = 2);
|
||||
/**
|
||||
* Helper function to convert from a double to a string.
|
||||
* @param input Floating-point number to convert.
|
||||
* @param output Output buffer.
|
||||
* @param digits Number of digits to convert. If argument is omitted, then 2 digits will be used.
|
||||
*/
|
||||
void doubleToString(double input, char* output, uint8_t digits = 2);
|
||||
|
||||
/**
|
||||
* Get number of bytes waiting to be read.
|
||||
* @return Return the number of bytes ready to be read.
|
||||
*/
|
||||
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;
|
||||
};
|
||||
/**@}*/
|
||||
|
||||
private:
|
||||
/* Bluetooth dongle library pointer */
|
||||
BTD *pBtd;
|
||||
/* Bluetooth dongle library pointer */
|
||||
BTD *pBtd;
|
||||
|
||||
/* Set true when a channel is created */
|
||||
bool SDPConnected;
|
||||
bool RFCOMMConnected;
|
||||
/* Set true when a channel is created */
|
||||
bool SDPConnected;
|
||||
bool RFCOMMConnected;
|
||||
|
||||
uint16_t hci_handle; // The HCI Handle for the connection
|
||||
uint16_t hci_handle; // The HCI Handle for the connection
|
||||
|
||||
/* Variables used by L2CAP state maschines */
|
||||
uint8_t l2cap_sdp_state;
|
||||
uint8_t l2cap_rfcomm_state;
|
||||
uint16_t l2cap_event_flag; // l2cap flags of received bluetooth events
|
||||
/* Variables used by L2CAP state maschines */
|
||||
uint8_t l2cap_sdp_state;
|
||||
uint8_t l2cap_rfcomm_state;
|
||||
uint16_t l2cap_event_flag; // l2cap flags of received bluetooth events
|
||||
|
||||
uint8_t l2capoutbuf[BULK_MAXPKTSIZE]; // General purpose buffer for l2cap out data
|
||||
uint8_t rfcommbuf[10]; // Buffer for RFCOMM Commands
|
||||
uint8_t l2capoutbuf[BULK_MAXPKTSIZE]; // General purpose buffer for l2cap out data
|
||||
uint8_t rfcommbuf[10]; // Buffer for RFCOMM Commands
|
||||
|
||||
/* L2CAP Channels */
|
||||
uint8_t sdp_scid[2]; // L2CAP source CID for SDP
|
||||
uint8_t sdp_dcid[2]; // 0x0050
|
||||
uint8_t rfcomm_scid[2]; // L2CAP source CID for RFCOMM
|
||||
uint8_t rfcomm_dcid[2]; // 0x0051
|
||||
uint8_t identifier; // Identifier for command
|
||||
/* L2CAP Channels */
|
||||
uint8_t sdp_scid[2]; // L2CAP source CID for SDP
|
||||
uint8_t sdp_dcid[2]; // 0x0050
|
||||
uint8_t rfcomm_scid[2]; // L2CAP source CID for RFCOMM
|
||||
uint8_t rfcomm_dcid[2]; // 0x0051
|
||||
uint8_t identifier; // Identifier for command
|
||||
|
||||
/* RFCOMM Variables */
|
||||
uint8_t rfcommChannel;
|
||||
uint8_t rfcommChannelConnection; // This is the channel the SPP chanel will be running at
|
||||
uint8_t rfcommDirection;
|
||||
uint8_t rfcommCommandResponse;
|
||||
uint8_t rfcommChannelType;
|
||||
uint8_t rfcommPfBit;
|
||||
/* RFCOMM Variables */
|
||||
uint8_t rfcommChannel;
|
||||
uint8_t rfcommChannelConnection; // This is the channel the SPP chanel will be running at
|
||||
uint8_t rfcommDirection;
|
||||
uint8_t rfcommCommandResponse;
|
||||
uint8_t rfcommChannelType;
|
||||
uint8_t rfcommPfBit;
|
||||
|
||||
unsigned long timer;
|
||||
bool waitForLastCommand;
|
||||
bool creditSent;
|
||||
unsigned long timer;
|
||||
bool waitForLastCommand;
|
||||
bool creditSent;
|
||||
|
||||
uint8_t rfcommDataBuffer[100]; // Create a 100 sized buffer for incoming data
|
||||
uint8_t rfcommAvailable;
|
||||
uint8_t rfcommDataBuffer[100]; // Create a 100 sized buffer for incoming data
|
||||
uint8_t rfcommAvailable;
|
||||
|
||||
bool firstMessage; // Used to see if it's the first SDP request received
|
||||
uint8_t bytesRead; // Counter to see when it's time to send more credit
|
||||
bool firstMessage; // Used to see if it's the first SDP request received
|
||||
uint8_t bytesRead; // Counter to see when it's time to send more credit
|
||||
|
||||
/* State machines */
|
||||
void SDP_task(); // SDP state machine
|
||||
void RFCOMM_task(); // RFCOMM state machine
|
||||
/* State machines */
|
||||
void SDP_task(); // SDP state machine
|
||||
void RFCOMM_task(); // RFCOMM state machine
|
||||
|
||||
/* SDP Commands */
|
||||
void SDP_Command(uint8_t* data, uint8_t nbytes);
|
||||
void serviceNotSupported(uint8_t transactionIDHigh, uint8_t transactionIDLow);
|
||||
void serialPortResponse1(uint8_t transactionIDHigh, uint8_t transactionIDLow);
|
||||
void serialPortResponse2(uint8_t transactionIDHigh, uint8_t transactionIDLow);
|
||||
void l2capResponse1(uint8_t transactionIDHigh, uint8_t transactionIDLow);
|
||||
void l2capResponse2(uint8_t transactionIDHigh, uint8_t transactionIDLow);
|
||||
/* SDP Commands */
|
||||
void SDP_Command(uint8_t* data, uint8_t nbytes);
|
||||
void serviceNotSupported(uint8_t transactionIDHigh, uint8_t transactionIDLow);
|
||||
void serialPortResponse1(uint8_t transactionIDHigh, uint8_t transactionIDLow);
|
||||
void serialPortResponse2(uint8_t transactionIDHigh, uint8_t transactionIDLow);
|
||||
void l2capResponse1(uint8_t transactionIDHigh, uint8_t transactionIDLow);
|
||||
void l2capResponse2(uint8_t transactionIDHigh, uint8_t transactionIDLow);
|
||||
|
||||
/* RFCOMM Commands */
|
||||
void RFCOMM_Command(uint8_t* data, uint8_t nbytes);
|
||||
void sendRfcomm(uint8_t channel, uint8_t direction, uint8_t CR, uint8_t channelType, uint8_t pfBit, uint8_t* data, uint8_t length);
|
||||
void sendRfcommCredit(uint8_t channel, uint8_t direction, uint8_t CR, uint8_t channelType, uint8_t pfBit, uint8_t credit);
|
||||
uint8_t calcFcs(uint8_t *data);
|
||||
uint8_t __crc(uint8_t* data);
|
||||
/* RFCOMM Commands */
|
||||
void RFCOMM_Command(uint8_t* data, uint8_t nbytes);
|
||||
void sendRfcomm(uint8_t channel, uint8_t direction, uint8_t CR, uint8_t channelType, uint8_t pfBit, uint8_t* data, uint8_t length);
|
||||
void sendRfcommCredit(uint8_t channel, uint8_t direction, uint8_t CR, uint8_t channelType, uint8_t pfBit, uint8_t credit);
|
||||
uint8_t calcFcs(uint8_t *data);
|
||||
uint8_t __crc(uint8_t* data);
|
||||
};
|
||||
#endif
|
269
Usb.h
269
Usb.h
|
@ -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
|
||||
typedef MAX3421e<P6, P3> MAX3421E; // Black Widow
|
||||
#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))
|
||||
|
||||
|
||||
|
||||
|
@ -80,22 +70,22 @@ typedef MAX3421e<P10, P9> MAX3421E; // Official Arduinos (UNO, Duemilanove, Me
|
|||
|
||||
// USB Device Classes
|
||||
#define USB_CLASS_USE_CLASS_INFO 0x00 // Use Class Info in the Interface Descriptors
|
||||
#define USB_CLASS_AUDIO 0x01 // Audio
|
||||
#define USB_CLASS_AUDIO 0x01 // Audio
|
||||
#define USB_CLASS_COM_AND_CDC_CTRL 0x02 // Communications and CDC Control
|
||||
#define USB_CLASS_HID 0x03 // HID
|
||||
#define USB_CLASS_PHYSICAL 0x05 // Physical
|
||||
#define USB_CLASS_IMAGE 0x06 // Image
|
||||
#define USB_CLASS_PRINTER 0x07 // Printer
|
||||
#define USB_CLASS_HID 0x03 // HID
|
||||
#define USB_CLASS_PHYSICAL 0x05 // Physical
|
||||
#define USB_CLASS_IMAGE 0x06 // Image
|
||||
#define USB_CLASS_PRINTER 0x07 // Printer
|
||||
#define USB_CLASS_MASS_STORAGE 0x08 // Mass Storage
|
||||
#define USB_CLASS_HUB 0x09 // Hub
|
||||
#define USB_CLASS_CDC_DATA 0x0a // CDC-Data
|
||||
#define USB_CLASS_HUB 0x09 // Hub
|
||||
#define USB_CLASS_CDC_DATA 0x0a // CDC-Data
|
||||
#define USB_CLASS_SMART_CARD 0x0b // Smart-Card
|
||||
#define USB_CLASS_CONTENT_SECURITY 0x0d // Content Security
|
||||
#define USB_CLASS_VIDEO 0x0e // Video
|
||||
#define USB_CLASS_VIDEO 0x0e // Video
|
||||
#define USB_CLASS_PERSONAL_HEALTH 0x0f // Personal Healthcare
|
||||
#define USB_CLASS_DIAGNOSTIC_DEVICE 0xdc // Diagnostic Device
|
||||
#define USB_CLASS_WIRELESS_CTRL 0xe0 // Wireless Controller
|
||||
#define USB_CLASS_MISC 0xef // Miscellaneous
|
||||
#define USB_CLASS_MISC 0xef // Miscellaneous
|
||||
#define USB_CLASS_APP_SPECIFIC 0xfe // Application Specific
|
||||
#define USB_CLASS_VENDOR_SPECIFIC 0xff // Vendor Specific
|
||||
|
||||
|
@ -104,32 +94,31 @@ typedef MAX3421e<P10, P9> MAX3421E; // Official Arduinos (UNO, Duemilanove, Me
|
|||
#define USB_DEV_CONFIG_ERROR_DEVICE_INIT_INCOMPLETE 0xD2
|
||||
#define USB_ERROR_UNABLE_TO_REGISTER_DEVICE_CLASS 0xD3
|
||||
#define USB_ERROR_OUT_OF_ADDRESS_SPACE_IN_POOL 0xD4
|
||||
#define USB_ERROR_HUB_ADDRESS_OVERFLOW 0xD5
|
||||
#define USB_ERROR_ADDRESS_NOT_FOUND_IN_POOL 0xD6
|
||||
#define USB_ERROR_EPINFO_IS_NULL 0xD7
|
||||
#define USB_ERROR_INVALID_ARGUMENT 0xD8
|
||||
#define USB_ERROR_HUB_ADDRESS_OVERFLOW 0xD5
|
||||
#define USB_ERROR_ADDRESS_NOT_FOUND_IN_POOL 0xD6
|
||||
#define USB_ERROR_EPINFO_IS_NULL 0xD7
|
||||
#define USB_ERROR_INVALID_ARGUMENT 0xD8
|
||||
#define USB_ERROR_CLASS_INSTANCE_ALREADY_IN_USE 0xD9
|
||||
#define USB_ERROR_INVALID_MAX_PKT_SIZE 0xDA
|
||||
#define USB_ERROR_EP_NOT_FOUND_IN_TBL 0xDB
|
||||
#define USB_ERROR_TRANSFER_TIMEOUT 0xFF
|
||||
#define USB_ERROR_INVALID_MAX_PKT_SIZE 0xDA
|
||||
#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;
|
||||
virtual uint8_t Poll() = 0;
|
||||
virtual uint8_t GetAddress() = 0;
|
||||
virtual uint8_t Init(uint8_t parent, uint8_t port, bool lowspeed) = 0;
|
||||
virtual uint8_t Release() = 0;
|
||||
virtual uint8_t Poll() = 0;
|
||||
virtual uint8_t GetAddress() = 0;
|
||||
};
|
||||
|
||||
#define USB_XFER_TIMEOUT 5000 //USB transfer timeout in milliseconds, per section 9.2.6.1 of USB 2.0 spec
|
||||
//#define USB_NAK_LIMIT 32000 //NAK limit for a transfer. 0 means NAKs are not counted
|
||||
#define USB_RETRY_LIMIT 3 //retry limit for a transfer
|
||||
#define USB_SETTLE_DELAY 200 //settle delay in milliseconds
|
||||
#define USB_XFER_TIMEOUT 5000 //USB transfer timeout in milliseconds, per section 9.2.6.1 of USB 2.0 spec
|
||||
//#define USB_NAK_LIMIT 32000 //NAK limit for a transfer. 0 means NAKs are not counted
|
||||
#define USB_RETRY_LIMIT 3 //retry limit for a transfer
|
||||
#define USB_SETTLE_DELAY 200 //settle delay in milliseconds
|
||||
|
||||
#define USB_NUMDEVICES 16 //number of USB devices
|
||||
//#define HUB_MAX_HUBS 7 // maximum number of hubs that can be attached to the host controller
|
||||
#define HUB_PORT_RESET_DELAY 20 // hub port reset delay 10 ms recomended, can be up to 20 ms
|
||||
#define USB_NUMDEVICES 16 //number of USB devices
|
||||
//#define HUB_MAX_HUBS 7 // maximum number of hubs that can be attached to the host controller
|
||||
#define HUB_PORT_RESET_DELAY 20 // hub port reset delay 10 ms recomended, can be up to 20 ms
|
||||
|
||||
/* USB state machine states */
|
||||
#define USB_STATE_MASK 0xf0
|
||||
|
@ -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 bRequest; // 1 Request
|
||||
union {
|
||||
uint16_t wValue; // 2 Depends on bRequest
|
||||
struct {
|
||||
uint8_t wValueLo;
|
||||
uint8_t wValueHi;
|
||||
};
|
||||
}wVal_u;
|
||||
uint16_t wIndex; // 4 Depends on bRequest
|
||||
uint16_t wLength; // 6 Depends on bRequest
|
||||
} SETUP_PKT, *PSETUP_PKT;
|
||||
|
||||
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
|
||||
} __attribute__((packed));
|
||||
} ReqType_u;
|
||||
uint8_t bRequest; // 1 Request
|
||||
|
||||
union {
|
||||
uint16_t wValue; // 2 Depends on bRequest
|
||||
|
||||
struct {
|
||||
uint8_t wValueLo;
|
||||
uint8_t wValueHi;
|
||||
} __attribute__((packed));
|
||||
} wVal_u;
|
||||
uint16_t wIndex; // 4 Depends on bRequest
|
||||
uint16_t wLength; // 6 Depends on bRequest
|
||||
} 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;
|
||||
virtual void Parse(const uint16_t len, const uint8_t *pbuf, const uint16_t &offset) = 0;
|
||||
};
|
||||
|
||||
class USB : public MAX3421E {
|
||||
AddressPoolImpl<USB_NUMDEVICES> addrPool;
|
||||
USBDeviceConfig* devConfig[USB_NUMDEVICES];
|
||||
uint8_t devConfigIndex;
|
||||
uint8_t bmHubPre;
|
||||
|
||||
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 SetHubPreMask() { bmHubPre |= bmHUBPRE; };
|
||||
void ResetHubPreMask() { bmHubPre &= (~bmHUBPRE); };
|
||||
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)
|
||||
{
|
||||
addrPool.ForEachUsbDevice(pfunc);
|
||||
};
|
||||
uint8_t getUsbTaskState( void );
|
||||
void setUsbTaskState( uint8_t state );
|
||||
AddressPool& GetAddressPool() {
|
||||
return(AddressPool&) addrPool;
|
||||
};
|
||||
|
||||
EpInfo* getEpInfoEntry( uint8_t addr, uint8_t ep );
|
||||
uint8_t setEpInfoEntry( uint8_t addr, uint8_t epcount, EpInfo* eprecord_ptr );
|
||||
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) {
|
||||
addrPool.ForEachUsbDevice(pfunc);
|
||||
};
|
||||
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);
|
||||
|
||||
//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 );
|
||||
/* 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 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 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,
|
||||
uint16_t wInd, uint16_t total, uint16_t nbytes, uint8_t* dataptr, USBReadParser *p);
|
||||
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 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);
|
||||
};
|
||||
|
||||
#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)
|
||||
|
|
651
Wii.h
651
Wii.h
|
@ -82,10 +82,10 @@
|
|||
|
||||
/** Enum used to read the joystick on the Nunchuck. */
|
||||
enum Hat {
|
||||
/** Read the x-axis on the Nunchuck joystick. */
|
||||
HatX = 0,
|
||||
/** Read the y-axis on the Nunchuck joystick. */
|
||||
HatY = 1,
|
||||
/** Read the x-axis on the Nunchuck joystick. */
|
||||
HatX = 0,
|
||||
/** Read the y-axis on the Nunchuck joystick. */
|
||||
HatY = 1,
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -95,347 +95,394 @@ enum Hat {
|
|||
*/
|
||||
class WII : public BluetoothService {
|
||||
public:
|
||||
/**
|
||||
* Constructor for the WII class.
|
||||
* @param p Pointer to BTD class instance.
|
||||
* @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);
|
||||
/**
|
||||
* Constructor for the WII class.
|
||||
* @param p Pointer to BTD class instance.
|
||||
* @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);
|
||||
|
||||
/** @name BluetoothService implementation */
|
||||
/**
|
||||
* Used to pass acldata to the services.
|
||||
* @param ACLData Incoming acldata.
|
||||
*/
|
||||
virtual void ACLData(uint8_t* ACLData);
|
||||
/** Used to run part of the state maschine. */
|
||||
virtual void Run();
|
||||
/** Use this to reset the service. */
|
||||
virtual void Reset();
|
||||
/** Used this to disconnect any of the controllers. */
|
||||
virtual void disconnect();
|
||||
/**@}*/
|
||||
/** @name BluetoothService implementation */
|
||||
/**
|
||||
* Used to pass acldata to the services.
|
||||
* @param ACLData Incoming acldata.
|
||||
*/
|
||||
virtual void ACLData(uint8_t* ACLData);
|
||||
/** Used to run part of the state maschine. */
|
||||
virtual void Run();
|
||||
/** Use this to reset the service. */
|
||||
virtual void Reset();
|
||||
/** Used this to disconnect any of the controllers. */
|
||||
virtual void disconnect();
|
||||
/**@}*/
|
||||
|
||||
/** @name Wii Controller functions */
|
||||
/**
|
||||
* getButtonPress(Button b) will return true as long as the button is held down.
|
||||
*
|
||||
* While getButtonClick(Button b) will only return it once.
|
||||
*
|
||||
* So you instance if you need to increase a variable once you would use getButtonClick(Button b),
|
||||
* but if you need to drive a robot forward you would use getButtonPress(Button b).
|
||||
*/
|
||||
bool getButtonPress(Button b);
|
||||
bool getButtonClick(Button b);
|
||||
/**@}*/
|
||||
/** @name Wii Controller functions */
|
||||
/**
|
||||
* getButtonPress(Button b) will return true as long as the button is held down.
|
||||
*
|
||||
* While getButtonClick(Button b) will only return it once.
|
||||
*
|
||||
* So you instance if you need to increase a variable once you would use getButtonClick(Button b),
|
||||
* but if you need to drive a robot forward you would use getButtonPress(Button b).
|
||||
*/
|
||||
bool getButtonPress(Button b);
|
||||
bool getButtonClick(Button b);
|
||||
/**@}*/
|
||||
|
||||
/** @name Wii Controller functions */
|
||||
/**
|
||||
* Used to read the joystick of the Nunchuck.
|
||||
* @param a Either ::HatX or ::HatY.
|
||||
* @return Return the analog value in the range from approximately 25-230.
|
||||
*/
|
||||
uint8_t getAnalogHat(Hat a);
|
||||
/**
|
||||
* Used to read the joystick of the Wii U Pro Controller.
|
||||
* @param a Either ::LeftHatX, ::LeftHatY, ::RightHatX or ::RightHatY.
|
||||
* @return Return the analog value in the range from approximately 800-3200.
|
||||
*/
|
||||
uint16_t getAnalogHat(AnalogHat a);
|
||||
/** @name Wii Controller functions */
|
||||
/**
|
||||
* Used to read the joystick of the Nunchuck.
|
||||
* @param a Either ::HatX or ::HatY.
|
||||
* @return Return the analog value in the range from approximately 25-230.
|
||||
*/
|
||||
uint8_t getAnalogHat(Hat a);
|
||||
/**
|
||||
* Used to read the joystick of the Wii U Pro Controller.
|
||||
* @param a Either ::LeftHatX, ::LeftHatY, ::RightHatX or ::RightHatY.
|
||||
* @return Return the analog value in the range from approximately 800-3200.
|
||||
*/
|
||||
uint16_t getAnalogHat(AnalogHat a);
|
||||
|
||||
/**
|
||||
* 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; };
|
||||
/**
|
||||
* 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; };
|
||||
/**
|
||||
* 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; };
|
||||
/**
|
||||
* 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;
|
||||
};
|
||||
|
||||
/** Used to set all LEDs and rumble off. */
|
||||
void setAllOff();
|
||||
/** Turn off rumble. */
|
||||
void setRumbleOff();
|
||||
/** Turn on rumble. */
|
||||
void setRumbleOn();
|
||||
/** Toggle rumble. */
|
||||
void setRumbleToggle();
|
||||
/**
|
||||
* Turn the specific ::LED off.
|
||||
* @param a The ::LED to turn off.
|
||||
*/
|
||||
void setLedOff(LED a);
|
||||
/**
|
||||
* Turn the specific ::LED on.
|
||||
* @param a The ::LED to turn on.
|
||||
*/
|
||||
void setLedOn(LED a);
|
||||
/**
|
||||
* Toggle the specific ::LED.
|
||||
* @param a The ::LED to toggle.
|
||||
*/
|
||||
void setLedToggle(LED a);
|
||||
/**
|
||||
* This will set the LEDs, so the user can see which connections are active.
|
||||
*
|
||||
* The first ::LED indicate that the Wiimote is connected,
|
||||
*
|
||||
* the second ::LED indicate indicate that a Motion Plus is also connected
|
||||
*
|
||||
* the third ::LED will indicate that a Nunchuck controller is also connected.
|
||||
*/
|
||||
void setLedStatus();
|
||||
/**
|
||||
* 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;
|
||||
};
|
||||
|
||||
/**
|
||||
* Return the battery level of the Wiimote.
|
||||
* @return The battery level in the range 0-255.
|
||||
*/
|
||||
uint8_t getBatteryLevel() { return batteryLevel; };
|
||||
/**
|
||||
* Return the Wiimote state.
|
||||
* @return See: http://wiibrew.org/wiki/Wiimote#0x20:_Status.
|
||||
*/
|
||||
uint8_t getWiiState() { return wiiState; };
|
||||
/**@}*/
|
||||
/**
|
||||
* 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;
|
||||
};
|
||||
|
||||
/**@{*/
|
||||
/** Variable used to indicate if a Wiimote is connected. */
|
||||
bool wiimoteConnected;
|
||||
/** Variable used to indicate if a Nunchuck controller is connected. */
|
||||
bool nunchuckConnected;
|
||||
/** Variable used to indicate if a Nunchuck controller is connected. */
|
||||
bool motionPlusConnected;
|
||||
/** Variable used to indicate if a Wii U Pro controller is connected. */
|
||||
bool wiiUProControllerConnected;
|
||||
/**@}*/
|
||||
/** Used to set all LEDs and rumble off. */
|
||||
void setAllOff();
|
||||
/** Turn off rumble. */
|
||||
void setRumbleOff();
|
||||
/** Turn on rumble. */
|
||||
void setRumbleOn();
|
||||
/** Toggle rumble. */
|
||||
void setRumbleToggle();
|
||||
/**
|
||||
* Turn the specific ::LED off.
|
||||
* @param a The ::LED to turn off.
|
||||
*/
|
||||
void setLedOff(LED a);
|
||||
/**
|
||||
* Turn the specific ::LED on.
|
||||
* @param a The ::LED to turn on.
|
||||
*/
|
||||
void setLedOn(LED a);
|
||||
/**
|
||||
* Toggle the specific ::LED.
|
||||
* @param a The ::LED to toggle.
|
||||
*/
|
||||
void setLedToggle(LED a);
|
||||
/**
|
||||
* This will set the LEDs, so the user can see which connections are active.
|
||||
*
|
||||
* The first ::LED indicate that the Wiimote is connected,
|
||||
*
|
||||
* the second ::LED indicate indicate that a Motion Plus is also connected
|
||||
*
|
||||
* the third ::LED will indicate that a Nunchuck controller is also connected.
|
||||
*/
|
||||
void setLedStatus();
|
||||
|
||||
/* IMU Data, might be usefull if you need to do something more advanced than just calculating the angle */
|
||||
/**
|
||||
* Return the battery level of the Wiimote.
|
||||
* @return The battery level in the range 0-255.
|
||||
*/
|
||||
uint8_t getBatteryLevel() {
|
||||
return batteryLevel;
|
||||
};
|
||||
|
||||
/**@{*/
|
||||
/** Pitch and roll calculated from the accelerometer inside the Wiimote. */
|
||||
double wiimotePitch;
|
||||
double wiimoteRoll;
|
||||
/**@}*/
|
||||
/**
|
||||
* Return the Wiimote state.
|
||||
* @return See: http://wiibrew.org/wiki/Wiimote#0x20:_Status.
|
||||
*/
|
||||
uint8_t getWiiState() {
|
||||
return wiiState;
|
||||
};
|
||||
/**@}*/
|
||||
|
||||
/**@{*/
|
||||
/** Pitch and roll calculated from the accelerometer inside the Nunchuck. */
|
||||
double nunchuckPitch;
|
||||
double nunchuckRoll;
|
||||
/**@}*/
|
||||
/**@{*/
|
||||
/** Variable used to indicate if a Wiimote is connected. */
|
||||
bool wiimoteConnected;
|
||||
/** Variable used to indicate if a Nunchuck controller is connected. */
|
||||
bool nunchuckConnected;
|
||||
/** Variable used to indicate if a Nunchuck controller is connected. */
|
||||
bool motionPlusConnected;
|
||||
/** Variable used to indicate if a Wii U Pro controller is connected. */
|
||||
bool wiiUProControllerConnected;
|
||||
/**@}*/
|
||||
|
||||
/**@{*/
|
||||
/** Accelerometer values used to calculate pitch and roll. */
|
||||
int16_t accX;
|
||||
int16_t accY;
|
||||
int16_t accZ;
|
||||
/**@}*/
|
||||
/* IMU Data, might be usefull if you need to do something more advanced than just calculating the angle */
|
||||
|
||||
/* Variables for the gyro inside the Motion Plus */
|
||||
/** This is the pitch calculated by the gyro - use this to tune WII#pitchGyroScale. */
|
||||
double gyroPitch;
|
||||
/** This is the roll calculated by the gyro - use this to tune WII#rollGyroScale. */
|
||||
double gyroRoll;
|
||||
/** This is the yaw calculated by the gyro - use this to tune WII#yawGyroScale. */
|
||||
double gyroYaw;
|
||||
/**@{*/
|
||||
/** Pitch and roll calculated from the accelerometer inside the Wiimote. */
|
||||
double wiimotePitch;
|
||||
double wiimoteRoll;
|
||||
/**@}*/
|
||||
|
||||
/**@{*/
|
||||
/** The speed in deg/s from the gyro. */
|
||||
double pitchGyroSpeed;
|
||||
double rollGyroSpeed;
|
||||
double yawGyroSpeed;
|
||||
/**@}*/
|
||||
/**@{*/
|
||||
/** Pitch and roll calculated from the accelerometer inside the Nunchuck. */
|
||||
double nunchuckPitch;
|
||||
double nunchuckRoll;
|
||||
/**@}*/
|
||||
|
||||
/**@{*/
|
||||
/** You might need to fine-tune these values. */
|
||||
uint16_t pitchGyroScale;
|
||||
uint16_t rollGyroScale;
|
||||
uint16_t yawGyroScale;
|
||||
/**@}*/
|
||||
/**@{*/
|
||||
/** Accelerometer values used to calculate pitch and roll. */
|
||||
int16_t accX;
|
||||
int16_t accY;
|
||||
int16_t accZ;
|
||||
/**@}*/
|
||||
|
||||
/**@{*/
|
||||
/** Raw value read directly from the Motion Plus. */
|
||||
int16_t gyroYawRaw;
|
||||
int16_t gyroRollRaw;
|
||||
int16_t gyroPitchRaw;
|
||||
/**@}*/
|
||||
/* Variables for the gyro inside the Motion Plus */
|
||||
/** This is the pitch calculated by the gyro - use this to tune WII#pitchGyroScale. */
|
||||
double gyroPitch;
|
||||
/** This is the roll calculated by the gyro - use this to tune WII#rollGyroScale. */
|
||||
double gyroRoll;
|
||||
/** This is the yaw calculated by the gyro - use this to tune WII#yawGyroScale. */
|
||||
double gyroYaw;
|
||||
|
||||
/**@{*/
|
||||
/** These values are set when the controller is first initialized. */
|
||||
int16_t gyroYawZero;
|
||||
int16_t gyroRollZero;
|
||||
int16_t gyroPitchZero;
|
||||
/**@}*/
|
||||
/**@{*/
|
||||
/** The speed in deg/s from the gyro. */
|
||||
double pitchGyroSpeed;
|
||||
double rollGyroSpeed;
|
||||
double yawGyroSpeed;
|
||||
/**@}*/
|
||||
|
||||
/**@{*/
|
||||
/** You might need to fine-tune these values. */
|
||||
uint16_t pitchGyroScale;
|
||||
uint16_t rollGyroScale;
|
||||
uint16_t yawGyroScale;
|
||||
/**@}*/
|
||||
|
||||
/**@{*/
|
||||
/** Raw value read directly from the Motion Plus. */
|
||||
int16_t gyroYawRaw;
|
||||
int16_t gyroRollRaw;
|
||||
int16_t gyroPitchRaw;
|
||||
/**@}*/
|
||||
|
||||
/**@{*/
|
||||
/** These values are set when the controller is first initialized. */
|
||||
int16_t gyroYawZero;
|
||||
int16_t gyroRollZero;
|
||||
int16_t gyroPitchZero;
|
||||
/**@}*/
|
||||
|
||||
#ifdef WIICAMERA
|
||||
/** @name Wiimote IR camera functions
|
||||
* You will have to uncomment #WIICAMERA in Wii.h to use the IR camera.
|
||||
*/
|
||||
/** Initialises the camera as per the steps from: http://wiibrew.org/wiki/Wiimote#IR_Camera */
|
||||
void IRinitialize();
|
||||
/** @name Wiimote IR camera functions
|
||||
* You will have to uncomment #WIICAMERA in Wii.h to use the IR camera.
|
||||
*/
|
||||
/** Initialises the camera as per the steps from: http://wiibrew.org/wiki/Wiimote#IR_Camera */
|
||||
void IRinitialize();
|
||||
|
||||
/**
|
||||
* 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; };
|
||||
/**
|
||||
* 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; };
|
||||
/**
|
||||
* 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; };
|
||||
/**
|
||||
* 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;
|
||||
};
|
||||
|
||||
/**
|
||||
* 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; };
|
||||
/**
|
||||
* 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; };
|
||||
/**
|
||||
* 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; };
|
||||
/**
|
||||
* 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;
|
||||
};
|
||||
|
||||
/**
|
||||
* 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; };
|
||||
/**
|
||||
* 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; };
|
||||
/**
|
||||
* 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; };
|
||||
/**
|
||||
* 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;
|
||||
};
|
||||
|
||||
/**
|
||||
* 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; };
|
||||
/**
|
||||
* 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; };
|
||||
/**
|
||||
* 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; };
|
||||
/**
|
||||
* 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;
|
||||
};
|
||||
|
||||
/**
|
||||
* 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); };
|
||||
/**@}*/
|
||||
/**
|
||||
* 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;
|
||||
};
|
||||
|
||||
/**
|
||||
* 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;
|
||||
};
|
||||
|
||||
/**
|
||||
* 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;
|
||||
};
|
||||
|
||||
/**
|
||||
* 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;
|
||||
};
|
||||
|
||||
/**
|
||||
* 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;
|
||||
};
|
||||
|
||||
/**
|
||||
* 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;
|
||||
};
|
||||
|
||||
/**
|
||||
* 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;
|
||||
};
|
||||
|
||||
/**
|
||||
* 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;
|
||||
};
|
||||
|
||||
/**
|
||||
* 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);
|
||||
};
|
||||
/**@}*/
|
||||
#endif
|
||||
|
||||
private:
|
||||
/* Mandatory members */
|
||||
BTD *pBtd;
|
||||
/* Mandatory members */
|
||||
BTD *pBtd;
|
||||
|
||||
void L2CAP_task(); // L2CAP state machine
|
||||
void L2CAP_task(); // L2CAP state machine
|
||||
|
||||
/* Variables filled from HCI event management */
|
||||
uint16_t hci_handle;
|
||||
bool activeConnection; // Used to indicate if it's already has established a connection
|
||||
/* Variables filled from HCI event management */
|
||||
uint16_t hci_handle;
|
||||
bool activeConnection; // Used to indicate if it's already has established a connection
|
||||
|
||||
/* variables used by high level L2CAP task */
|
||||
uint8_t l2cap_state;
|
||||
uint16_t l2cap_event_flag;// l2cap flags of received bluetooth events
|
||||
/* variables used by high level L2CAP task */
|
||||
uint8_t l2cap_state;
|
||||
uint16_t l2cap_event_flag; // l2cap flags of received bluetooth events
|
||||
|
||||
uint32_t ButtonState;
|
||||
uint32_t OldButtonState;
|
||||
uint32_t ButtonClickState;
|
||||
uint16_t hatValues[4];
|
||||
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;
|
||||
bool extensionConnected;
|
||||
uint16_t stateCounter;
|
||||
bool unknownExtensionConnected;
|
||||
bool extensionConnected;
|
||||
|
||||
/* L2CAP Channels */
|
||||
uint8_t control_scid[2]; // L2CAP source CID for HID_Control
|
||||
uint8_t control_dcid[2]; // 0x0060
|
||||
uint8_t interrupt_scid[2]; // L2CAP source CID for HID_Interrupt
|
||||
uint8_t interrupt_dcid[2]; // 0x0061
|
||||
uint8_t identifier; // Identifier for connection
|
||||
/* L2CAP Channels */
|
||||
uint8_t control_scid[2]; // L2CAP source CID for HID_Control
|
||||
uint8_t control_dcid[2]; // 0x0060
|
||||
uint8_t interrupt_scid[2]; // L2CAP source CID for HID_Interrupt
|
||||
uint8_t interrupt_dcid[2]; // 0x0061
|
||||
uint8_t identifier; // Identifier for connection
|
||||
|
||||
/* HID Commands */
|
||||
void HID_Command(uint8_t* data, uint8_t nbytes);
|
||||
void setReportMode(bool continuous, uint8_t mode);
|
||||
void statusRequest();
|
||||
/* HID Commands */
|
||||
void HID_Command(uint8_t* data, uint8_t nbytes);
|
||||
void setReportMode(bool continuous, uint8_t mode);
|
||||
void statusRequest();
|
||||
|
||||
void writeData(uint32_t offset, uint8_t size, uint8_t* data);
|
||||
void initExtension1();
|
||||
void initExtension2();
|
||||
void writeData(uint32_t offset, uint8_t size, uint8_t* data);
|
||||
void initExtension1();
|
||||
void initExtension2();
|
||||
|
||||
void readData(uint32_t offset, uint16_t size, bool EEPROM);
|
||||
void readExtensionType();
|
||||
void readCalData();
|
||||
void readData(uint32_t offset, uint16_t size, bool EEPROM);
|
||||
void readExtensionType();
|
||||
void readCalData();
|
||||
|
||||
void checkMotionPresent(); // Used to see if a Motion Plus is connected to the Wiimote
|
||||
void initMotionPlus();
|
||||
void activateMotionPlus();
|
||||
void checkMotionPresent(); // Used to see if a Motion Plus is connected to the Wiimote
|
||||
void initMotionPlus();
|
||||
void activateMotionPlus();
|
||||
|
||||
double pitch; // Fusioned angle using a complimentary filter if the Motion Plus is connected
|
||||
double roll; // Fusioned angle using a complimentary filter if the Motion Plus is connected
|
||||
double pitch; // Fusioned angle using a complimentary filter if the Motion Plus is connected
|
||||
double roll; // Fusioned angle using a complimentary filter if the Motion Plus is connected
|
||||
|
||||
bool activateNunchuck;
|
||||
bool motionValuesReset; // This bool is true when the gyro values has been reset
|
||||
unsigned long timer;
|
||||
bool activateNunchuck;
|
||||
bool motionValuesReset; // This bool is true when the gyro values has been reset
|
||||
unsigned long timer;
|
||||
|
||||
uint8_t wiiState; // Stores the value in l2capinbuf[12] - (0x01: Battery is nearly empty), (0x02: An Extension Controller is connected), (0x04: Speaker enabled), (0x08: IR enabled), (0x10: LED1, 0x20: LED2, 0x40: LED3, 0x80: LED4)
|
||||
uint8_t batteryLevel;
|
||||
uint8_t wiiState; // Stores the value in l2capinbuf[12] - (0x01: Battery is nearly empty), (0x02: An Extension Controller is connected), (0x04: Speaker enabled), (0x08: IR enabled), (0x10: LED1, 0x20: LED2, 0x40: LED3, 0x80: LED4)
|
||||
uint8_t batteryLevel;
|
||||
|
||||
#ifdef WIICAMERA
|
||||
/* Private function and variables for the readings from teh IR Camera */
|
||||
void enableIRCamera1(); // Sets bit 2 of output report 13
|
||||
void enableIRCamera2(); // Sets bit 2 of output report 1A
|
||||
void writeSensitivityBlock1();
|
||||
void writeSensitivityBlock2();
|
||||
void write0x08Value();
|
||||
void setWiiModeNumber(uint8_t mode_number);
|
||||
/* Private function and variables for the readings from teh IR Camera */
|
||||
void enableIRCamera1(); // Sets bit 2 of output report 13
|
||||
void enableIRCamera2(); // Sets bit 2 of output report 1A
|
||||
void writeSensitivityBlock1();
|
||||
void writeSensitivityBlock2();
|
||||
void write0x08Value();
|
||||
void setWiiModeNumber(uint8_t mode_number);
|
||||
|
||||
uint16_t IR_object_x1; // IR x position 10 bits
|
||||
uint16_t IR_object_y1; // IR y position 10 bits
|
||||
uint8_t IR_object_s1; // IR size value
|
||||
uint16_t IR_object_x2;
|
||||
uint16_t IR_object_y2;
|
||||
uint8_t IR_object_s2;
|
||||
uint16_t IR_object_x3; // IR x position 10 bits
|
||||
uint16_t IR_object_y3; // IR y position 10 bits
|
||||
uint8_t IR_object_s3; // IR size value
|
||||
uint16_t IR_object_x4;
|
||||
uint16_t IR_object_y4;
|
||||
uint8_t IR_object_s4;
|
||||
uint16_t IR_object_x1; // IR x position 10 bits
|
||||
uint16_t IR_object_y1; // IR y position 10 bits
|
||||
uint8_t IR_object_s1; // IR size value
|
||||
uint16_t IR_object_x2;
|
||||
uint16_t IR_object_y2;
|
||||
uint8_t IR_object_s2;
|
||||
uint16_t IR_object_x3; // IR x position 10 bits
|
||||
uint16_t IR_object_y3; // IR y position 10 bits
|
||||
uint8_t IR_object_s3; // IR size value
|
||||
uint16_t IR_object_x4;
|
||||
uint16_t IR_object_y4;
|
||||
uint8_t IR_object_s4;
|
||||
#endif
|
||||
};
|
||||
#endif
|
705
XBOXRECV.cpp
705
XBOXRECV.cpp
|
@ -22,395 +22,411 @@
|
|||
//#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++) {
|
||||
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;
|
||||
}
|
||||
for (uint8_t i = 0; i < XBOX_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;
|
||||
}
|
||||
|
||||
if (pUsb) // register in USB subsystem
|
||||
pUsb->RegisterDeviceClass(this); //set devConfig[] entry
|
||||
if (pUsb) // register in USB subsystem
|
||||
pUsb->RegisterDeviceClass(this); //set devConfig[] entry
|
||||
}
|
||||
|
||||
uint8_t XBOXRECV::Init(uint8_t parent, uint8_t port, bool lowspeed) {
|
||||
uint8_t buf[sizeof(USB_DEVICE_DESCRIPTOR)];
|
||||
uint8_t rcode;
|
||||
UsbDevice *p = NULL;
|
||||
EpInfo *oldep_ptr = NULL;
|
||||
uint16_t PID;
|
||||
uint16_t VID;
|
||||
uint8_t buf[sizeof (USB_DEVICE_DESCRIPTOR)];
|
||||
uint8_t rcode;
|
||||
UsbDevice *p = NULL;
|
||||
EpInfo *oldep_ptr = NULL;
|
||||
uint16_t PID;
|
||||
uint16_t VID;
|
||||
|
||||
// get memory address of USB device address pool
|
||||
AddressPool &addrPool = pUsb->GetAddressPool();
|
||||
// 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) {
|
||||
// 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;
|
||||
}
|
||||
return USB_ERROR_CLASS_INSTANCE_ALREADY_IN_USE;
|
||||
}
|
||||
|
||||
// Get pointer to pseudo device with address 0 assigned
|
||||
p = addrPool.GetUsbDevicePtr(0);
|
||||
// Get pointer to pseudo device with address 0 assigned
|
||||
p = addrPool.GetUsbDevicePtr(0);
|
||||
|
||||
if (!p) {
|
||||
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;
|
||||
}
|
||||
return USB_ERROR_ADDRESS_NOT_FOUND_IN_POOL;
|
||||
}
|
||||
|
||||
if (!p->epinfo) {
|
||||
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;
|
||||
}
|
||||
return USB_ERROR_EPINFO_IS_NULL;
|
||||
}
|
||||
|
||||
// Save old pointer to EP_RECORD of address 0
|
||||
oldep_ptr = p->epinfo;
|
||||
// Save old pointer to EP_RECORD of address 0
|
||||
oldep_ptr = p->epinfo;
|
||||
|
||||
// Temporary assign new pointer to epInfo to p->epinfo in order to avoid toggle inconsistence
|
||||
p->epinfo = epInfo;
|
||||
// Temporary assign new pointer to epInfo to p->epinfo in order to avoid toggle inconsistence
|
||||
p->epinfo = epInfo;
|
||||
|
||||
p->lowspeed = 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
|
||||
// Restore p->epinfo
|
||||
p->epinfo = oldep_ptr;
|
||||
// Get device descriptor
|
||||
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)
|
||||
goto FailGetDevDescr;
|
||||
if (rcode)
|
||||
goto FailGetDevDescr;
|
||||
|
||||
VID = ((USB_DEVICE_DESCRIPTOR*)buf)->idVendor;
|
||||
PID = ((USB_DEVICE_DESCRIPTOR*)buf)->idProduct;
|
||||
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
|
||||
goto FailUnknownDevice;
|
||||
else if(PID != XBOX_WIRELESS_RECEIVER_PID && PID != XBOX_WIRELESS_RECEIVER_THIRD_PARTY_PID) {
|
||||
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) {
|
||||
#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;
|
||||
}
|
||||
goto FailUnknownDevice;
|
||||
}
|
||||
|
||||
// Allocate new address according to device class
|
||||
bAddress = addrPool.AllocAddress(parent, false, port);
|
||||
// Allocate new address according to device class
|
||||
bAddress = addrPool.AllocAddress(parent, false, port);
|
||||
|
||||
if (!bAddress)
|
||||
return USB_ERROR_OUT_OF_ADDRESS_SPACE_IN_POOL;
|
||||
if (!bAddress)
|
||||
return USB_ERROR_OUT_OF_ADDRESS_SPACE_IN_POOL;
|
||||
|
||||
// Extract Max Packet Size from device descriptor
|
||||
epInfo[0].maxPktSize = (uint8_t)((USB_DEVICE_DESCRIPTOR*)buf)->bMaxPacketSize0;
|
||||
// Extract Max Packet Size from device descriptor
|
||||
epInfo[0].maxPktSize = (uint8_t)((USB_DEVICE_DESCRIPTOR*)buf)->bMaxPacketSize0;
|
||||
|
||||
// Assign new address to the device
|
||||
rcode = pUsb->setAddr( 0, 0, bAddress );
|
||||
if (rcode) {
|
||||
// Assign new address to the device
|
||||
rcode = pUsb->setAddr(0, 0, bAddress);
|
||||
if (rcode) {
|
||||
p->lowspeed = false;
|
||||
addrPool.FreeAddress(bAddress);
|
||||
bAddress = 0;
|
||||
#ifdef DEBUG
|
||||
Notify(PSTR("\r\nsetAddr: "), 0x80);
|
||||
#endif
|
||||
PrintHex<uint8_t > (rcode, 0x80);
|
||||
return rcode;
|
||||
}
|
||||
#ifdef EXTRADEBUG
|
||||
Notify(PSTR("\r\nAddr: "), 0x80);
|
||||
PrintHex<uint8_t > (bAddress, 0x80);
|
||||
#endif
|
||||
p->lowspeed = false;
|
||||
addrPool.FreeAddress(bAddress);
|
||||
bAddress = 0;
|
||||
#ifdef DEBUG
|
||||
Notify(PSTR("\r\nsetAddr: "));
|
||||
#endif
|
||||
PrintHex<uint8_t>(rcode);
|
||||
return rcode;
|
||||
}
|
||||
#ifdef EXTRADEBUG
|
||||
Notify(PSTR("\r\nAddr: "));
|
||||
PrintHex<uint8_t>(bAddress);
|
||||
#endif
|
||||
p->lowspeed = false;
|
||||
|
||||
//get pointer to assigned address record
|
||||
p = addrPool.GetUsbDevicePtr(bAddress);
|
||||
if (!p)
|
||||
return USB_ERROR_ADDRESS_NOT_FOUND_IN_POOL;
|
||||
//get pointer to assigned address record
|
||||
p = addrPool.GetUsbDevicePtr(bAddress);
|
||||
if (!p)
|
||||
return USB_ERROR_ADDRESS_NOT_FOUND_IN_POOL;
|
||||
|
||||
p->lowspeed = lowspeed;
|
||||
p->lowspeed = lowspeed;
|
||||
|
||||
// Assign epInfo to epinfo pointer - only EP0 is known
|
||||
rcode = pUsb->setEpInfoEntry(bAddress, 1, epInfo);
|
||||
if (rcode)
|
||||
goto FailSetDevTblEntry;
|
||||
// Assign epInfo to epinfo pointer - only EP0 is known
|
||||
rcode = pUsb->setEpInfoEntry(bAddress, 1, epInfo);
|
||||
if (rcode)
|
||||
goto FailSetDevTblEntry;
|
||||
|
||||
/* The application will work in reduced host mode, so we can save program and data
|
||||
memory space. After verifying the VID we will use known values for the
|
||||
configuration values for device, interface, endpoints and HID for the XBOX360 Wireless receiver */
|
||||
/* The application will work in reduced host mode, so we can save program and data
|
||||
memory space. After verifying the VID we will use known values for the
|
||||
configuration values for device, interface, endpoints and HID for the XBOX360 Wireless receiver */
|
||||
|
||||
/* Initialize data structures for endpoints of device */
|
||||
epInfo[ XBOX_INPUT_PIPE_1 ].epAddr = 0x01; // XBOX 360 report endpoint - poll interval 1ms
|
||||
epInfo[ XBOX_INPUT_PIPE_1 ].epAttribs = EP_INTERRUPT;
|
||||
epInfo[ XBOX_INPUT_PIPE_1 ].bmNakPower = USB_NAK_NOWAIT; // Only poll once for interrupt endpoints
|
||||
epInfo[ XBOX_INPUT_PIPE_1 ].maxPktSize = EP_MAXPKTSIZE;
|
||||
epInfo[ XBOX_INPUT_PIPE_1 ].bmSndToggle = bmSNDTOG0;
|
||||
epInfo[ XBOX_INPUT_PIPE_1 ].bmRcvToggle = bmRCVTOG0;
|
||||
epInfo[ XBOX_OUTPUT_PIPE_1 ].epAddr = 0x01; // XBOX 360 output endpoint - poll interval 8ms
|
||||
epInfo[ XBOX_OUTPUT_PIPE_1 ].epAttribs = EP_INTERRUPT;
|
||||
epInfo[ XBOX_OUTPUT_PIPE_1 ].bmNakPower = USB_NAK_NOWAIT; // Only poll once for interrupt endpoints
|
||||
epInfo[ XBOX_OUTPUT_PIPE_1 ].maxPktSize = EP_MAXPKTSIZE;
|
||||
epInfo[ XBOX_OUTPUT_PIPE_1 ].bmSndToggle = bmSNDTOG0;
|
||||
epInfo[ XBOX_OUTPUT_PIPE_1 ].bmRcvToggle = bmRCVTOG0;
|
||||
/* Initialize data structures for endpoints of device */
|
||||
epInfo[ XBOX_INPUT_PIPE_1 ].epAddr = 0x01; // XBOX 360 report endpoint - poll interval 1ms
|
||||
epInfo[ XBOX_INPUT_PIPE_1 ].epAttribs = EP_INTERRUPT;
|
||||
epInfo[ XBOX_INPUT_PIPE_1 ].bmNakPower = USB_NAK_NOWAIT; // Only poll once for interrupt endpoints
|
||||
epInfo[ XBOX_INPUT_PIPE_1 ].maxPktSize = EP_MAXPKTSIZE;
|
||||
epInfo[ XBOX_INPUT_PIPE_1 ].bmSndToggle = bmSNDTOG0;
|
||||
epInfo[ XBOX_INPUT_PIPE_1 ].bmRcvToggle = bmRCVTOG0;
|
||||
epInfo[ XBOX_OUTPUT_PIPE_1 ].epAddr = 0x01; // XBOX 360 output endpoint - poll interval 8ms
|
||||
epInfo[ XBOX_OUTPUT_PIPE_1 ].epAttribs = EP_INTERRUPT;
|
||||
epInfo[ XBOX_OUTPUT_PIPE_1 ].bmNakPower = USB_NAK_NOWAIT; // Only poll once for interrupt endpoints
|
||||
epInfo[ XBOX_OUTPUT_PIPE_1 ].maxPktSize = EP_MAXPKTSIZE;
|
||||
epInfo[ XBOX_OUTPUT_PIPE_1 ].bmSndToggle = bmSNDTOG0;
|
||||
epInfo[ XBOX_OUTPUT_PIPE_1 ].bmRcvToggle = bmRCVTOG0;
|
||||
|
||||
epInfo[ XBOX_INPUT_PIPE_2 ].epAddr = 0x03; // XBOX 360 report endpoint - poll interval 1ms
|
||||
epInfo[ XBOX_INPUT_PIPE_2 ].epAttribs = EP_INTERRUPT;
|
||||
epInfo[ XBOX_INPUT_PIPE_2 ].bmNakPower = USB_NAK_NOWAIT; // Only poll once for interrupt endpoints
|
||||
epInfo[ XBOX_INPUT_PIPE_2 ].maxPktSize = EP_MAXPKTSIZE;
|
||||
epInfo[ XBOX_INPUT_PIPE_2 ].bmSndToggle = bmSNDTOG0;
|
||||
epInfo[ XBOX_INPUT_PIPE_2 ].bmRcvToggle = bmRCVTOG0;
|
||||
epInfo[ XBOX_OUTPUT_PIPE_2 ].epAddr = 0x03; // XBOX 360 output endpoint - poll interval 8ms
|
||||
epInfo[ XBOX_OUTPUT_PIPE_2 ].epAttribs = EP_INTERRUPT;
|
||||
epInfo[ XBOX_OUTPUT_PIPE_2 ].bmNakPower = USB_NAK_NOWAIT; // Only poll once for interrupt endpoints
|
||||
epInfo[ XBOX_OUTPUT_PIPE_2 ].maxPktSize = EP_MAXPKTSIZE;
|
||||
epInfo[ XBOX_OUTPUT_PIPE_2 ].bmSndToggle = bmSNDTOG0;
|
||||
epInfo[ XBOX_OUTPUT_PIPE_2 ].bmRcvToggle = bmRCVTOG0;
|
||||
epInfo[ XBOX_INPUT_PIPE_2 ].epAddr = 0x03; // XBOX 360 report endpoint - poll interval 1ms
|
||||
epInfo[ XBOX_INPUT_PIPE_2 ].epAttribs = EP_INTERRUPT;
|
||||
epInfo[ XBOX_INPUT_PIPE_2 ].bmNakPower = USB_NAK_NOWAIT; // Only poll once for interrupt endpoints
|
||||
epInfo[ XBOX_INPUT_PIPE_2 ].maxPktSize = EP_MAXPKTSIZE;
|
||||
epInfo[ XBOX_INPUT_PIPE_2 ].bmSndToggle = bmSNDTOG0;
|
||||
epInfo[ XBOX_INPUT_PIPE_2 ].bmRcvToggle = bmRCVTOG0;
|
||||
epInfo[ XBOX_OUTPUT_PIPE_2 ].epAddr = 0x03; // XBOX 360 output endpoint - poll interval 8ms
|
||||
epInfo[ XBOX_OUTPUT_PIPE_2 ].epAttribs = EP_INTERRUPT;
|
||||
epInfo[ XBOX_OUTPUT_PIPE_2 ].bmNakPower = USB_NAK_NOWAIT; // Only poll once for interrupt endpoints
|
||||
epInfo[ XBOX_OUTPUT_PIPE_2 ].maxPktSize = EP_MAXPKTSIZE;
|
||||
epInfo[ XBOX_OUTPUT_PIPE_2 ].bmSndToggle = bmSNDTOG0;
|
||||
epInfo[ XBOX_OUTPUT_PIPE_2 ].bmRcvToggle = bmRCVTOG0;
|
||||
|
||||
epInfo[ XBOX_INPUT_PIPE_3 ].epAddr = 0x05; // XBOX 360 report endpoint - poll interval 1ms
|
||||
epInfo[ XBOX_INPUT_PIPE_3 ].epAttribs = EP_INTERRUPT;
|
||||
epInfo[ XBOX_INPUT_PIPE_3 ].bmNakPower = USB_NAK_NOWAIT; // Only poll once for interrupt endpoints
|
||||
epInfo[ XBOX_INPUT_PIPE_3 ].maxPktSize = EP_MAXPKTSIZE;
|
||||
epInfo[ XBOX_INPUT_PIPE_3 ].bmSndToggle = bmSNDTOG0;
|
||||
epInfo[ XBOX_INPUT_PIPE_3 ].bmRcvToggle = bmRCVTOG0;
|
||||
epInfo[ XBOX_OUTPUT_PIPE_3 ].epAddr = 0x05; // XBOX 360 output endpoint - poll interval 8ms
|
||||
epInfo[ XBOX_OUTPUT_PIPE_3 ].epAttribs = EP_INTERRUPT;
|
||||
epInfo[ XBOX_OUTPUT_PIPE_3 ].bmNakPower = USB_NAK_NOWAIT; // Only poll once for interrupt endpoints
|
||||
epInfo[ XBOX_OUTPUT_PIPE_3 ].maxPktSize = EP_MAXPKTSIZE;
|
||||
epInfo[ XBOX_OUTPUT_PIPE_3 ].bmSndToggle = bmSNDTOG0;
|
||||
epInfo[ XBOX_OUTPUT_PIPE_3 ].bmRcvToggle = bmRCVTOG0;
|
||||
epInfo[ XBOX_INPUT_PIPE_3 ].epAddr = 0x05; // XBOX 360 report endpoint - poll interval 1ms
|
||||
epInfo[ XBOX_INPUT_PIPE_3 ].epAttribs = EP_INTERRUPT;
|
||||
epInfo[ XBOX_INPUT_PIPE_3 ].bmNakPower = USB_NAK_NOWAIT; // Only poll once for interrupt endpoints
|
||||
epInfo[ XBOX_INPUT_PIPE_3 ].maxPktSize = EP_MAXPKTSIZE;
|
||||
epInfo[ XBOX_INPUT_PIPE_3 ].bmSndToggle = bmSNDTOG0;
|
||||
epInfo[ XBOX_INPUT_PIPE_3 ].bmRcvToggle = bmRCVTOG0;
|
||||
epInfo[ XBOX_OUTPUT_PIPE_3 ].epAddr = 0x05; // XBOX 360 output endpoint - poll interval 8ms
|
||||
epInfo[ XBOX_OUTPUT_PIPE_3 ].epAttribs = EP_INTERRUPT;
|
||||
epInfo[ XBOX_OUTPUT_PIPE_3 ].bmNakPower = USB_NAK_NOWAIT; // Only poll once for interrupt endpoints
|
||||
epInfo[ XBOX_OUTPUT_PIPE_3 ].maxPktSize = EP_MAXPKTSIZE;
|
||||
epInfo[ XBOX_OUTPUT_PIPE_3 ].bmSndToggle = bmSNDTOG0;
|
||||
epInfo[ XBOX_OUTPUT_PIPE_3 ].bmRcvToggle = bmRCVTOG0;
|
||||
|
||||
epInfo[ XBOX_INPUT_PIPE_4 ].epAddr = 0x07; // XBOX 360 report endpoint - poll interval 1ms
|
||||
epInfo[ XBOX_INPUT_PIPE_4 ].epAttribs = EP_INTERRUPT;
|
||||
epInfo[ XBOX_INPUT_PIPE_4 ].bmNakPower = USB_NAK_NOWAIT; // Only poll once for interrupt endpoints
|
||||
epInfo[ XBOX_INPUT_PIPE_4 ].maxPktSize = EP_MAXPKTSIZE;
|
||||
epInfo[ XBOX_INPUT_PIPE_4 ].bmSndToggle = bmSNDTOG0;
|
||||
epInfo[ XBOX_INPUT_PIPE_4 ].bmRcvToggle = bmRCVTOG0;
|
||||
epInfo[ XBOX_OUTPUT_PIPE_4 ].epAddr = 0x07; // XBOX 360 output endpoint - poll interval 8ms
|
||||
epInfo[ XBOX_OUTPUT_PIPE_4 ].epAttribs = EP_INTERRUPT;
|
||||
epInfo[ XBOX_OUTPUT_PIPE_4 ].bmNakPower = USB_NAK_NOWAIT; // Only poll once for interrupt endpoints
|
||||
epInfo[ XBOX_OUTPUT_PIPE_4 ].maxPktSize = EP_MAXPKTSIZE;
|
||||
epInfo[ XBOX_OUTPUT_PIPE_4 ].bmSndToggle = bmSNDTOG0;
|
||||
epInfo[ XBOX_OUTPUT_PIPE_4 ].bmRcvToggle = bmRCVTOG0;
|
||||
epInfo[ XBOX_INPUT_PIPE_4 ].epAddr = 0x07; // XBOX 360 report endpoint - poll interval 1ms
|
||||
epInfo[ XBOX_INPUT_PIPE_4 ].epAttribs = EP_INTERRUPT;
|
||||
epInfo[ XBOX_INPUT_PIPE_4 ].bmNakPower = USB_NAK_NOWAIT; // Only poll once for interrupt endpoints
|
||||
epInfo[ XBOX_INPUT_PIPE_4 ].maxPktSize = EP_MAXPKTSIZE;
|
||||
epInfo[ XBOX_INPUT_PIPE_4 ].bmSndToggle = bmSNDTOG0;
|
||||
epInfo[ XBOX_INPUT_PIPE_4 ].bmRcvToggle = bmRCVTOG0;
|
||||
epInfo[ XBOX_OUTPUT_PIPE_4 ].epAddr = 0x07; // XBOX 360 output endpoint - poll interval 8ms
|
||||
epInfo[ XBOX_OUTPUT_PIPE_4 ].epAttribs = EP_INTERRUPT;
|
||||
epInfo[ XBOX_OUTPUT_PIPE_4 ].bmNakPower = USB_NAK_NOWAIT; // Only poll once for interrupt endpoints
|
||||
epInfo[ XBOX_OUTPUT_PIPE_4 ].maxPktSize = EP_MAXPKTSIZE;
|
||||
epInfo[ XBOX_OUTPUT_PIPE_4 ].bmSndToggle = bmSNDTOG0;
|
||||
epInfo[ XBOX_OUTPUT_PIPE_4 ].bmRcvToggle = bmRCVTOG0;
|
||||
|
||||
rcode = pUsb->setEpInfoEntry(bAddress, 9, epInfo);
|
||||
if( rcode )
|
||||
goto FailSetDevTblEntry;
|
||||
rcode = pUsb->setEpInfoEntry(bAddress, 9, epInfo);
|
||||
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 )
|
||||
goto FailSetConf;
|
||||
rcode = pUsb->setConf(bAddress, epInfo[ XBOX_CONTROL_PIPE ].epAddr, 1);
|
||||
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;
|
||||
return 0; // successful configuration
|
||||
XboxReceiverConnected = true;
|
||||
bPollEnable = true;
|
||||
return 0; // successful configuration
|
||||
|
||||
/* diagnostic messages */
|
||||
/* diagnostic messages */
|
||||
FailGetDevDescr:
|
||||
#ifdef DEBUG
|
||||
Notify(PSTR("\r\ngetDevDescr:"));
|
||||
Notify(PSTR("\r\ngetDevDescr:"), 0x80);
|
||||
#endif
|
||||
goto Fail;
|
||||
goto Fail;
|
||||
FailSetDevTblEntry:
|
||||
#ifdef DEBUG
|
||||
Notify(PSTR("\r\nsetDevTblEn:"));
|
||||
Notify(PSTR("\r\nsetDevTblEn:"), 0x80);
|
||||
#endif
|
||||
goto Fail;
|
||||
goto Fail;
|
||||
FailSetConf:
|
||||
#ifdef DEBUG
|
||||
Notify(PSTR("\r\nsetConf:"));
|
||||
Notify(PSTR("\r\nsetConf:"), 0x80);
|
||||
#endif
|
||||
goto Fail;
|
||||
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;
|
||||
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;
|
||||
Release();
|
||||
return rcode;
|
||||
}
|
||||
|
||||
/* Performs a cleanup after failed Init() attempt */
|
||||
uint8_t XBOXRECV::Release() {
|
||||
XboxReceiverConnected = false;
|
||||
for(uint8_t i=0;i<4;i++)
|
||||
Xbox360Connected[i] = 0x00;
|
||||
pUsb->GetAddressPool().FreeAddress(bAddress);
|
||||
bAddress = 0;
|
||||
bPollEnable = false;
|
||||
return 0;
|
||||
XboxReceiverConnected = false;
|
||||
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
|
||||
timer = millis();
|
||||
checkStatus();
|
||||
}
|
||||
uint8_t inputPipe;
|
||||
uint16_t bufferSize;
|
||||
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;
|
||||
if (!bPollEnable)
|
||||
return 0;
|
||||
if (!timer || ((millis() - timer) > 3000)) { // Run checkStatus every 3 seconds
|
||||
timer = millis();
|
||||
checkStatus();
|
||||
}
|
||||
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
|
||||
uint8_t inputPipe;
|
||||
uint16_t bufferSize;
|
||||
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;
|
||||
}
|
||||
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
|
||||
#ifdef EXTRADEBUG
|
||||
Notify(PSTR("Bytes Received: "));
|
||||
Serial.print(bufferSize);
|
||||
Notify(PSTR("\r\n"));
|
||||
Notify(PSTR("Bytes Received: "), 0x80);
|
||||
Serial.print(bufferSize);
|
||||
Notify(PSTR("\r\n"), 0x80);
|
||||
#endif
|
||||
readReport(i);
|
||||
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
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
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]) {
|
||||
Xbox360Connected[controller] = readBuf[1];
|
||||
if (readBuf == NULL)
|
||||
return;
|
||||
// This report is send when a controller is connected and disconnected
|
||||
if (readBuf[0] == 0x08 && readBuf[1] != Xbox360Connected[controller]) {
|
||||
Xbox360Connected[controller] = readBuf[1];
|
||||
#ifdef DEBUG
|
||||
Notify(PSTR("Controller "));
|
||||
Serial.print(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;
|
||||
}
|
||||
Notify(PSTR(": connected"));
|
||||
Notify(str);
|
||||
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;
|
||||
}
|
||||
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;
|
||||
}
|
||||
setLedOn(controller,led);
|
||||
LED led;
|
||||
switch (controller) {
|
||||
case 0: led = LED1;
|
||||
break;
|
||||
case 1: led = LED2;
|
||||
break;
|
||||
case 2: led = LED3;
|
||||
break;
|
||||
case 3: led = LED4;
|
||||
break;
|
||||
}
|
||||
setLedOn(controller, led);
|
||||
}
|
||||
#ifdef DEBUG
|
||||
else
|
||||
Notify(PSTR(": disconnected\r\n"), 0x80);
|
||||
#endif
|
||||
return;
|
||||
}
|
||||
#ifdef DEBUG
|
||||
else
|
||||
Notify(PSTR(": disconnected\r\n"));
|
||||
#endif
|
||||
return;
|
||||
}
|
||||
// Controller status report
|
||||
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
|
||||
return;
|
||||
// Controller status report
|
||||
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
|
||||
return;
|
||||
|
||||
// A controller must be connected if it's sending data
|
||||
if(!Xbox360Connected[controller])
|
||||
Xbox360Connected[controller] |= 0x80;
|
||||
// A controller must be connected if it's sending data
|
||||
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));
|
||||
ButtonState[controller] = (uint32_t)(readBuf[9] | ((uint16_t)readBuf[8] << 8) | ((uint32_t)readBuf[7] << 16) | ((uint32_t)readBuf[6] << 24));
|
||||
|
||||
hatValue[controller][LeftHatX] = (int16_t)(((uint16_t)readBuf[11] << 8) | readBuf[10]);
|
||||
hatValue[controller][LeftHatY] = (int16_t)(((uint16_t)readBuf[13] << 8) | readBuf[12]);
|
||||
hatValue[controller][RightHatX] = (int16_t)(((uint16_t)readBuf[15] << 8) | readBuf[14]);
|
||||
hatValue[controller][RightHatY] = (int16_t)(((uint16_t)readBuf[17] << 8) | readBuf[16]);
|
||||
hatValue[controller][LeftHatX] = (int16_t)(((uint16_t)readBuf[11] << 8) | readBuf[10]);
|
||||
hatValue[controller][LeftHatY] = (int16_t)(((uint16_t)readBuf[13] << 8) | readBuf[12]);
|
||||
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]) {
|
||||
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
|
||||
R2Clicked[controller] = true;
|
||||
if((uint8_t)(OldButtonState[controller] >> 8) == 0 && (uint8_t)(ButtonState[controller] >> 8) != 0)
|
||||
L2Clicked[controller] = true;
|
||||
OldButtonState[controller] = ButtonState[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
|
||||
R2Clicked[controller] = true;
|
||||
if ((uint8_t)(OldButtonState[controller] >> 8) == 0 && (uint8_t)(ButtonState[controller] >> 8) != 0)
|
||||
L2Clicked[controller] = true;
|
||||
OldButtonState[controller] = ButtonState[controller];
|
||||
}
|
||||
}
|
||||
|
||||
void XBOXRECV::printReport(uint8_t controller, uint8_t nBytes) { //Uncomment "#define PRINTREPORT" to print the report send by the Xbox 360 Controller
|
||||
#ifdef PRINTREPORT
|
||||
if (readBuf == NULL)
|
||||
return;
|
||||
Notify(PSTR("Controller "));
|
||||
Serial.print(controller);
|
||||
Notify(PSTR(": "));
|
||||
for(uint8_t i = 0; i < nBytes;i++) {
|
||||
PrintHex<uint8_t>(readBuf[i]);
|
||||
Serial.print(" ");
|
||||
}
|
||||
Serial.println();
|
||||
if (readBuf == NULL)
|
||||
return;
|
||||
Notify(PSTR("Controller "), 0x80);
|
||||
Serial.print(controller);
|
||||
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
|
||||
return (uint8_t)(ButtonState[controller] >> 8);
|
||||
else if(b == R2)
|
||||
return (uint8_t)ButtonState[controller];
|
||||
return (ButtonState[controller] & ((uint32_t)pgm_read_word(&XBOXBUTTONS[(uint8_t)b]) << 16));
|
||||
if (b == L2) // These are analog buttons
|
||||
return (uint8_t)(ButtonState[controller] >> 8);
|
||||
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]) {
|
||||
L2Clicked[controller] = false;
|
||||
return true;
|
||||
if (b == L2) {
|
||||
if (L2Clicked[controller]) {
|
||||
L2Clicked[controller] = false;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
} else if (b == R2) {
|
||||
if (R2Clicked[controller]) {
|
||||
R2Clicked[controller] = false;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
else if(b == R2) {
|
||||
if(R2Clicked[controller]) {
|
||||
R2Clicked[controller] = false;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
uint16_t button = pgm_read_word(&XBOXBUTTONS[(uint8_t)b]);
|
||||
bool click = (ButtonClickState[controller] & button);
|
||||
ButtonClickState[controller] &= ~button; // clear "click" event
|
||||
return click;
|
||||
uint16_t button = pgm_read_word(&XBOXBUTTONS[(uint8_t)b]);
|
||||
bool click = (ButtonClickState[controller] & button);
|
||||
ButtonClickState[controller] &= ~button; // clear "click" event
|
||||
return click;
|
||||
}
|
||||
|
||||
int16_t XBOXRECV::getAnalogHat(uint8_t controller, AnalogHat a) {
|
||||
return hatValue[controller][a];
|
||||
return hatValue[controller][a];
|
||||
}
|
||||
|
||||
bool XBOXRECV::buttonChanged(uint8_t controller) {
|
||||
bool state = buttonStateChanged[controller];
|
||||
buttonStateChanged[controller] = false;
|
||||
return state;
|
||||
bool state = buttonStateChanged[controller];
|
||||
buttonStateChanged[controller] = false;
|
||||
return state;
|
||||
}
|
||||
|
||||
/*
|
||||
ControllerStatus Breakdown
|
||||
ControllerStatus[controller] & 0x0001 // 0
|
||||
|
@ -429,81 +445,90 @@ 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)
|
||||
batteryLevel = 100;
|
||||
return batteryLevel;
|
||||
uint8_t batteryLevel = ((controllerStatus[controller] & 0x00C0) >> 6) * 33;
|
||||
if (batteryLevel == 99)
|
||||
batteryLevel = 100;
|
||||
return batteryLevel;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
rcode = pUsb->outTransfer(bAddress, epInfo[ outputPipe ].epAddr, nbytes, data);
|
||||
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;
|
||||
}
|
||||
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;
|
||||
writeBuf[2] = 0x08;
|
||||
writeBuf[3] = value | 0x40;
|
||||
|
||||
XboxCommand(controller, writeBuf, 4);
|
||||
void XBOXRECV::setLedRaw(uint8_t controller, uint8_t value) {
|
||||
writeBuf[0] = 0x00;
|
||||
writeBuf[1] = 0x00;
|
||||
writeBuf[2] = 0x08;
|
||||
writeBuf[3] = value | 0x40;
|
||||
|
||||
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)
|
||||
return;
|
||||
// Get controller info
|
||||
writeBuf[0] = 0x08;
|
||||
writeBuf[1] = 0x00;
|
||||
writeBuf[2] = 0x0f;
|
||||
writeBuf[3] = 0xc0;
|
||||
for(uint8_t i=0; i<4; i++) {
|
||||
XboxCommand(i, writeBuf, 4);
|
||||
}
|
||||
// Get battery status
|
||||
writeBuf[0] = 0x00;
|
||||
writeBuf[1] = 0x00;
|
||||
writeBuf[2] = 0x00;
|
||||
writeBuf[3] = 0x40;
|
||||
for(uint8_t i=0; i<4; i++) {
|
||||
if(Xbox360Connected[i])
|
||||
XboxCommand(i, writeBuf, 4);
|
||||
}
|
||||
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++) {
|
||||
XboxCommand(i, writeBuf, 4);
|
||||
}
|
||||
// Get battery status
|
||||
writeBuf[0] = 0x00;
|
||||
writeBuf[1] = 0x00;
|
||||
writeBuf[2] = 0x00;
|
||||
writeBuf[3] = 0x40;
|
||||
for (uint8_t i = 0; i < 4; i++) {
|
||||
if (Xbox360Connected[i])
|
||||
XboxCommand(i, writeBuf, 4);
|
||||
}
|
||||
}
|
||||
|
||||
void XBOXRECV::setRumbleOn(uint8_t controller, uint8_t lValue, uint8_t rValue) {
|
||||
writeBuf[0] = 0x00;
|
||||
writeBuf[1] = 0x01;
|
||||
writeBuf[2] = 0x0f;
|
||||
writeBuf[3] = 0xc0;
|
||||
writeBuf[4] = 0x00;
|
||||
writeBuf[5] = lValue; // big weight
|
||||
writeBuf[6] = rValue; // small weight
|
||||
writeBuf[0] = 0x00;
|
||||
writeBuf[1] = 0x01;
|
||||
writeBuf[2] = 0x0f;
|
||||
writeBuf[3] = 0xc0;
|
||||
writeBuf[4] = 0x00;
|
||||
writeBuf[5] = lValue; // big weight
|
||||
writeBuf[6] = rValue; // small weight
|
||||
|
||||
XboxCommand(controller, writeBuf, 7);
|
||||
XboxCommand(controller, writeBuf, 7);
|
||||
}
|
312
XBOXRECV.h
312
XBOXRECV.h
|
@ -62,167 +62,183 @@
|
|||
*/
|
||||
class XBOXRECV : public USBDeviceConfig {
|
||||
public:
|
||||
/**
|
||||
* Constructor for the XBOXRECV class.
|
||||
* @param pUsb Pointer to USB class instance.
|
||||
*/
|
||||
XBOXRECV(USB *pUsb);
|
||||
/**
|
||||
* Constructor for the XBOXRECV class.
|
||||
* @param pUsb Pointer to USB class instance.
|
||||
*/
|
||||
XBOXRECV(USB *pUsb);
|
||||
|
||||
/** @name USBDeviceConfig implementation */
|
||||
/**
|
||||
* Initialize the Xbox wireless receiver.
|
||||
* @param parent Hub number.
|
||||
* @param port Port number on the hub.
|
||||
* @param lowspeed Speed of the device.
|
||||
* @return 0 on success.
|
||||
*/
|
||||
virtual uint8_t Init(uint8_t parent, uint8_t port, bool lowspeed);
|
||||
/**
|
||||
* Release the USB device.
|
||||
* @return 0 on success.
|
||||
*/
|
||||
virtual uint8_t Release();
|
||||
/**
|
||||
* Poll the USB Input endpoins and run the state machines.
|
||||
* @return 0 on success.
|
||||
*/
|
||||
virtual uint8_t Poll();
|
||||
/**
|
||||
* Get the device address.
|
||||
* @return The device address.
|
||||
*/
|
||||
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; };
|
||||
/**@}*/
|
||||
/** @name USBDeviceConfig implementation */
|
||||
/**
|
||||
* Initialize the Xbox wireless receiver.
|
||||
* @param parent Hub number.
|
||||
* @param port Port number on the hub.
|
||||
* @param lowspeed Speed of the device.
|
||||
* @return 0 on success.
|
||||
*/
|
||||
virtual uint8_t Init(uint8_t parent, uint8_t port, bool lowspeed);
|
||||
/**
|
||||
* Release the USB device.
|
||||
* @return 0 on success.
|
||||
*/
|
||||
virtual uint8_t Release();
|
||||
/**
|
||||
* Poll the USB Input endpoins and run the state machines.
|
||||
* @return 0 on success.
|
||||
*/
|
||||
virtual uint8_t Poll();
|
||||
|
||||
/** @name Xbox Controller functions */
|
||||
/**
|
||||
* getButtonPress(uint8_t controller, Button b) will return true as long as the button is held down.
|
||||
*
|
||||
* While getButtonClick(uint8_t controller, Button b) will only return it once.
|
||||
*
|
||||
* So you instance if you need to increase a variable once you would use getButtonClick(uint8_t controller, Button b),
|
||||
* but if you need to drive a robot forward you would use getButtonPress(uint8_t controller, Button b).
|
||||
* @param controller The controller to read from.
|
||||
* @param b ::Button to read.
|
||||
* @return getButtonClick(uint8_t controller, Button b) will return a bool, but getButtonPress(uint8_t controller, Button b)
|
||||
* will return a byte if reading ::L2 or ::R2.
|
||||
*/
|
||||
uint8_t getButtonPress(uint8_t controller, Button b);
|
||||
bool getButtonClick(uint8_t controller, Button b);
|
||||
/**@}*/
|
||||
/**
|
||||
* Get the device address.
|
||||
* @return The device address.
|
||||
*/
|
||||
virtual uint8_t GetAddress() {
|
||||
return bAddress;
|
||||
};
|
||||
|
||||
/** @name Xbox Controller functions */
|
||||
/**
|
||||
* Return the analog value from the joysticks on the controller.
|
||||
* @param controller The controller to read from.
|
||||
* @param a Either ::LeftHatX, ::LeftHatY, ::RightHatX or ::RightHatY.
|
||||
* @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); };
|
||||
/**
|
||||
* Turn rumble off the specific controller.
|
||||
* @param controller The controller to write to.
|
||||
*/
|
||||
void setRumbleOff(uint8_t controller) { setRumbleOn(controller,0,0); };
|
||||
/**
|
||||
* Turn rumble on.
|
||||
* @param controller The controller to write to.
|
||||
* @param lValue Left motor (big weight) inside the controller.
|
||||
* @param rValue Right motor (small weight) inside the controller.
|
||||
*/
|
||||
void setRumbleOn(uint8_t controller, uint8_t lValue, uint8_t rValue);
|
||||
/**
|
||||
* Set LED value. Without using the ::LED or ::LEDMode enum.
|
||||
* @param controller The controller to write to.
|
||||
* @param value See:
|
||||
* setLedOff(uint8_t controller), setLedOn(uint8_t controller, LED l),
|
||||
* 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); };
|
||||
/**
|
||||
* Turn on a LED by using the ::LED enum.
|
||||
* @param controller The controller to write to.
|
||||
* @param l ::LED1, ::LED2, ::LED3 and ::LED4 is supported by the Xbox controller.
|
||||
*/
|
||||
void setLedOn(uint8_t controller, LED l);
|
||||
/**
|
||||
* Turn on a LED by using the ::LED enum.
|
||||
* @param controller The controller to write to.
|
||||
* @param l ::ALL, ::LED1, ::LED2, ::LED3 and ::LED4 is supported by the Xbox controller.
|
||||
*/
|
||||
void setLedBlink(uint8_t controller, LED l);
|
||||
/**
|
||||
* Used to set special LED modes supported by the Xbox controller.
|
||||
* @param controller The controller to write to.
|
||||
* @param lm See ::LEDMode.
|
||||
*/
|
||||
void setLedMode(uint8_t controller, LEDMode lm);
|
||||
/**
|
||||
* Used to get the battery level from the controller.
|
||||
* @param controller The controller to read from.
|
||||
* @return Returns the battery level in percentage in 33% steps.
|
||||
*/
|
||||
uint8_t getBatteryLevel(uint8_t controller);
|
||||
/**
|
||||
* Used to check if a button has changed.
|
||||
* @param controller The controller to read from.
|
||||
* @return True if a button has changed.
|
||||
*/
|
||||
bool buttonChanged(uint8_t controller);
|
||||
/**@}*/
|
||||
/**
|
||||
* Used to check if the controller has been initialized.
|
||||
* @return True if it's ready.
|
||||
*/
|
||||
virtual bool isReady() {
|
||||
return bPollEnable;
|
||||
};
|
||||
/**@}*/
|
||||
|
||||
/** True if a wireless receiver is connected. */
|
||||
bool XboxReceiverConnected;
|
||||
/** Variable used to indicate if the XBOX 360 controller is successfully connected. */
|
||||
uint8_t Xbox360Connected[4];
|
||||
/** @name Xbox Controller functions */
|
||||
/**
|
||||
* getButtonPress(uint8_t controller, Button b) will return true as long as the button is held down.
|
||||
*
|
||||
* While getButtonClick(uint8_t controller, Button b) will only return it once.
|
||||
*
|
||||
* So you instance if you need to increase a variable once you would use getButtonClick(uint8_t controller, Button b),
|
||||
* but if you need to drive a robot forward you would use getButtonPress(uint8_t controller, Button b).
|
||||
* @param controller The controller to read from.
|
||||
* @param b ::Button to read.
|
||||
* @return getButtonClick(uint8_t controller, Button b) will return a bool, but getButtonPress(uint8_t controller, Button b)
|
||||
* will return a byte if reading ::L2 or ::R2.
|
||||
*/
|
||||
uint8_t getButtonPress(uint8_t controller, Button b);
|
||||
bool getButtonClick(uint8_t controller, Button b);
|
||||
/**@}*/
|
||||
|
||||
/** @name Xbox Controller functions */
|
||||
/**
|
||||
* Return the analog value from the joysticks on the controller.
|
||||
* @param controller The controller to read from.
|
||||
* @param a Either ::LeftHatX, ::LeftHatY, ::RightHatX or ::RightHatY.
|
||||
* @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);
|
||||
};
|
||||
|
||||
/**
|
||||
* Turn rumble off the specific controller.
|
||||
* @param controller The controller to write to.
|
||||
*/
|
||||
void setRumbleOff(uint8_t controller) {
|
||||
setRumbleOn(controller, 0, 0);
|
||||
};
|
||||
/**
|
||||
* Turn rumble on.
|
||||
* @param controller The controller to write to.
|
||||
* @param lValue Left motor (big weight) inside the controller.
|
||||
* @param rValue Right motor (small weight) inside the controller.
|
||||
*/
|
||||
void setRumbleOn(uint8_t controller, uint8_t lValue, uint8_t rValue);
|
||||
/**
|
||||
* Set LED value. Without using the ::LED or ::LEDMode enum.
|
||||
* @param controller The controller to write to.
|
||||
* @param value See:
|
||||
* setLedOff(uint8_t controller), setLedOn(uint8_t controller, LED l),
|
||||
* 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);
|
||||
};
|
||||
/**
|
||||
* Turn on a LED by using the ::LED enum.
|
||||
* @param controller The controller to write to.
|
||||
* @param l ::LED1, ::LED2, ::LED3 and ::LED4 is supported by the Xbox controller.
|
||||
*/
|
||||
void setLedOn(uint8_t controller, LED l);
|
||||
/**
|
||||
* Turn on a LED by using the ::LED enum.
|
||||
* @param controller The controller to write to.
|
||||
* @param l ::ALL, ::LED1, ::LED2, ::LED3 and ::LED4 is supported by the Xbox controller.
|
||||
*/
|
||||
void setLedBlink(uint8_t controller, LED l);
|
||||
/**
|
||||
* Used to set special LED modes supported by the Xbox controller.
|
||||
* @param controller The controller to write to.
|
||||
* @param lm See ::LEDMode.
|
||||
*/
|
||||
void setLedMode(uint8_t controller, LEDMode lm);
|
||||
/**
|
||||
* Used to get the battery level from the controller.
|
||||
* @param controller The controller to read from.
|
||||
* @return Returns the battery level in percentage in 33% steps.
|
||||
*/
|
||||
uint8_t getBatteryLevel(uint8_t controller);
|
||||
/**
|
||||
* Used to check if a button has changed.
|
||||
* @param controller The controller to read from.
|
||||
* @return True if a button has changed.
|
||||
*/
|
||||
bool buttonChanged(uint8_t controller);
|
||||
/**@}*/
|
||||
|
||||
/** True if a wireless receiver is connected. */
|
||||
bool XboxReceiverConnected;
|
||||
/** Variable used to indicate if the XBOX 360 controller is successfully connected. */
|
||||
uint8_t Xbox360Connected[4];
|
||||
|
||||
protected:
|
||||
/** Pointer to USB class instance. */
|
||||
USB *pUsb;
|
||||
/** Device address. */
|
||||
uint8_t bAddress;
|
||||
/** Endpoint info structure. */
|
||||
EpInfo epInfo[XBOX_MAX_ENDPOINTS];
|
||||
/** Pointer to USB class instance. */
|
||||
USB *pUsb;
|
||||
/** Device address. */
|
||||
uint8_t bAddress;
|
||||
/** Endpoint info structure. */
|
||||
EpInfo epInfo[XBOX_MAX_ENDPOINTS];
|
||||
|
||||
private:
|
||||
bool bPollEnable;
|
||||
bool bPollEnable;
|
||||
|
||||
/* Variables to store the buttons */
|
||||
uint32_t ButtonState[4];
|
||||
uint32_t OldButtonState[4];
|
||||
uint16_t ButtonClickState[4];
|
||||
int16_t hatValue[4][4];
|
||||
uint16_t controllerStatus[4];
|
||||
bool buttonStateChanged[4]; // True if a button has changed
|
||||
/* Variables to store the buttons */
|
||||
uint32_t ButtonState[4];
|
||||
uint32_t OldButtonState[4];
|
||||
uint16_t ButtonClickState[4];
|
||||
int16_t hatValue[4][4];
|
||||
uint16_t controllerStatus[4];
|
||||
bool buttonStateChanged[4]; // True if a button has changed
|
||||
|
||||
bool L2Clicked[4]; // These buttons are analog, so we use we use these bools to check if they where clicked or not
|
||||
bool R2Clicked[4];
|
||||
bool L2Clicked[4]; // These buttons are analog, so we use we use these bools to check if they where clicked or not
|
||||
bool R2Clicked[4];
|
||||
|
||||
unsigned long timer; // Timing for checkStatus() signals
|
||||
unsigned long timer; // Timing for checkStatus() signals
|
||||
|
||||
uint8_t readBuf[EP_MAXPKTSIZE]; // General purpose buffer for input data
|
||||
uint8_t writeBuf[EP_MAXPKTSIZE]; // General purpose buffer for output data
|
||||
uint8_t readBuf[EP_MAXPKTSIZE]; // General purpose buffer for input data
|
||||
uint8_t writeBuf[EP_MAXPKTSIZE]; // General purpose buffer for output data
|
||||
|
||||
void readReport(uint8_t controller); // read incoming data
|
||||
void printReport(uint8_t controller, uint8_t nBytes); // print incoming date - Uncomment for debugging
|
||||
void readReport(uint8_t controller); // read incoming data
|
||||
void printReport(uint8_t controller, uint8_t nBytes); // print incoming date - Uncomment for debugging
|
||||
|
||||
/* Private commands */
|
||||
void XboxCommand(uint8_t controller, uint8_t* data, uint16_t nbytes);
|
||||
void checkStatus();
|
||||
/* Private commands */
|
||||
void XboxCommand(uint8_t controller, uint8_t* data, uint16_t nbytes);
|
||||
void checkStatus();
|
||||
};
|
||||
#endif
|
442
XBOXUSB.cpp
442
XBOXUSB.cpp
|
@ -20,323 +20,329 @@
|
|||
//#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++) {
|
||||
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;
|
||||
}
|
||||
for (uint8_t i = 0; i < XBOX_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;
|
||||
}
|
||||
|
||||
if (pUsb) // register in USB subsystem
|
||||
pUsb->RegisterDeviceClass(this); //set devConfig[] entry
|
||||
if (pUsb) // register in USB subsystem
|
||||
pUsb->RegisterDeviceClass(this); //set devConfig[] entry
|
||||
}
|
||||
|
||||
uint8_t XBOXUSB::Init(uint8_t parent, uint8_t port, bool lowspeed) {
|
||||
uint8_t buf[sizeof(USB_DEVICE_DESCRIPTOR)];
|
||||
uint8_t rcode;
|
||||
UsbDevice *p = NULL;
|
||||
EpInfo *oldep_ptr = NULL;
|
||||
uint16_t PID;
|
||||
uint16_t VID;
|
||||
uint8_t buf[sizeof (USB_DEVICE_DESCRIPTOR)];
|
||||
uint8_t rcode;
|
||||
UsbDevice *p = NULL;
|
||||
EpInfo *oldep_ptr = NULL;
|
||||
uint16_t PID;
|
||||
uint16_t VID;
|
||||
|
||||
// get memory address of USB device address pool
|
||||
AddressPool &addrPool = pUsb->GetAddressPool();
|
||||
// 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) {
|
||||
// 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;
|
||||
}
|
||||
return USB_ERROR_CLASS_INSTANCE_ALREADY_IN_USE;
|
||||
}
|
||||
|
||||
// Get pointer to pseudo device with address 0 assigned
|
||||
p = addrPool.GetUsbDevicePtr(0);
|
||||
// Get pointer to pseudo device with address 0 assigned
|
||||
p = addrPool.GetUsbDevicePtr(0);
|
||||
|
||||
if (!p) {
|
||||
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;
|
||||
}
|
||||
return USB_ERROR_ADDRESS_NOT_FOUND_IN_POOL;
|
||||
}
|
||||
|
||||
if (!p->epinfo) {
|
||||
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;
|
||||
}
|
||||
return USB_ERROR_EPINFO_IS_NULL;
|
||||
}
|
||||
|
||||
// Save old pointer to EP_RECORD of address 0
|
||||
oldep_ptr = p->epinfo;
|
||||
// Save old pointer to EP_RECORD of address 0
|
||||
oldep_ptr = p->epinfo;
|
||||
|
||||
// Temporary assign new pointer to epInfo to p->epinfo in order to avoid toggle inconsistence
|
||||
p->epinfo = epInfo;
|
||||
// Temporary assign new pointer to epInfo to p->epinfo in order to avoid toggle inconsistence
|
||||
p->epinfo = epInfo;
|
||||
|
||||
p->lowspeed = 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
|
||||
// Restore p->epinfo
|
||||
p->epinfo = oldep_ptr;
|
||||
// Get device descriptor
|
||||
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)
|
||||
goto FailGetDevDescr;
|
||||
if (rcode)
|
||||
goto FailGetDevDescr;
|
||||
|
||||
VID = ((USB_DEVICE_DESCRIPTOR*)buf)->idVendor;
|
||||
PID = ((USB_DEVICE_DESCRIPTOR*)buf)->idProduct;
|
||||
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
|
||||
goto FailUnknownDevice;
|
||||
if(PID == XBOX_WIRELESS_PID) {
|
||||
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) {
|
||||
#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) {
|
||||
goto FailUnknownDevice;
|
||||
} 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;
|
||||
}
|
||||
goto FailUnknownDevice;
|
||||
}
|
||||
|
||||
// Allocate new address according to device class
|
||||
bAddress = addrPool.AllocAddress(parent, false, port);
|
||||
// Allocate new address according to device class
|
||||
bAddress = addrPool.AllocAddress(parent, false, port);
|
||||
|
||||
if (!bAddress)
|
||||
return USB_ERROR_OUT_OF_ADDRESS_SPACE_IN_POOL;
|
||||
if (!bAddress)
|
||||
return USB_ERROR_OUT_OF_ADDRESS_SPACE_IN_POOL;
|
||||
|
||||
// Extract Max Packet Size from device descriptor
|
||||
epInfo[0].maxPktSize = (uint8_t)((USB_DEVICE_DESCRIPTOR*)buf)->bMaxPacketSize0;
|
||||
// Extract Max Packet Size from device descriptor
|
||||
epInfo[0].maxPktSize = (uint8_t)((USB_DEVICE_DESCRIPTOR*)buf)->bMaxPacketSize0;
|
||||
|
||||
// Assign new address to the device
|
||||
rcode = pUsb->setAddr( 0, 0, bAddress );
|
||||
if (rcode) {
|
||||
// Assign new address to the device
|
||||
rcode = pUsb->setAddr(0, 0, bAddress);
|
||||
if (rcode) {
|
||||
p->lowspeed = false;
|
||||
addrPool.FreeAddress(bAddress);
|
||||
bAddress = 0;
|
||||
#ifdef DEBUG
|
||||
Notify(PSTR("\r\nsetAddr: "), 0x80);
|
||||
#endif
|
||||
PrintHex<uint8_t > (rcode, 0x80);
|
||||
return rcode;
|
||||
}
|
||||
#ifdef EXTRADEBUG
|
||||
Notify(PSTR("\r\nAddr: "), 0x80);
|
||||
PrintHex<uint8_t > (bAddress, 0x80);
|
||||
#endif
|
||||
p->lowspeed = false;
|
||||
addrPool.FreeAddress(bAddress);
|
||||
bAddress = 0;
|
||||
#ifdef DEBUG
|
||||
Notify(PSTR("\r\nsetAddr: "));
|
||||
#endif
|
||||
PrintHex<uint8_t>(rcode);
|
||||
return rcode;
|
||||
}
|
||||
#ifdef EXTRADEBUG
|
||||
Notify(PSTR("\r\nAddr: "));
|
||||
PrintHex<uint8_t>(bAddress);
|
||||
#endif
|
||||
p->lowspeed = false;
|
||||
|
||||
//get pointer to assigned address record
|
||||
p = addrPool.GetUsbDevicePtr(bAddress);
|
||||
if (!p)
|
||||
return USB_ERROR_ADDRESS_NOT_FOUND_IN_POOL;
|
||||
//get pointer to assigned address record
|
||||
p = addrPool.GetUsbDevicePtr(bAddress);
|
||||
if (!p)
|
||||
return USB_ERROR_ADDRESS_NOT_FOUND_IN_POOL;
|
||||
|
||||
p->lowspeed = lowspeed;
|
||||
p->lowspeed = lowspeed;
|
||||
|
||||
// Assign epInfo to epinfo pointer - only EP0 is known
|
||||
rcode = pUsb->setEpInfoEntry(bAddress, 1, epInfo);
|
||||
if (rcode)
|
||||
goto FailSetDevTblEntry;
|
||||
// Assign epInfo to epinfo pointer - only EP0 is known
|
||||
rcode = pUsb->setEpInfoEntry(bAddress, 1, epInfo);
|
||||
if (rcode)
|
||||
goto FailSetDevTblEntry;
|
||||
|
||||
/* The application will work in reduced host mode, so we can save program and data
|
||||
memory space. After verifying the VID we will use known values for the
|
||||
configuration values for device, interface, endpoints and HID for the XBOX360 Controllers */
|
||||
/* The application will work in reduced host mode, so we can save program and data
|
||||
memory space. After verifying the VID we will use known values for the
|
||||
configuration values for device, interface, endpoints and HID for the XBOX360 Controllers */
|
||||
|
||||
/* Initialize data structures for endpoints of device */
|
||||
epInfo[ XBOX_INPUT_PIPE ].epAddr = 0x01; // XBOX 360 report endpoint
|
||||
epInfo[ XBOX_INPUT_PIPE ].epAttribs = EP_INTERRUPT;
|
||||
epInfo[ XBOX_INPUT_PIPE ].bmNakPower = USB_NAK_NOWAIT; // Only poll once for interrupt endpoints
|
||||
epInfo[ XBOX_INPUT_PIPE ].maxPktSize = EP_MAXPKTSIZE;
|
||||
epInfo[ XBOX_INPUT_PIPE ].bmSndToggle = bmSNDTOG0;
|
||||
epInfo[ XBOX_INPUT_PIPE ].bmRcvToggle = bmRCVTOG0;
|
||||
epInfo[ XBOX_OUTPUT_PIPE ].epAddr = 0x02; // XBOX 360 output endpoint
|
||||
epInfo[ XBOX_OUTPUT_PIPE ].epAttribs = EP_INTERRUPT;
|
||||
epInfo[ XBOX_OUTPUT_PIPE ].bmNakPower = USB_NAK_NOWAIT; // Only poll once for interrupt endpoints
|
||||
epInfo[ XBOX_OUTPUT_PIPE ].maxPktSize = EP_MAXPKTSIZE;
|
||||
epInfo[ XBOX_OUTPUT_PIPE ].bmSndToggle = bmSNDTOG0;
|
||||
epInfo[ XBOX_OUTPUT_PIPE ].bmRcvToggle = bmRCVTOG0;
|
||||
/* Initialize data structures for endpoints of device */
|
||||
epInfo[ XBOX_INPUT_PIPE ].epAddr = 0x01; // XBOX 360 report endpoint
|
||||
epInfo[ XBOX_INPUT_PIPE ].epAttribs = EP_INTERRUPT;
|
||||
epInfo[ XBOX_INPUT_PIPE ].bmNakPower = USB_NAK_NOWAIT; // Only poll once for interrupt endpoints
|
||||
epInfo[ XBOX_INPUT_PIPE ].maxPktSize = EP_MAXPKTSIZE;
|
||||
epInfo[ XBOX_INPUT_PIPE ].bmSndToggle = bmSNDTOG0;
|
||||
epInfo[ XBOX_INPUT_PIPE ].bmRcvToggle = bmRCVTOG0;
|
||||
epInfo[ XBOX_OUTPUT_PIPE ].epAddr = 0x02; // XBOX 360 output endpoint
|
||||
epInfo[ XBOX_OUTPUT_PIPE ].epAttribs = EP_INTERRUPT;
|
||||
epInfo[ XBOX_OUTPUT_PIPE ].bmNakPower = USB_NAK_NOWAIT; // Only poll once for interrupt endpoints
|
||||
epInfo[ XBOX_OUTPUT_PIPE ].maxPktSize = EP_MAXPKTSIZE;
|
||||
epInfo[ XBOX_OUTPUT_PIPE ].bmSndToggle = bmSNDTOG0;
|
||||
epInfo[ XBOX_OUTPUT_PIPE ].bmRcvToggle = bmRCVTOG0;
|
||||
|
||||
rcode = pUsb->setEpInfoEntry(bAddress, 3, epInfo);
|
||||
if( rcode )
|
||||
goto FailSetDevTblEntry;
|
||||
rcode = pUsb->setEpInfoEntry(bAddress, 3, epInfo);
|
||||
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 )
|
||||
goto FailSetConf;
|
||||
rcode = pUsb->setConf(bAddress, epInfo[ XBOX_CONTROL_PIPE ].epAddr, 1);
|
||||
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;
|
||||
bPollEnable = true;
|
||||
return 0; // successful configuration
|
||||
setLedOn(LED1);
|
||||
Xbox360Connected = true;
|
||||
bPollEnable = true;
|
||||
return 0; // successful configuration
|
||||
|
||||
/* diagnostic messages */
|
||||
/* diagnostic messages */
|
||||
FailGetDevDescr:
|
||||
#ifdef DEBUG
|
||||
Notify(PSTR("\r\ngetDevDescr:"));
|
||||
Notify(PSTR("\r\ngetDevDescr:"), 0x80);
|
||||
#endif
|
||||
goto Fail;
|
||||
goto Fail;
|
||||
FailSetDevTblEntry:
|
||||
#ifdef DEBUG
|
||||
Notify(PSTR("\r\nsetDevTblEn:"));
|
||||
Notify(PSTR("\r\nsetDevTblEn:"), 0x80);
|
||||
#endif
|
||||
goto Fail;
|
||||
goto Fail;
|
||||
FailSetConf:
|
||||
#ifdef DEBUG
|
||||
Notify(PSTR("\r\nsetConf:"));
|
||||
Notify(PSTR("\r\nsetConf:"), 0x80);
|
||||
#endif
|
||||
goto Fail;
|
||||
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;
|
||||
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;
|
||||
Release();
|
||||
return rcode;
|
||||
}
|
||||
|
||||
/* Performs a cleanup after failed Init() attempt */
|
||||
uint8_t XBOXUSB::Release() {
|
||||
Xbox360Connected = false;
|
||||
pUsb->GetAddressPool().FreeAddress(bAddress);
|
||||
bAddress = 0;
|
||||
bPollEnable = false;
|
||||
return 0;
|
||||
Xbox360Connected = false;
|
||||
pUsb->GetAddressPool().FreeAddress(bAddress);
|
||||
bAddress = 0;
|
||||
bPollEnable = false;
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint8_t XBOXUSB::Poll() {
|
||||
if (!bPollEnable)
|
||||
return 0;
|
||||
uint16_t BUFFER_SIZE = EP_MAXPKTSIZE;
|
||||
pUsb->inTransfer(bAddress, epInfo[ XBOX_INPUT_PIPE ].epAddr, &BUFFER_SIZE, readBuf); // input on endpoint 1
|
||||
readReport();
|
||||
if (!bPollEnable)
|
||||
return 0;
|
||||
uint16_t BUFFER_SIZE = EP_MAXPKTSIZE;
|
||||
pUsb->inTransfer(bAddress, epInfo[ XBOX_INPUT_PIPE ].epAddr, &BUFFER_SIZE, readBuf); // input on endpoint 1
|
||||
readReport();
|
||||
#ifdef PRINTREPORT
|
||||
printReport(); // Uncomment "#define PRINTREPORT" to print the report send by the Xbox 360 Controller
|
||||
printReport(); // Uncomment "#define PRINTREPORT" to print the report send by the Xbox 360 Controller
|
||||
#endif
|
||||
return 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
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
|
||||
return;
|
||||
}
|
||||
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
|
||||
return;
|
||||
}
|
||||
|
||||
ButtonState = (uint32_t)(readBuf[5] | ((uint16_t)readBuf[4] << 8) | ((uint32_t)readBuf[3] << 16) | ((uint32_t)readBuf[2] << 24));
|
||||
ButtonState = (uint32_t)(readBuf[5] | ((uint16_t)readBuf[4] << 8) | ((uint32_t)readBuf[3] << 16) | ((uint32_t)readBuf[2] << 24));
|
||||
|
||||
hatValue[LeftHatX] = (int16_t)(((uint16_t)readBuf[7] << 8) | readBuf[6]);
|
||||
hatValue[LeftHatY] = (int16_t)(((uint16_t)readBuf[9] << 8) | readBuf[8]);
|
||||
hatValue[RightHatX] = (int16_t)(((uint16_t)readBuf[11] << 8) | readBuf[10]);
|
||||
hatValue[RightHatY] = (int16_t)(((uint16_t)readBuf[13] << 8) | readBuf[12]);
|
||||
hatValue[LeftHatX] = (int16_t)(((uint16_t)readBuf[7] << 8) | readBuf[6]);
|
||||
hatValue[LeftHatY] = (int16_t)(((uint16_t)readBuf[9] << 8) | readBuf[8]);
|
||||
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) {
|
||||
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
|
||||
R2Clicked = true;
|
||||
if((uint8_t)(OldButtonState >> 8) == 0 && (uint8_t)(ButtonState >> 8) != 0)
|
||||
L2Clicked = true;
|
||||
OldButtonState = ButtonState;
|
||||
}
|
||||
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
|
||||
R2Clicked = true;
|
||||
if ((uint8_t)(OldButtonState >> 8) == 0 && (uint8_t)(ButtonState >> 8) != 0)
|
||||
L2Clicked = true;
|
||||
OldButtonState = ButtonState;
|
||||
}
|
||||
}
|
||||
|
||||
void XBOXUSB::printReport() { //Uncomment "#define PRINTREPORT" to print the report send by the Xbox 360 Controller
|
||||
#ifdef PRINTREPORT
|
||||
if (readBuf == NULL)
|
||||
return;
|
||||
for(uint8_t i = 0; i < XBOX_REPORT_BUFFER_SIZE;i++) {
|
||||
PrintHex<uint8_t>(readBuf[i]);
|
||||
Serial.print(" ");
|
||||
}
|
||||
Serial.println();
|
||||
if (readBuf == NULL)
|
||||
return;
|
||||
for (uint8_t i = 0; i < XBOX_REPORT_BUFFER_SIZE; i++) {
|
||||
PrintHex<uint8_t > (readBuf[i], 0x80);
|
||||
Serial.print(" ");
|
||||
}
|
||||
Serial.println();
|
||||
#endif
|
||||
}
|
||||
|
||||
uint8_t XBOXUSB::getButtonPress(Button b) {
|
||||
if(b == L2) // These are analog buttons
|
||||
return (uint8_t)(ButtonState >> 8);
|
||||
else if(b == R2)
|
||||
return (uint8_t)ButtonState;
|
||||
return (ButtonState & ((uint32_t)pgm_read_word(&XBOXBUTTONS[(uint8_t)b]) << 16));
|
||||
if (b == L2) // These are analog buttons
|
||||
return (uint8_t)(ButtonState >> 8);
|
||||
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) {
|
||||
L2Clicked = false;
|
||||
return true;
|
||||
if (b == L2) {
|
||||
if (L2Clicked) {
|
||||
L2Clicked = false;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
} else if (b == R2) {
|
||||
if (R2Clicked) {
|
||||
R2Clicked = false;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
else if(b == R2) {
|
||||
if(R2Clicked) {
|
||||
R2Clicked = false;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
uint16_t button = pgm_read_word(&XBOXBUTTONS[(uint8_t)b]);
|
||||
bool click = (ButtonClickState & button);
|
||||
ButtonClickState &= ~button; // clear "click" event
|
||||
return click;
|
||||
uint16_t button = pgm_read_word(&XBOXBUTTONS[(uint8_t)b]);
|
||||
bool click = (ButtonClickState & button);
|
||||
ButtonClickState &= ~button; // clear "click" event
|
||||
return click;
|
||||
}
|
||||
|
||||
int16_t XBOXUSB::getAnalogHat(AnalogHat a) {
|
||||
return hatValue[a];
|
||||
return hatValue[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);
|
||||
//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);
|
||||
}
|
||||
|
||||
void XBOXUSB::setLedRaw(uint8_t value) {
|
||||
writeBuf[0] = 0x01;
|
||||
writeBuf[1] = 0x03;
|
||||
writeBuf[2] = value;
|
||||
writeBuf[0] = 0x01;
|
||||
writeBuf[1] = 0x03;
|
||||
writeBuf[2] = value;
|
||||
|
||||
XboxCommand(writeBuf, 3);
|
||||
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;
|
||||
writeBuf[2] = 0x00;
|
||||
writeBuf[3] = lValue; // big weight
|
||||
writeBuf[4] = rValue; // small weight
|
||||
writeBuf[5] = 0x00;
|
||||
writeBuf[6] = 0x00;
|
||||
writeBuf[7] = 0x00;
|
||||
|
||||
XboxCommand(writeBuf, 8);
|
||||
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;
|
||||
writeBuf[2] = 0x00;
|
||||
writeBuf[3] = lValue; // big weight
|
||||
writeBuf[4] = rValue; // small weight
|
||||
writeBuf[5] = 0x00;
|
||||
writeBuf[6] = 0x00;
|
||||
writeBuf[7] = 0x00;
|
||||
|
||||
XboxCommand(writeBuf, 8);
|
||||
}
|
247
XBOXUSB.h
247
XBOXUSB.h
|
@ -58,135 +58,150 @@
|
|||
/** This class implements support for a Xbox wired controller via USB. */
|
||||
class XBOXUSB : public USBDeviceConfig {
|
||||
public:
|
||||
/**
|
||||
* Constructor for the XBOXUSB class.
|
||||
* @param pUsb Pointer to USB class instance.
|
||||
*/
|
||||
XBOXUSB(USB *pUsb);
|
||||
/**
|
||||
* Constructor for the XBOXUSB class.
|
||||
* @param pUsb Pointer to USB class instance.
|
||||
*/
|
||||
XBOXUSB(USB *pUsb);
|
||||
|
||||
/** @name USBDeviceConfig implementation */
|
||||
/**
|
||||
* Initialize the Xbox Controller.
|
||||
* @param parent Hub number.
|
||||
* @param port Port number on the hub.
|
||||
* @param lowspeed Speed of the device.
|
||||
* @return 0 on success.
|
||||
*/
|
||||
virtual uint8_t Init(uint8_t parent, uint8_t port, bool lowspeed);
|
||||
/**
|
||||
* Release the USB device.
|
||||
* @return 0 on success.
|
||||
*/
|
||||
virtual uint8_t Release();
|
||||
/**
|
||||
* Poll the USB Input endpoins and run the state machines.
|
||||
* @return 0 on success.
|
||||
*/
|
||||
virtual uint8_t Poll();
|
||||
/**
|
||||
* Get the device address.
|
||||
* @return The device address.
|
||||
*/
|
||||
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; };
|
||||
/**@}*/
|
||||
/** @name USBDeviceConfig implementation */
|
||||
/**
|
||||
* Initialize the Xbox Controller.
|
||||
* @param parent Hub number.
|
||||
* @param port Port number on the hub.
|
||||
* @param lowspeed Speed of the device.
|
||||
* @return 0 on success.
|
||||
*/
|
||||
virtual uint8_t Init(uint8_t parent, uint8_t port, bool lowspeed);
|
||||
/**
|
||||
* Release the USB device.
|
||||
* @return 0 on success.
|
||||
*/
|
||||
virtual uint8_t Release();
|
||||
/**
|
||||
* Poll the USB Input endpoins and run the state machines.
|
||||
* @return 0 on success.
|
||||
*/
|
||||
virtual uint8_t Poll();
|
||||
|
||||
/** @name Xbox Controller functions */
|
||||
/**
|
||||
* getButtonPress(Button b) will return true as long as the button is held down.
|
||||
*
|
||||
* While getButtonClick(Button b) will only return it once.
|
||||
*
|
||||
* So you instance if you need to increase a variable once you would use getButtonClick(Button b),
|
||||
* but if you need to drive a robot forward you would use getButtonPress(Button b).
|
||||
* @param b ::Button to read.
|
||||
* @return getButtonClick(Button b) will return a bool, but getButtonPress(Button b)
|
||||
* will return a byte if reading ::L2 or ::R2.
|
||||
*/
|
||||
uint8_t getButtonPress(Button b);
|
||||
bool getButtonClick(Button b);
|
||||
/**@}*/
|
||||
/**
|
||||
* Get the device address.
|
||||
* @return The device address.
|
||||
*/
|
||||
virtual uint8_t GetAddress() {
|
||||
return bAddress;
|
||||
};
|
||||
|
||||
/** @name Xbox Controller functions */
|
||||
/**
|
||||
* Return the analog value from the joysticks on the controller.
|
||||
* @param a Either ::LeftHatX, ::LeftHatY, ::RightHatX or ::RightHatY.
|
||||
* @return Returns a signed 16-bit integer.
|
||||
*/
|
||||
int16_t getAnalogHat(AnalogHat a);
|
||||
/**
|
||||
* Used to check if the controller has been initialized.
|
||||
* @return True if it's ready.
|
||||
*/
|
||||
virtual bool isReady() {
|
||||
return bPollEnable;
|
||||
};
|
||||
/**@}*/
|
||||
|
||||
/** Turn rumble off and all the LEDs on the controller. */
|
||||
void setAllOff() { setRumbleOn(0,0); setLedRaw(0); };
|
||||
/** Turn rumble off the controller. */
|
||||
void setRumbleOff() { setRumbleOn(0,0); };
|
||||
/**
|
||||
* Turn rumble on.
|
||||
* @param lValue Left motor (big weight) inside the controller.
|
||||
* @param rValue Right motor (small weight) inside the controller.
|
||||
*/
|
||||
void setRumbleOn(uint8_t lValue, uint8_t rValue);
|
||||
/**
|
||||
* Set LED value. Without using the ::LED or ::LEDMode enum.
|
||||
* @param value See:
|
||||
* setLedOff(), setLedOn(LED l),
|
||||
* setLedBlink(LED l), and setLedMode(LEDMode lm).
|
||||
*/
|
||||
void setLedRaw(uint8_t value);
|
||||
/** Turn all LEDs off the controller. */
|
||||
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.
|
||||
*/
|
||||
void setLedOn(LED l);
|
||||
/**
|
||||
* Turn on a LED by using the ::LED enum.
|
||||
* @param l ::ALL, ::LED1, ::LED2, ::LED3 and ::LED4 is supported by the Xbox controller.
|
||||
*/
|
||||
void setLedBlink(LED l);
|
||||
/**
|
||||
* Used to set special LED modes supported by the Xbox controller.
|
||||
* @param controller The controller to write to.
|
||||
* @param lm See ::LEDMode.
|
||||
*/
|
||||
void setLedMode(LEDMode lm);
|
||||
/**@}*/
|
||||
/** @name Xbox Controller functions */
|
||||
/**
|
||||
* getButtonPress(Button b) will return true as long as the button is held down.
|
||||
*
|
||||
* While getButtonClick(Button b) will only return it once.
|
||||
*
|
||||
* So you instance if you need to increase a variable once you would use getButtonClick(Button b),
|
||||
* but if you need to drive a robot forward you would use getButtonPress(Button b).
|
||||
* @param b ::Button to read.
|
||||
* @return getButtonClick(Button b) will return a bool, but getButtonPress(Button b)
|
||||
* will return a byte if reading ::L2 or ::R2.
|
||||
*/
|
||||
uint8_t getButtonPress(Button b);
|
||||
bool getButtonClick(Button b);
|
||||
/**@}*/
|
||||
|
||||
/** True if a Xbox 360 controller is connected. */
|
||||
bool Xbox360Connected;
|
||||
/** @name Xbox Controller functions */
|
||||
/**
|
||||
* Return the analog value from the joysticks on the controller.
|
||||
* @param a Either ::LeftHatX, ::LeftHatY, ::RightHatX or ::RightHatY.
|
||||
* @return Returns a signed 16-bit integer.
|
||||
*/
|
||||
int16_t getAnalogHat(AnalogHat a);
|
||||
|
||||
/** Turn rumble off and all the LEDs on the controller. */
|
||||
void setAllOff() {
|
||||
setRumbleOn(0, 0);
|
||||
setLedRaw(0);
|
||||
};
|
||||
|
||||
/** Turn rumble off the controller. */
|
||||
void setRumbleOff() {
|
||||
setRumbleOn(0, 0);
|
||||
};
|
||||
/**
|
||||
* Turn rumble on.
|
||||
* @param lValue Left motor (big weight) inside the controller.
|
||||
* @param rValue Right motor (small weight) inside the controller.
|
||||
*/
|
||||
void setRumbleOn(uint8_t lValue, uint8_t rValue);
|
||||
/**
|
||||
* Set LED value. Without using the ::LED or ::LEDMode enum.
|
||||
* @param value See:
|
||||
* setLedOff(), setLedOn(LED l),
|
||||
* setLedBlink(LED l), and setLedMode(LEDMode lm).
|
||||
*/
|
||||
void setLedRaw(uint8_t value);
|
||||
|
||||
/** Turn all LEDs off the controller. */
|
||||
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.
|
||||
*/
|
||||
void setLedOn(LED l);
|
||||
/**
|
||||
* Turn on a LED by using the ::LED enum.
|
||||
* @param l ::ALL, ::LED1, ::LED2, ::LED3 and ::LED4 is supported by the Xbox controller.
|
||||
*/
|
||||
void setLedBlink(LED l);
|
||||
/**
|
||||
* Used to set special LED modes supported by the Xbox controller.
|
||||
* @param controller The controller to write to.
|
||||
* @param lm See ::LEDMode.
|
||||
*/
|
||||
void setLedMode(LEDMode lm);
|
||||
/**@}*/
|
||||
|
||||
/** True if a Xbox 360 controller is connected. */
|
||||
bool Xbox360Connected;
|
||||
|
||||
protected:
|
||||
/** Pointer to USB class instance. */
|
||||
USB *pUsb;
|
||||
/** Device address. */
|
||||
uint8_t bAddress;
|
||||
/** Endpoint info structure. */
|
||||
EpInfo epInfo[XBOX_MAX_ENDPOINTS];
|
||||
/** Pointer to USB class instance. */
|
||||
USB *pUsb;
|
||||
/** Device address. */
|
||||
uint8_t bAddress;
|
||||
/** Endpoint info structure. */
|
||||
EpInfo epInfo[XBOX_MAX_ENDPOINTS];
|
||||
|
||||
private:
|
||||
bool bPollEnable;
|
||||
bool bPollEnable;
|
||||
|
||||
/* Variables to store the buttons */
|
||||
uint32_t ButtonState;
|
||||
uint32_t OldButtonState;
|
||||
uint16_t ButtonClickState;
|
||||
int16_t hatValue[4];
|
||||
uint16_t controllerStatus;
|
||||
/* Variables to store the buttons */
|
||||
uint32_t ButtonState;
|
||||
uint32_t OldButtonState;
|
||||
uint16_t ButtonClickState;
|
||||
int16_t hatValue[4];
|
||||
uint16_t controllerStatus;
|
||||
|
||||
bool L2Clicked; // These buttons are analog, so we use we use these bools to check if they where clicked or not
|
||||
bool R2Clicked;
|
||||
bool L2Clicked; // These buttons are analog, so we use we use these bools to check if they where clicked or not
|
||||
bool R2Clicked;
|
||||
|
||||
uint8_t readBuf[EP_MAXPKTSIZE]; // General purpose buffer for input data
|
||||
uint8_t writeBuf[EP_MAXPKTSIZE]; // General purpose buffer for output data
|
||||
uint8_t readBuf[EP_MAXPKTSIZE]; // General purpose buffer for input data
|
||||
uint8_t writeBuf[EP_MAXPKTSIZE]; // General purpose buffer for output data
|
||||
|
||||
void readReport(); // read incoming data
|
||||
void printReport(); // print incoming date - Uncomment for debugging
|
||||
void readReport(); // read incoming data
|
||||
void printReport(); // print incoming date - Uncomment for debugging
|
||||
|
||||
/* Private commands */
|
||||
void XboxCommand(uint8_t* data, uint16_t nbytes);
|
||||
/* Private commands */
|
||||
void XboxCommand(uint8_t* data, uint16_t nbytes);
|
||||
};
|
||||
#endif
|
||||
|
|
394
address.h
394
address.h
|
@ -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
|
||||
{
|
||||
uint8_t epAddr; // Endpoint address
|
||||
uint8_t maxPktSize; // Maximum packet size
|
||||
struct EpInfo {
|
||||
uint8_t epAddr; // Endpoint address
|
||||
uint8_t maxPktSize; // Maximum packet size
|
||||
|
||||
union
|
||||
{
|
||||
uint8_t epAttribs;
|
||||
union {
|
||||
uint8_t epAttribs;
|
||||
|
||||
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
|
||||
};
|
||||
};
|
||||
};
|
||||
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,40 +53,38 @@ struct EpInfo
|
|||
// P - parent hub address
|
||||
// A - device address / port number in case of hub
|
||||
//
|
||||
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
|
||||
};
|
||||
uint8_t devAddress;
|
||||
};
|
||||
};
|
||||
|
||||
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
|
||||
{
|
||||
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
|
||||
};
|
||||
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
|
||||
} __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;
|
||||
virtual void FreeAddress(uint8_t addr) = 0;
|
||||
virtual UsbDevice* GetUsbDevicePtr(uint8_t addr) = 0;
|
||||
virtual uint8_t AllocAddress(uint8_t parent, bool is_hub = false, uint8_t port = 0) = 0;
|
||||
virtual void FreeAddress(uint8_t addr) = 0;
|
||||
};
|
||||
|
||||
typedef void (*UsbDeviceHandleFunc)(UsbDevice *pdev);
|
||||
|
@ -98,191 +93,180 @@ typedef void (*UsbDeviceHandleFunc)(UsbDevice *pdev);
|
|||
#define ADDR_ERROR_INVALID_ADDRESS 0xFF
|
||||
|
||||
template <const uint8_t MAX_DEVICES_ALLOWED>
|
||||
class AddressPoolImpl : public AddressPool
|
||||
{
|
||||
EpInfo dev0ep; //Endpoint data structure used during enumeration for uninitialized device
|
||||
class AddressPoolImpl : public AddressPool {
|
||||
EpInfo dev0ep; //Endpoint data structure used during enumeration for uninitialized device
|
||||
|
||||
uint8_t hubCounter; // hub counter is kept
|
||||
// in order to avoid hub address duplication
|
||||
uint8_t hubCounter; // hub counter is kept
|
||||
// in order to avoid hub address duplication
|
||||
|
||||
UsbDevice thePool[MAX_DEVICES_ALLOWED];
|
||||
UsbDevice thePool[MAX_DEVICES_ALLOWED];
|
||||
|
||||
// Initializes address pool entry
|
||||
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)
|
||||
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)
|
||||
return i;
|
||||
}
|
||||
return 0;
|
||||
};
|
||||
// Frees address entry specified by index parameter
|
||||
void FreeAddressByIndex(uint8_t index)
|
||||
{
|
||||
// Zerro field is reserved and should not be affected
|
||||
if (index == 0)
|
||||
return;
|
||||
// Initializes address pool entry
|
||||
|
||||
// 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); )
|
||||
FreeAddressByIndex(i);
|
||||
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
|
||||
|
||||
// If the hub had the last allocated address, hubCounter should be decremented
|
||||
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++)
|
||||
InitEntry(i);
|
||||
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
|
||||
|
||||
hubCounter = 0;
|
||||
};
|
||||
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) {
|
||||
// Zerro field is reserved and should not be affected
|
||||
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));)
|
||||
FreeAddressByIndex(i);
|
||||
|
||||
// If the hub had the last allocated address, hubCounter should be decremented
|
||||
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++)
|
||||
InitEntry(i);
|
||||
|
||||
hubCounter = 0;
|
||||
};
|
||||
|
||||
public:
|
||||
AddressPoolImpl() : hubCounter(0)
|
||||
{
|
||||
// Zero address is reserved
|
||||
InitEntry(0);
|
||||
|
||||
thePool[0].address = 0;
|
||||
thePool[0].epinfo = &dev0ep;
|
||||
dev0ep.epAddr = 0;
|
||||
dev0ep.maxPktSize = 8;
|
||||
dev0ep.epAttribs = 0; //set DATA0/1 toggles to 0
|
||||
dev0ep.bmNakPower = USB_NAK_MAX_POWER;
|
||||
AddressPoolImpl() : hubCounter(0) {
|
||||
// Zero address is reserved
|
||||
InitEntry(0);
|
||||
|
||||
InitAllAddresses();
|
||||
};
|
||||
// Returns a pointer to a specified address entry
|
||||
virtual UsbDevice* GetUsbDevicePtr(uint8_t addr)
|
||||
{
|
||||
if (!addr)
|
||||
return thePool;
|
||||
thePool[0].address = 0;
|
||||
thePool[0].epinfo = &dev0ep;
|
||||
dev0ep.epAddr = 0;
|
||||
dev0ep.maxPktSize = 8;
|
||||
dev0ep.epAttribs = 0; //set DATA0/1 toggles to 0
|
||||
dev0ep.bmNakPower = USB_NAK_MAX_POWER;
|
||||
|
||||
uint8_t index = FindAddressIndex(addr);
|
||||
InitAllAddresses();
|
||||
};
|
||||
// Returns a pointer to a specified address entry
|
||||
|
||||
return (!index) ? NULL : thePool + index;
|
||||
};
|
||||
virtual UsbDevice* GetUsbDevicePtr(uint8_t addr) {
|
||||
if(!addr)
|
||||
return thePool;
|
||||
|
||||
// Performs an operation specified by pfunc for each addressed device
|
||||
void ForEachUsbDevice(UsbDeviceHandleFunc pfunc)
|
||||
{
|
||||
if (!pfunc)
|
||||
return;
|
||||
uint8_t index = FindAddressIndex(addr);
|
||||
|
||||
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)
|
||||
{
|
||||
/* if (parent != 0 && port == 0)
|
||||
Serial.println("PRT:0"); */
|
||||
return(!index) ? NULL : thePool + index;
|
||||
};
|
||||
|
||||
if (parent > 127 || port > 7)
|
||||
return 0;
|
||||
// Performs an operation specified by pfunc for each addressed device
|
||||
|
||||
if (is_hub && hubCounter == 7)
|
||||
return 0;
|
||||
void ForEachUsbDevice(UsbDeviceHandleFunc pfunc) {
|
||||
if(!pfunc)
|
||||
return;
|
||||
|
||||
// finds first empty address entry starting from one
|
||||
uint8_t index = FindAddressIndex(0);
|
||||
for(uint8_t i = 1; i < MAX_DEVICES_ALLOWED; i++)
|
||||
if(thePool[i].address)
|
||||
pfunc(thePool + i);
|
||||
};
|
||||
// Allocates new address
|
||||
|
||||
if (!index) // if empty entry is not found
|
||||
return 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 == 0)
|
||||
{
|
||||
if (is_hub)
|
||||
{
|
||||
thePool[index].address = 0x41;
|
||||
hubCounter ++;
|
||||
}
|
||||
else
|
||||
thePool[index].address = 1;
|
||||
if(parent > 127 || port > 7)
|
||||
return 0;
|
||||
|
||||
return thePool[index].address;
|
||||
}
|
||||
if(is_hub && hubCounter == 7)
|
||||
return 0;
|
||||
|
||||
UsbDeviceAddress addr;
|
||||
// finds first empty address entry starting from one
|
||||
uint8_t index = FindAddressIndex(0);
|
||||
|
||||
addr.bmParent = ((UsbDeviceAddress*)&parent)->bmAddress;
|
||||
if(!index) // if empty entry is not found
|
||||
return 0;
|
||||
|
||||
if (is_hub)
|
||||
{
|
||||
addr.bmHub = 1;
|
||||
addr.bmAddress = ++hubCounter;
|
||||
}
|
||||
else
|
||||
{
|
||||
addr.bmHub = 0;
|
||||
addr.bmAddress = port;
|
||||
}
|
||||
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)
|
||||
{
|
||||
// if the root hub is disconnected all the addresses should be initialized
|
||||
if (addr == 0x41)
|
||||
{
|
||||
InitAllAddresses();
|
||||
return;
|
||||
}
|
||||
uint8_t index = FindAddressIndex(addr);
|
||||
FreeAddressByIndex(index);
|
||||
};
|
||||
// Returns number of hubs attached
|
||||
// It can be rather helpfull to find out if there are hubs attached than getting the exact number of hubs.
|
||||
//uint8_t GetNumHubs()
|
||||
//{
|
||||
// return hubCounter;
|
||||
//};
|
||||
//uint8_t GetNumDevices()
|
||||
//{
|
||||
// uint8_t counter = 0;
|
||||
if(parent == 0) {
|
||||
if(is_hub) {
|
||||
thePool[index].address = 0x41;
|
||||
hubCounter++;
|
||||
} else
|
||||
thePool[index].address = 1;
|
||||
|
||||
// for (uint8_t i=1; i<MAX_DEVICES_ALLOWED; i++)
|
||||
// if (thePool[i].address != 0);
|
||||
// counter ++;
|
||||
return thePool[index].address;
|
||||
}
|
||||
|
||||
// return counter;
|
||||
//};
|
||||
UsbDeviceAddress addr;
|
||||
|
||||
addr.bmParent = ((UsbDeviceAddress*) & parent)->bmAddress;
|
||||
|
||||
if(is_hub) {
|
||||
addr.bmHub = 1;
|
||||
addr.bmAddress = ++hubCounter;
|
||||
} else {
|
||||
addr.bmHub = 0;
|
||||
addr.bmAddress = port;
|
||||
}
|
||||
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) {
|
||||
// if the root hub is disconnected all the addresses should be initialized
|
||||
if(addr == 0x41) {
|
||||
InitAllAddresses();
|
||||
return;
|
||||
}
|
||||
uint8_t index = FindAddressIndex(addr);
|
||||
FreeAddressByIndex(index);
|
||||
};
|
||||
// Returns number of hubs attached
|
||||
// It can be rather helpfull to find out if there are hubs attached than getting the exact number of hubs.
|
||||
//uint8_t GetNumHubs()
|
||||
//{
|
||||
// return hubCounter;
|
||||
//};
|
||||
//uint8_t GetNumDevices()
|
||||
//{
|
||||
// uint8_t counter = 0;
|
||||
|
||||
// for (uint8_t i=1; i<MAX_DEVICES_ALLOWED; i++)
|
||||
// if (thePool[i].address != 0);
|
||||
// counter ++;
|
||||
|
||||
// return counter;
|
||||
//};
|
||||
};
|
||||
|
||||
#endif // __ADDRESS_H__
|
528
adk.cpp
528
adk.cpp
|
@ -13,371 +13,319 @@ 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;
|
||||
const uint8_t ADK::epDataInIndex = 1;
|
||||
const uint8_t ADK::epDataOutIndex = 2;
|
||||
|
||||
ADK::ADK(USB *p, const char* manufacturer,
|
||||
const char* model,
|
||||
const char* description,
|
||||
const char* version,
|
||||
const char* uri,
|
||||
const char* serial) :
|
||||
ADK::ADK(USB *p, const char* manufacturer,
|
||||
const char* model,
|
||||
const char* description,
|
||||
const char* version,
|
||||
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),
|
||||
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++) {
|
||||
epInfo[i].epAddr = 0;
|
||||
epInfo[i].maxPktSize = (i) ? 0 : 8;
|
||||
epInfo[i].epAttribs = (0xfc & (USB_NAK_MAX_POWER << 2));
|
||||
}//for(uint8_t i=0; i<ADK_MAX_ENDPOINTS; i++...
|
||||
|
||||
manufacturer(manufacturer),
|
||||
model(model),
|
||||
description(description),
|
||||
version(version),
|
||||
uri(uri),
|
||||
serial(serial)
|
||||
//set bulk-IN EP naklimit to 1
|
||||
epInfo[epDataInIndex].epAttribs = (0xfc & (USB_NAK_NOWAIT << 2));
|
||||
|
||||
{
|
||||
// initialize endpoint data structures
|
||||
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;
|
||||
}//for(uint8_t i=0; i<ADK_MAX_ENDPOINTS; i++...
|
||||
|
||||
// register in USB subsystem
|
||||
if (pUsb) {
|
||||
pUsb->RegisterDeviceClass(this); //set devConfig[] entry
|
||||
}
|
||||
// register in USB subsystem
|
||||
if (pUsb) {
|
||||
pUsb->RegisterDeviceClass(this); //set devConfig[] entry
|
||||
}
|
||||
}
|
||||
|
||||
/* 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 rcode;
|
||||
UsbDevice *p = NULL;
|
||||
EpInfo *oldep_ptr = NULL;
|
||||
uint8_t num_of_conf; // number of configurations
|
||||
uint8_t buf[sizeof (USB_DEVICE_DESCRIPTOR)];
|
||||
uint8_t rcode;
|
||||
UsbDevice *p = NULL;
|
||||
EpInfo *oldep_ptr = NULL;
|
||||
uint8_t num_of_conf; // number of configurations
|
||||
|
||||
// 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;
|
||||
}
|
||||
// get memory address of USB device address pool
|
||||
AddressPool &addrPool = pUsb->GetAddressPool();
|
||||
|
||||
// Get pointer to pseudo device with address 0 assigned
|
||||
p = addrPool.GetUsbDevicePtr(0);
|
||||
USBTRACE("\r\nADK Init");
|
||||
|
||||
if (!p) {
|
||||
#ifdef DEBUG
|
||||
USBTRACE("\r\nAddress not found");
|
||||
#endif
|
||||
return USB_ERROR_ADDRESS_NOT_FOUND_IN_POOL;
|
||||
}
|
||||
// check if address has already been assigned to an instance
|
||||
if (bAddress) {
|
||||
USBTRACE("\r\nAddress in use");
|
||||
return USB_ERROR_CLASS_INSTANCE_ALREADY_IN_USE;
|
||||
}
|
||||
|
||||
if (!p->epinfo) {
|
||||
#ifdef DEBUG
|
||||
USBTRACE("epinfo is null\r\n");
|
||||
#endif
|
||||
return USB_ERROR_EPINFO_IS_NULL;
|
||||
}
|
||||
// Get pointer to pseudo device with address 0 assigned
|
||||
p = addrPool.GetUsbDevicePtr(0);
|
||||
|
||||
// Save old pointer to EP_RECORD of address 0
|
||||
oldep_ptr = p->epinfo;
|
||||
if (!p) {
|
||||
USBTRACE("\r\nAddress not found");
|
||||
return USB_ERROR_ADDRESS_NOT_FOUND_IN_POOL;
|
||||
}
|
||||
|
||||
// Temporary assign new pointer to epInfo to p->epinfo in order to avoid toggle inconsistence
|
||||
p->epinfo = epInfo;
|
||||
if (!p->epinfo) {
|
||||
USBTRACE("epinfo is null\r\n");
|
||||
return USB_ERROR_EPINFO_IS_NULL;
|
||||
}
|
||||
|
||||
p->lowspeed = lowspeed;
|
||||
// Save old pointer to EP_RECORD of address 0
|
||||
oldep_ptr = p->epinfo;
|
||||
|
||||
// Get device descriptor
|
||||
rcode = pUsb->getDevDescr( 0, 0, sizeof(USB_DEVICE_DESCRIPTOR), (uint8_t*)buf );
|
||||
// Temporary assign new pointer to epInfo to p->epinfo in order to avoid toggle inconsistence
|
||||
p->epinfo = epInfo;
|
||||
|
||||
// Restore p->epinfo
|
||||
p->epinfo = oldep_ptr;
|
||||
p->lowspeed = lowspeed;
|
||||
|
||||
if( rcode ){
|
||||
goto FailGetDevDescr;
|
||||
}
|
||||
// Get device descriptor
|
||||
rcode = pUsb->getDevDescr(0, 0, sizeof (USB_DEVICE_DESCRIPTOR), (uint8_t*)buf);
|
||||
|
||||
// Allocate new address according to device class
|
||||
bAddress = addrPool.AllocAddress(parent, false, port);
|
||||
// Restore p->epinfo
|
||||
p->epinfo = oldep_ptr;
|
||||
|
||||
// Extract Max Packet Size from device descriptor
|
||||
epInfo[0].maxPktSize = (uint8_t)((USB_DEVICE_DESCRIPTOR*)buf)->bMaxPacketSize0;
|
||||
if (rcode) {
|
||||
goto FailGetDevDescr;
|
||||
}
|
||||
|
||||
// Assign new address to the device
|
||||
rcode = pUsb->setAddr( 0, 0, bAddress );
|
||||
if (rcode) {
|
||||
p->lowspeed = false;
|
||||
addrPool.FreeAddress(bAddress);
|
||||
bAddress = 0;
|
||||
//USBTRACE2("setAddr:",rcode);
|
||||
return rcode;
|
||||
}//if (rcode...
|
||||
// Allocate new address according to device class
|
||||
bAddress = addrPool.AllocAddress(parent, false, port);
|
||||
|
||||
//USBTRACE2("\r\nAddr:", bAddress);
|
||||
// Extract Max Packet Size from device descriptor
|
||||
epInfo[0].maxPktSize = (uint8_t)((USB_DEVICE_DESCRIPTOR*)buf)->bMaxPacketSize0;
|
||||
|
||||
p->lowspeed = false;
|
||||
// Assign new address to the device
|
||||
rcode = pUsb->setAddr(0, 0, bAddress);
|
||||
if (rcode) {
|
||||
p->lowspeed = false;
|
||||
addrPool.FreeAddress(bAddress);
|
||||
bAddress = 0;
|
||||
//USBTRACE2("setAddr:",rcode);
|
||||
return rcode;
|
||||
}//if (rcode...
|
||||
|
||||
//get pointer to assigned address record
|
||||
p = addrPool.GetUsbDevicePtr(bAddress);
|
||||
if (!p) {
|
||||
return USB_ERROR_ADDRESS_NOT_FOUND_IN_POOL;
|
||||
}
|
||||
//USBTRACE2("\r\nAddr:", bAddress);
|
||||
|
||||
p->lowspeed = lowspeed;
|
||||
p->lowspeed = false;
|
||||
|
||||
// Assign epInfo to epinfo pointer - only EP0 is known
|
||||
rcode = pUsb->setEpInfoEntry(bAddress, 1, epInfo);
|
||||
if (rcode) {
|
||||
goto FailSetDevTblEntry;
|
||||
}
|
||||
//get pointer to assigned address record
|
||||
p = addrPool.GetUsbDevicePtr(bAddress);
|
||||
if (!p) {
|
||||
return USB_ERROR_ADDRESS_NOT_FOUND_IN_POOL;
|
||||
}
|
||||
|
||||
//check if ADK device is already in accessory mode; if yes, configure and exit
|
||||
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;
|
||||
p->lowspeed = lowspeed;
|
||||
|
||||
//USBTRACE2("\r\nNC:",num_of_conf);
|
||||
// Assign epInfo to epinfo pointer - only EP0 is known
|
||||
rcode = pUsb->setEpInfoEntry(bAddress, 1, epInfo);
|
||||
if (rcode) {
|
||||
goto FailSetDevTblEntry;
|
||||
}
|
||||
|
||||
for (uint8_t i=0; i<num_of_conf; i++) {
|
||||
ConfigDescParser<0, 0, 0, 0> confDescrParser(this);
|
||||
delay(1);
|
||||
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);
|
||||
//check if ADK device is already in accessory mode; if yes, configure and exit
|
||||
if (((USB_DEVICE_DESCRIPTOR*)buf)->idVendor == ADK_VID &&
|
||||
(((USB_DEVICE_DESCRIPTOR*)buf)->idProduct == ADK_PID || ((USB_DEVICE_DESCRIPTOR*)buf)->idProduct == ADB_PID)) {
|
||||
USBTRACE("\r\nAcc.mode device detected");
|
||||
/* 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);
|
||||
rcode = pUsb->getConfDescr(bAddress, 0, i, &confDescrParser);
|
||||
if (rcode) {
|
||||
goto FailGetConfDescr;
|
||||
}
|
||||
if (bNumEP > 2) {
|
||||
break;
|
||||
}
|
||||
} // for (uint8_t i=0; i<num_of_conf; i++...
|
||||
|
||||
if (bNumEP == 3) {
|
||||
// Assign epInfo to epinfo pointer - this time all 3 endpoins
|
||||
rcode = pUsb->setEpInfoEntry(bAddress, 3, epInfo);
|
||||
if (rcode) {
|
||||
goto FailSetDevTblEntry;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
if( rcode ) {
|
||||
goto FailGetConfDescr;
|
||||
}
|
||||
if( bNumEP > 2 ) {
|
||||
break;
|
||||
}
|
||||
} // for (uint8_t i=0; i<num_of_conf; i++...
|
||||
|
||||
if( bNumEP == 3 ) {
|
||||
// Assign epInfo to epinfo pointer - this time all 3 endpoins
|
||||
rcode = pUsb->setEpInfoEntry(bAddress, 3, epInfo);
|
||||
|
||||
|
||||
// Set Configuration Value
|
||||
rcode = pUsb->setConf(bAddress, 0, bConfNum);
|
||||
if (rcode) {
|
||||
goto FailSetDevTblEntry;
|
||||
}
|
||||
}
|
||||
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 );
|
||||
|
||||
USBTRACE("\r\nConfiguration successful");
|
||||
ready = true;
|
||||
return 0; //successful configuration
|
||||
}//if( buf->idVendor == ADK_VID...
|
||||
|
||||
//probe device - get accessory protocol revision
|
||||
{
|
||||
uint16_t adkproto = -1;
|
||||
rcode = getProto((uint8_t*) & adkproto);
|
||||
if (rcode) {
|
||||
goto FailGetProto; //init fails
|
||||
}
|
||||
USBTRACE2("\r\nADK protocol rev. ", adkproto);
|
||||
}
|
||||
|
||||
// Set Configuration Value
|
||||
rcode = pUsb->setConf(bAddress, 0, bConfNum);
|
||||
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\nConfiguration successful");
|
||||
#endif
|
||||
ready = true;
|
||||
return 0; //successful configuration
|
||||
}//if( buf->idVendor == ADK_VID...
|
||||
//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);
|
||||
|
||||
//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 ){
|
||||
goto FailGetProto; //init fails
|
||||
}
|
||||
#ifdef DEBUG
|
||||
USBTRACE2("\r\nADK protocol rev. ", adkproto );
|
||||
#endif
|
||||
}
|
||||
//switch to accessory mode
|
||||
//the Android phone will reset
|
||||
rcode = switchAcc();
|
||||
if (rcode) {
|
||||
goto FailSwAcc; //init fails
|
||||
}
|
||||
rcode = -1;
|
||||
goto SwAttempt; //switch to accessory mode attempted
|
||||
|
||||
//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);
|
||||
|
||||
//switch to accessory mode
|
||||
//the Android phone will reset
|
||||
rcode = switchAcc();
|
||||
if( rcode ) {
|
||||
goto FailSwAcc; //init fails
|
||||
}
|
||||
rcode = -1;
|
||||
goto SwAttempt; //switch to accessory mode attempted
|
||||
|
||||
/* diagnostic messages */
|
||||
/* diagnostic messages */
|
||||
FailGetDevDescr:
|
||||
#ifdef DEBUG
|
||||
USBTRACE("\r\ngetDevDescr:");
|
||||
#endif
|
||||
goto Fail;
|
||||
USBTRACE("\r\ngetDevDescr:");
|
||||
goto Fail;
|
||||
|
||||
FailSetDevTblEntry:
|
||||
#ifdef DEBUG
|
||||
USBTRACE("\r\nsetDevTblEn:");
|
||||
#endif
|
||||
goto Fail;
|
||||
USBTRACE("\r\nsetDevTblEn:");
|
||||
goto Fail;
|
||||
|
||||
FailGetProto:
|
||||
#ifdef DEBUG
|
||||
USBTRACE("\r\ngetProto:");
|
||||
#endif
|
||||
goto Fail;
|
||||
USBTRACE("\r\ngetProto:");
|
||||
goto Fail;
|
||||
|
||||
FailSwAcc:
|
||||
#ifdef DEBUG
|
||||
USBTRACE("\r\nswAcc:");
|
||||
#endif
|
||||
goto Fail;
|
||||
USBTRACE("\r\nswAcc:");
|
||||
goto Fail;
|
||||
|
||||
SwAttempt:
|
||||
#ifdef DEBUG
|
||||
USBTRACE("\r\nAccessory mode switch attempt");
|
||||
#endif
|
||||
goto Fail;
|
||||
USBTRACE("\r\nAccessory mode switch attempt");
|
||||
goto Fail;
|
||||
|
||||
FailGetConfDescr:
|
||||
// USBTRACE("getConf:");
|
||||
goto Fail;
|
||||
//
|
||||
// USBTRACE("getConf:");
|
||||
goto Fail;
|
||||
//
|
||||
FailSetConf:
|
||||
// USBTRACE("setConf:");
|
||||
goto Fail;
|
||||
//
|
||||
//FailOnInit:
|
||||
// USBTRACE("OnInit:");
|
||||
// goto Fail;
|
||||
//
|
||||
// USBTRACE("setConf:");
|
||||
goto Fail;
|
||||
//
|
||||
//FailOnInit:
|
||||
// USBTRACE("OnInit:");
|
||||
// goto Fail;
|
||||
//
|
||||
Fail:
|
||||
//USBTRACE2("\r\nADK Init Failed, error code: ", rcode);
|
||||
Release();
|
||||
return rcode;
|
||||
//USBTRACE2("\r\nADK Init Failed, error code: ", rcode);
|
||||
Release();
|
||||
return rcode;
|
||||
}
|
||||
|
||||
/* 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)
|
||||
{
|
||||
//ErrorMessage<uint8_t>(PSTR("Conf.Val"), conf);
|
||||
//ErrorMessage<uint8_t>(PSTR("Iface Num"),iface);
|
||||
//ErrorMessage<uint8_t>(PSTR("Alt.Set"), alt);
|
||||
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 ) {
|
||||
return;
|
||||
}
|
||||
//added by Yuuichi Akagawa
|
||||
if (bNumEP == 3) {
|
||||
return;
|
||||
}
|
||||
|
||||
bConfNum = conf;
|
||||
bConfNum = conf;
|
||||
|
||||
uint8_t index;
|
||||
uint8_t index;
|
||||
|
||||
if ((pep->bmAttributes & 0x02) == 2) {
|
||||
index = ((pep->bEndpointAddress & 0x80) == 0x80) ? epDataInIndex : epDataOutIndex;
|
||||
}
|
||||
// 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;
|
||||
// Fill in the endpoint info structure
|
||||
epInfo[index].epAddr = (pep->bEndpointAddress & 0x0F);
|
||||
epInfo[index].maxPktSize = (uint8_t)pep->wMaxPacketSize;
|
||||
|
||||
bNumEP ++;
|
||||
bNumEP++;
|
||||
|
||||
//PrintEndpointDescriptor(pep);
|
||||
//PrintEndpointDescriptor(pep);
|
||||
}
|
||||
|
||||
/* Performs a cleanup after failed Init() attempt */
|
||||
uint8_t ADK::Release()
|
||||
{
|
||||
pUsb->GetAddressPool().FreeAddress(bAddress);
|
||||
uint8_t ADK::Release() {
|
||||
pUsb->GetAddressPool().FreeAddress(bAddress);
|
||||
|
||||
bNumEP = 1; //must have to be reset to 1
|
||||
bNumEP = 1; //must have to be reset to 1
|
||||
|
||||
bAddress = 0;
|
||||
ready = false;
|
||||
return 0;
|
||||
bAddress = 0;
|
||||
ready = false;
|
||||
return 0;
|
||||
}
|
||||
|
||||
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::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)
|
||||
{
|
||||
return pUsb->outTransfer(bAddress, epInfo[epDataOutIndex].epAddr, nbytes, 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);
|
||||
}
|
||||
|
|
114
adk.h
114
adk.h
|
@ -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,78 +64,86 @@ 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;
|
||||
const char* model;
|
||||
const char* description;
|
||||
const char* version;
|
||||
const char* uri;
|
||||
const char* serial;
|
||||
/* ID strings */
|
||||
const char* manufacturer;
|
||||
const char* model;
|
||||
const char* description;
|
||||
const char* version;
|
||||
const char* uri;
|
||||
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 );
|
||||
/* ADK proprietary requests */
|
||||
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
|
||||
static const uint8_t epDataOutIndex; // DataOUT endpoint index
|
||||
static const uint8_t epDataInIndex; // DataIn endpoint index
|
||||
static const uint8_t epDataOutIndex; // DataOUT endpoint index
|
||||
|
||||
/* mandatory members */
|
||||
USB *pUsb;
|
||||
uint8_t bAddress;
|
||||
uint8_t bConfNum; // configuration number
|
||||
/* mandatory members */
|
||||
USB *pUsb;
|
||||
uint8_t bAddress;
|
||||
uint8_t bConfNum; // configuration number
|
||||
|
||||
uint8_t bNumEP; // total number of EP in the configuration
|
||||
bool ready;
|
||||
uint8_t bNumEP; // total number of EP in the configuration
|
||||
bool ready;
|
||||
|
||||
/* Endpoint data structure */
|
||||
EpInfo epInfo[ADK_MAX_ENDPOINTS];
|
||||
/* Endpoint data structure */
|
||||
EpInfo epInfo[ADK_MAX_ENDPOINTS];
|
||||
|
||||
void PrintEndpointDescriptor(const USB_ENDPOINT_DESCRIPTOR* ep_ptr);
|
||||
void PrintEndpointDescriptor(const USB_ENDPOINT_DESCRIPTOR* ep_ptr);
|
||||
|
||||
public:
|
||||
ADK(USB *pUsb, const char* manufacturer,
|
||||
const char* model,
|
||||
const char* description,
|
||||
const char* version,
|
||||
const char* uri,
|
||||
const char* serial);
|
||||
ADK(USB *pUsb, const char* manufacturer,
|
||||
const char* model,
|
||||
const char* description,
|
||||
const char* version,
|
||||
const char* uri,
|
||||
const char* serial);
|
||||
|
||||
// Methods for receiving and sending data
|
||||
uint8_t RcvData(uint16_t *nbytesptr, uint8_t *dataptr);
|
||||
uint8_t SndData(uint16_t nbytes, uint8_t *dataptr);
|
||||
// Methods for receiving and sending data
|
||||
uint8_t RcvData(uint16_t *nbytesptr, uint8_t *dataptr);
|
||||
uint8_t SndData(uint16_t nbytes, uint8_t *dataptr);
|
||||
|
||||
|
||||
// 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; };
|
||||
// USBDeviceConfig implementation
|
||||
virtual uint8_t Init(uint8_t parent, uint8_t port, bool lowspeed);
|
||||
virtual uint8_t Release();
|
||||
|
||||
//UsbConfigXtracter implementation
|
||||
virtual void EndpointXtract(uint8_t conf, uint8_t iface, uint8_t alt, uint8_t proto, const USB_ENDPOINT_DESCRIPTOR *ep);
|
||||
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 )
|
||||
{
|
||||
return( pUsb->ctrlReq(bAddress, 0, bmREQ_ADK_SEND, ADK_ACCSTART, 0, 0, 0, 0, 0, NULL, NULL));
|
||||
inline uint8_t ADK::switchAcc(void) {
|
||||
return( pUsb->ctrlReq(bAddress, 0, bmREQ_ADK_SEND, ADK_ACCSTART, 0, 0, 0, 0, 0, NULL, NULL));
|
||||
}
|
||||
|
||||
#endif // _ADK_H_
|
464
avrpins.h
464
avrpins.h
|
@ -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,238 +161,271 @@ 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:
|
||||
typedef PORT Port;
|
||||
enum{Number = PIN};
|
||||
// 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;
|
||||
|
||||
static void Set() { PORT::Set(1 << PIN); }
|
||||
enum {
|
||||
Number = PIN
|
||||
};
|
||||
|
||||
static void Set(uint8_t val){
|
||||
if(val)
|
||||
Set();
|
||||
else Clear();}
|
||||
static void Set() {
|
||||
PORT::Set(1 << PIN);
|
||||
}
|
||||
|
||||
static void SetDir(uint8_t val){
|
||||
if(val)
|
||||
SetDirWrite();
|
||||
else SetDirRead();}
|
||||
static void Set(uint8_t val) {
|
||||
if(val)
|
||||
Set();
|
||||
else Clear();
|
||||
}
|
||||
|
||||
static void Clear(){PORT::Clear(1 << PIN);}
|
||||
static void SetDir(uint8_t val) {
|
||||
if(val)
|
||||
SetDirWrite();
|
||||
else SetDirRead();
|
||||
}
|
||||
|
||||
static void Toggle(){PORT::Toggle(1 << PIN);}
|
||||
static void Clear() {
|
||||
PORT::Clear(1 << PIN);
|
||||
}
|
||||
|
||||
static void SetDirRead(){PORT::DirClear(1 << PIN);}
|
||||
static void Toggle() {
|
||||
PORT::Toggle(1 << PIN);
|
||||
}
|
||||
|
||||
static void SetDirWrite(){PORT::DirSet(1 << PIN);}
|
||||
static void SetDirRead() {
|
||||
PORT::DirClear(1 << PIN);
|
||||
}
|
||||
|
||||
static uint8_t IsSet(){return PORT::PinRead() & (uint8_t)(1 << PIN);}
|
||||
static void SetDirWrite() {
|
||||
PORT::DirSet(1 << PIN);
|
||||
}
|
||||
|
||||
static void WaiteForSet(){ while(IsSet()==0){} }
|
||||
static uint8_t IsSet() {
|
||||
return PORT::PinRead() & (uint8_t) (1 << PIN);
|
||||
}
|
||||
|
||||
static void WaiteForClear(){ while(IsSet()){} }
|
||||
}; //class TPin...
|
||||
static void WaiteForSet() {
|
||||
while(IsSet() == 0) {
|
||||
}
|
||||
}
|
||||
|
||||
// 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 WaiteForClear() {
|
||||
while(IsSet()) {
|
||||
}
|
||||
}
|
||||
}; //class TPin...
|
||||
|
||||
static void Set() { TCCR::Set(1 << COM); }
|
||||
// this class represents one bit in TCCR port.
|
||||
// used to set/clear TCCRx bits
|
||||
// It is fully static.
|
||||
|
||||
static void Clear() { TCCR::Clear(1 << COM); }
|
||||
template<typename TCCR, uint8_t COM>
|
||||
class TCom {
|
||||
// BOOST_STATIC_ASSERT(PIN < PORT::Width);
|
||||
public:
|
||||
typedef TCCR Tccr;
|
||||
|
||||
static void Toggle() { TCCR::Toggle(1 << COM); }
|
||||
}; //class TCom...
|
||||
enum {
|
||||
Com = COM
|
||||
};
|
||||
|
||||
static void Set() {
|
||||
TCCR::Set(1 << COM);
|
||||
}
|
||||
|
||||
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
|
||||
typedef TCom<Tccr0a, COM0A1> Tc0a; //P6
|
||||
typedef TCom<Tccr0a, COM0B1> Tc0b; //P5
|
||||
typedef TCom<Tccr0a, COM0A1> Tc0a; //P6
|
||||
typedef TCom<Tccr0a, COM0B1> Tc0b; //P5
|
||||
#endif
|
||||
|
||||
#ifdef USE_TCCR1A
|
||||
typedef TCom<Tccr1a, COM1A1> Tc1a; //P9
|
||||
typedef TCom<Tccr1a, COM1B1> Tc1b; //P10
|
||||
typedef TCom<Tccr1a, COM1A1> Tc1a; //P9
|
||||
typedef TCom<Tccr1a, COM1B1> Tc1b; //P10
|
||||
#endif
|
||||
|
||||
#ifdef USE_TCCR2A
|
||||
typedef TCom<Tccr2a, COM2A1> Tc2a; //P11
|
||||
typedef TCom<Tccr2a, COM2B1> Tc2b; //P3
|
||||
typedef TCom<Tccr2a, COM2A1> Tc2a; //P11
|
||||
typedef TCom<Tccr2a, COM2B1> Tc2b; //P3
|
||||
#endif
|
||||
|
||||
template<typename Tp_pin, typename Tc_bit>
|
||||
class Tp_Tc
|
||||
{
|
||||
public:
|
||||
static void SetDir(uint8_t val){
|
||||
if(val)
|
||||
SetDirWrite();
|
||||
else SetDirRead();
|
||||
}
|
||||
static void SetDirRead(){
|
||||
Tp_pin::SetDirRead(); //set pin direction
|
||||
Tc_bit::Clear(); //disconnect pin from PWM
|
||||
}
|
||||
static void SetDirWrite(){
|
||||
Tp_pin::SetDirWrite();
|
||||
Tc_bit::Clear();
|
||||
}
|
||||
};
|
||||
class Tp_Tc {
|
||||
public:
|
||||
|
||||
static void SetDir(uint8_t val) {
|
||||
if(val)
|
||||
SetDirWrite();
|
||||
else SetDirRead();
|
||||
}
|
||||
|
||||
static void SetDirRead() {
|
||||
Tp_pin::SetDirRead(); //set pin direction
|
||||
Tc_bit::Clear(); //disconnect pin from PWM
|
||||
}
|
||||
|
||||
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
|
||||
|
|
460
cdcacm.cpp
460
cdcacm.cpp
|
@ -13,347 +13,325 @@ 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;
|
||||
const uint8_t ACM::epDataOutIndex = 2;
|
||||
const uint8_t ACM::epInterruptInIndex = 3;
|
||||
const uint8_t ACM::epDataInIndex = 1;
|
||||
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++)
|
||||
{
|
||||
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;
|
||||
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_MAX_POWER;
|
||||
|
||||
}
|
||||
if (pUsb)
|
||||
pUsb->RegisterDeviceClass(this);
|
||||
//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;
|
||||
UsbDevice *p = NULL;
|
||||
EpInfo *oldep_ptr = NULL;
|
||||
uint8_t num_of_conf; // number of configurations
|
||||
uint8_t buf[constBufSize];
|
||||
uint8_t rcode;
|
||||
UsbDevice *p = NULL;
|
||||
EpInfo *oldep_ptr = NULL;
|
||||
uint8_t num_of_conf; // number of configurations
|
||||
|
||||
AddressPool &addrPool = pUsb->GetAddressPool();
|
||||
AddressPool &addrPool = pUsb->GetAddressPool();
|
||||
|
||||
USBTRACE("ACM Init\r\n");
|
||||
USBTRACE("ACM Init\r\n");
|
||||
|
||||
if (bAddress)
|
||||
return USB_ERROR_CLASS_INSTANCE_ALREADY_IN_USE;
|
||||
if (bAddress)
|
||||
return USB_ERROR_CLASS_INSTANCE_ALREADY_IN_USE;
|
||||
|
||||
// Get pointer to pseudo device with address 0 assigned
|
||||
p = addrPool.GetUsbDevicePtr(0);
|
||||
// Get pointer to pseudo device with address 0 assigned
|
||||
p = addrPool.GetUsbDevicePtr(0);
|
||||
|
||||
if (!p)
|
||||
return USB_ERROR_ADDRESS_NOT_FOUND_IN_POOL;
|
||||
if (!p)
|
||||
return USB_ERROR_ADDRESS_NOT_FOUND_IN_POOL;
|
||||
|
||||
if (!p->epinfo)
|
||||
{
|
||||
USBTRACE("epinfo\r\n");
|
||||
return USB_ERROR_EPINFO_IS_NULL;
|
||||
}
|
||||
if (!p->epinfo) {
|
||||
USBTRACE("epinfo\r\n");
|
||||
return USB_ERROR_EPINFO_IS_NULL;
|
||||
}
|
||||
|
||||
// Save old pointer to EP_RECORD of address 0
|
||||
oldep_ptr = p->epinfo;
|
||||
// Save old pointer to EP_RECORD of address 0
|
||||
oldep_ptr = p->epinfo;
|
||||
|
||||
// Temporary assign new pointer to epInfo to p->epinfo in order to avoid toggle inconsistence
|
||||
p->epinfo = epInfo;
|
||||
// Temporary assign new pointer to epInfo to p->epinfo in order to avoid toggle inconsistence
|
||||
p->epinfo = epInfo;
|
||||
|
||||
p->lowspeed = lowspeed;
|
||||
p->lowspeed = lowspeed;
|
||||
|
||||
// Get device descriptor
|
||||
rcode = pUsb->getDevDescr( 0, 0, constBufSize, (uint8_t*)buf );
|
||||
// Get device descriptor
|
||||
rcode = pUsb->getDevDescr(0, 0, constBufSize, (uint8_t*)buf);
|
||||
|
||||
// Restore p->epinfo
|
||||
p->epinfo = oldep_ptr;
|
||||
// Restore p->epinfo
|
||||
p->epinfo = oldep_ptr;
|
||||
|
||||
if( rcode )
|
||||
goto FailGetDevDescr;
|
||||
if (rcode)
|
||||
goto FailGetDevDescr;
|
||||
|
||||
// Allocate new address according to device class
|
||||
bAddress = addrPool.AllocAddress(parent, false, port);
|
||||
// Allocate new address according to device class
|
||||
bAddress = addrPool.AllocAddress(parent, false, port);
|
||||
|
||||
if (!bAddress)
|
||||
return USB_ERROR_OUT_OF_ADDRESS_SPACE_IN_POOL;
|
||||
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;
|
||||
// Extract Max Packet Size from the device descriptor
|
||||
epInfo[0].maxPktSize = (uint8_t)((USB_DEVICE_DESCRIPTOR*)buf)->bMaxPacketSize0;
|
||||
|
||||
// Assign new address to the device
|
||||
rcode = pUsb->setAddr( 0, 0, bAddress );
|
||||
// Assign new address to the device
|
||||
rcode = pUsb->setAddr(0, 0, bAddress);
|
||||
|
||||
if (rcode)
|
||||
{
|
||||
p->lowspeed = false;
|
||||
addrPool.FreeAddress(bAddress);
|
||||
bAddress = 0;
|
||||
USBTRACE2("setAddr:",rcode);
|
||||
return rcode;
|
||||
}
|
||||
if (rcode) {
|
||||
p->lowspeed = false;
|
||||
addrPool.FreeAddress(bAddress);
|
||||
bAddress = 0;
|
||||
USBTRACE2("setAddr:", rcode);
|
||||
return rcode;
|
||||
}
|
||||
|
||||
USBTRACE2("Addr:", bAddress);
|
||||
USBTRACE2("Addr:", bAddress);
|
||||
|
||||
p->lowspeed = false;
|
||||
p->lowspeed = false;
|
||||
|
||||
p = addrPool.GetUsbDevicePtr(bAddress);
|
||||
p = addrPool.GetUsbDevicePtr(bAddress);
|
||||
|
||||
if (!p)
|
||||
return USB_ERROR_ADDRESS_NOT_FOUND_IN_POOL;
|
||||
if (!p)
|
||||
return USB_ERROR_ADDRESS_NOT_FOUND_IN_POOL;
|
||||
|
||||
p->lowspeed = lowspeed;
|
||||
p->lowspeed = lowspeed;
|
||||
|
||||
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);
|
||||
// Assign epInfo to epinfo pointer
|
||||
rcode = pUsb->setEpInfoEntry(bAddress, 1, epInfo);
|
||||
|
||||
if (rcode)
|
||||
goto FailSetDevTblEntry;
|
||||
if (rcode)
|
||||
goto FailSetDevTblEntry;
|
||||
|
||||
USBTRACE2("NC:", num_of_conf);
|
||||
USBTRACE2("NC:", num_of_conf);
|
||||
|
||||
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);
|
||||
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);
|
||||
|
||||
ConfigDescParser<USB_CLASS_CDC_DATA, 0, 0,
|
||||
CP_MASK_COMPARE_CLASS> CdcDataParser(this);
|
||||
ConfigDescParser<USB_CLASS_CDC_DATA, 0, 0,
|
||||
CP_MASK_COMPARE_CLASS> CdcDataParser(this);
|
||||
|
||||
rcode = pUsb->getConfDescr(bAddress, 0, i, &CdcControlParser);
|
||||
rcode = pUsb->getConfDescr(bAddress, 0, i, &CdcDataParser);
|
||||
rcode = pUsb->getConfDescr(bAddress, 0, i, &CdcControlParser);
|
||||
|
||||
if (bNumEP > 1)
|
||||
break;
|
||||
} // for
|
||||
if (rcode)
|
||||
goto FailGetConfDescr;
|
||||
|
||||
if (bNumEP < 4)
|
||||
return USB_DEV_CONFIG_ERROR_DEVICE_NOT_SUPPORTED;
|
||||
rcode = pUsb->getConfDescr(bAddress, 0, i, &CdcDataParser);
|
||||
|
||||
// Assign epInfo to epinfo pointer
|
||||
rcode = pUsb->setEpInfoEntry(bAddress, bNumEP, epInfo);
|
||||
if (rcode)
|
||||
goto FailGetConfDescr;
|
||||
|
||||
USBTRACE2("Conf:", bConfNum);
|
||||
if (bNumEP > 1)
|
||||
break;
|
||||
} // for
|
||||
|
||||
// Set Configuration Value
|
||||
rcode = pUsb->setConf(bAddress, 0, bConfNum);
|
||||
if (bNumEP < 4)
|
||||
return USB_DEV_CONFIG_ERROR_DEVICE_NOT_SUPPORTED;
|
||||
|
||||
if (rcode)
|
||||
goto FailSetConf;
|
||||
// Assign epInfo to epinfo pointer
|
||||
rcode = pUsb->setEpInfoEntry(bAddress, bNumEP, epInfo);
|
||||
|
||||
rcode = pAsync->OnInit(this);
|
||||
USBTRACE2("Conf:", bConfNum);
|
||||
|
||||
if (rcode)
|
||||
goto FailOnInit;
|
||||
// Set Configuration Value
|
||||
rcode = pUsb->setConf(bAddress, 0, bConfNum);
|
||||
|
||||
USBTRACE("ACM configured\r\n");
|
||||
ready = true;
|
||||
if (rcode)
|
||||
goto FailSetConf;
|
||||
|
||||
//bPollEnable = true;
|
||||
rcode = pAsync->OnInit(this);
|
||||
|
||||
//USBTRACE("Poll enabled\r\n");
|
||||
return 0;
|
||||
if (rcode)
|
||||
goto FailOnInit;
|
||||
|
||||
USBTRACE("ACM configured\r\n");
|
||||
|
||||
//bPollEnable = true;
|
||||
|
||||
//USBTRACE("Poll enabled\r\n");
|
||||
return 0;
|
||||
|
||||
FailGetDevDescr:
|
||||
USBTRACE("getDevDescr:");
|
||||
goto Fail;
|
||||
USBTRACE("getDevDescr:");
|
||||
goto Fail;
|
||||
|
||||
FailSetDevTblEntry:
|
||||
USBTRACE("setDevTblEn:");
|
||||
goto Fail;
|
||||
USBTRACE("setDevTblEn:");
|
||||
goto Fail;
|
||||
|
||||
FailGetConfDescr:
|
||||
USBTRACE("getConf:");
|
||||
goto Fail;
|
||||
USBTRACE("getConf:");
|
||||
goto Fail;
|
||||
|
||||
FailSetConf:
|
||||
USBTRACE("setConf:");
|
||||
goto Fail;
|
||||
USBTRACE("setConf:");
|
||||
goto Fail;
|
||||
|
||||
FailOnInit:
|
||||
USBTRACE("OnInit:");
|
||||
goto Fail;
|
||||
USBTRACE("OnInit:");
|
||||
goto Fail;
|
||||
|
||||
Fail:
|
||||
Serial.println(rcode, HEX);
|
||||
Release();
|
||||
return rcode;
|
||||
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;
|
||||
|
||||
bConfNum = conf;
|
||||
uint8_t index;
|
||||
|
||||
uint8_t index;
|
||||
if ((pep->bmAttributes & 0x03) == 3 && (pep->bEndpointAddress & 0x80) == 0x80)
|
||||
index = epInterruptInIndex;
|
||||
else
|
||||
if ((pep->bmAttributes & 0x02) == 2)
|
||||
index = ((pep->bEndpointAddress & 0x80) == 0x80) ? epDataInIndex : epDataOutIndex;
|
||||
else
|
||||
return;
|
||||
|
||||
if ((pep->bmAttributes & 0x03) == 3 && (pep->bEndpointAddress & 0x80) == 0x80)
|
||||
index = epInterruptInIndex;
|
||||
else
|
||||
if ((pep->bmAttributes & 0x02) == 2)
|
||||
index = ((pep->bEndpointAddress & 0x80) == 0x80) ? epDataInIndex : epDataOutIndex;
|
||||
else
|
||||
return;
|
||||
// Fill in the endpoint info structure
|
||||
epInfo[index].epAddr = (pep->bEndpointAddress & 0x0F);
|
||||
epInfo[index].maxPktSize = (uint8_t)pep->wMaxPacketSize;
|
||||
epInfo[index].epAttribs = 0;
|
||||
|
||||
// Fill in the endpoint info structure
|
||||
epInfo[index].epAddr = (pep->bEndpointAddress & 0x0F);
|
||||
epInfo[index].maxPktSize = (uint8_t)pep->wMaxPacketSize;
|
||||
//epInfo[index].epAttribs = 0;
|
||||
bNumEP++;
|
||||
|
||||
bNumEP ++;
|
||||
|
||||
//PrintEndpointDescriptor(pep);
|
||||
PrintEndpointDescriptor(pep);
|
||||
}
|
||||
|
||||
uint8_t ACM::Release()
|
||||
{
|
||||
pUsb->GetAddressPool().FreeAddress(bAddress);
|
||||
uint8_t ACM::Release() {
|
||||
pUsb->GetAddressPool().FreeAddress(bAddress);
|
||||
|
||||
bControlIface = 0;
|
||||
bDataIface = 0;
|
||||
bNumEP = 1;
|
||||
bControlIface = 0;
|
||||
bDataIface = 0;
|
||||
bNumEP = 1;
|
||||
|
||||
bAddress = 0;
|
||||
qNextPollTime = 0;
|
||||
bPollEnable = false;
|
||||
ready = false;
|
||||
return 0;
|
||||
bAddress = 0;
|
||||
qNextPollTime = 0;
|
||||
bPollEnable = false;
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint8_t ACM::Poll()
|
||||
{
|
||||
uint8_t rcode = 0;
|
||||
uint8_t ACM::Poll() {
|
||||
uint8_t rcode = 0;
|
||||
|
||||
if (!bPollEnable)
|
||||
return 0;
|
||||
if (!bPollEnable)
|
||||
return 0;
|
||||
|
||||
//uint32_t time_now = millis();
|
||||
//uint32_t time_now = millis();
|
||||
|
||||
//if (qNextPollTime <= time_now)
|
||||
//{
|
||||
// qNextPollTime = time_now + 100;
|
||||
//if (qNextPollTime <= time_now)
|
||||
//{
|
||||
// qNextPollTime = time_now + 100;
|
||||
|
||||
// uint8_t rcode;
|
||||
// const uint8_t constBufSize = 16;
|
||||
// uint8_t buf[constBufSize];
|
||||
// uint8_t rcode;
|
||||
// const uint8_t constBufSize = 16;
|
||||
// uint8_t buf[constBufSize];
|
||||
|
||||
// for (uint8_t i=0; i<constBufSize; i++)
|
||||
// buf[i] = 0;
|
||||
// for (uint8_t i=0; i<constBufSize; i++)
|
||||
// buf[i] = 0;
|
||||
|
||||
// uint16_t read = (constBufSize > epInfo[epInterruptInIndex].maxPktSize)
|
||||
// ? epInfo[epInterruptInIndex].maxPktSize : constBufSize;
|
||||
// rcode = pUsb->inTransfer(bAddress, epInfo[epInterruptInIndex].epAddr, &read, buf);
|
||||
// uint16_t read = (constBufSize > epInfo[epInterruptInIndex].maxPktSize)
|
||||
// ? epInfo[epInterruptInIndex].maxPktSize : constBufSize;
|
||||
// rcode = pUsb->inTransfer(bAddress, epInfo[epInterruptInIndex].epAddr, &read, buf);
|
||||
|
||||
// if (rcode)
|
||||
// return rcode;
|
||||
// if (rcode)
|
||||
// return rcode;
|
||||
|
||||
// for (uint8_t i=0; i<read; i++)
|
||||
// {
|
||||
// PrintHex<uint8_t>(buf[i]);
|
||||
// Serial.print(" ");
|
||||
// }
|
||||
// USBTRACE("\r\n");
|
||||
//}
|
||||
return rcode;
|
||||
// for (uint8_t i=0; i<read; i++)
|
||||
// {
|
||||
// PrintHex<uint8_t>(buf[i]);
|
||||
// Serial.print(" ");
|
||||
// }
|
||||
// USBTRACE("\r\n");
|
||||
//}
|
||||
return rcode;
|
||||
}
|
||||
|
||||
uint8_t ACM::RcvData(uint16_t *bytes_rcvd, uint8_t *dataptr)
|
||||
{
|
||||
return pUsb->inTransfer(bAddress, epInfo[epDataInIndex].epAddr, bytes_rcvd, 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)
|
||||
{
|
||||
return pUsb->outTransfer(bAddress, epInfo[epDataOutIndex].epAddr, nbytes, 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);
|
||||
}
|
||||
|
|
156
cdcacm.h
156
cdcacm.h
|
@ -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,123 +89,97 @@ 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
|
||||
{
|
||||
uint8_t bFunctionLength;
|
||||
uint8_t bDescriptorType;
|
||||
uint8_t bDescriptorSubtype;
|
||||
uint8_t bmCapabilities;
|
||||
uint8_t bDataInterface;
|
||||
|
||||
typedef struct {
|
||||
uint8_t bFunctionLength;
|
||||
uint8_t bDescriptorType;
|
||||
uint8_t bDescriptorSubtype;
|
||||
uint8_t bmCapabilities;
|
||||
uint8_t bDataInterface;
|
||||
} CALL_MGMNT_FUNC_DESCR;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
uint8_t bFunctionLength;
|
||||
uint8_t bDescriptorType;
|
||||
uint8_t bDescriptorSubtype;
|
||||
uint8_t bmCapabilities;
|
||||
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
|
||||
{
|
||||
uint8_t bFunctionLength;
|
||||
uint8_t bDescriptorType;
|
||||
uint8_t bDescriptorSubtype;
|
||||
uint8_t bRingerVolSteps;
|
||||
uint8_t bNumRingerPatterns;
|
||||
typedef struct {
|
||||
uint8_t bFunctionLength;
|
||||
uint8_t bDescriptorType;
|
||||
uint8_t bDescriptorSubtype;
|
||||
uint8_t bRingerVolSteps;
|
||||
uint8_t bNumRingerPatterns;
|
||||
} TEL_RINGER_FUNC_DESCR;
|
||||
|
||||
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)
|
||||
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;
|
||||
//virtual void OnDisconnected(ACM *pacm) = 0;
|
||||
virtual uint8_t OnInit(ACM *pacm) = 0;
|
||||
//virtual void OnDataRcvd(ACM *pacm, uint8_t nbytes, uint8_t *dataptr) = 0;
|
||||
//virtual void OnDisconnected(ACM *pacm) = 0;
|
||||
};
|
||||
|
||||
|
||||
#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
|
||||
static const uint8_t epInterruptInIndex; // InterruptIN endpoint index
|
||||
static const uint8_t epDataInIndex; // DataIn endpoint index
|
||||
static const uint8_t epDataOutIndex; // DataOUT endpoint index
|
||||
static const uint8_t epInterruptInIndex; // InterruptIN endpoint index
|
||||
|
||||
USB *pUsb;
|
||||
CDCAsyncOper *pAsync;
|
||||
uint8_t bAddress;
|
||||
uint8_t bConfNum; // configuration number
|
||||
uint8_t bControlIface; // Control interface value
|
||||
uint8_t bDataIface; // Data interface value
|
||||
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
|
||||
USB *pUsb;
|
||||
CDCAsyncOper *pAsync;
|
||||
uint8_t bAddress;
|
||||
uint8_t bConfNum; // configuration number
|
||||
uint8_t bControlIface; // Control interface value
|
||||
uint8_t bDataIface; // Data interface value
|
||||
uint8_t bNumEP; // total number of EP in the configuration
|
||||
uint32_t qNextPollTime; // next poll time
|
||||
bool bPollEnable; // poll enable flag
|
||||
|
||||
EpInfo epInfo[ACM_MAX_ENDPOINTS];
|
||||
EpInfo epInfo[ACM_MAX_ENDPOINTS];
|
||||
|
||||
void PrintEndpointDescriptor(const USB_ENDPOINT_DESCRIPTOR* ep_ptr);
|
||||
void PrintEndpointDescriptor(const USB_ENDPOINT_DESCRIPTOR* ep_ptr);
|
||||
|
||||
public:
|
||||
ACM(USB *pusb, CDCAsyncOper *pasync);
|
||||
ACM(USB *pusb, CDCAsyncOper *pasync);
|
||||
|
||||
uint8_t SetCommFeature(uint16_t fid, uint8_t nbytes, uint8_t *dataptr);
|
||||
uint8_t GetCommFeature(uint16_t fid, uint8_t nbytes, uint8_t *dataptr);
|
||||
uint8_t ClearCommFeature(uint16_t fid);
|
||||
uint8_t SetLineCoding(const LINE_CODING *dataptr);
|
||||
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 );
|
||||
uint8_t SetCommFeature(uint16_t fid, uint8_t nbytes, uint8_t *dataptr);
|
||||
uint8_t GetCommFeature(uint16_t fid, uint8_t nbytes, uint8_t *dataptr);
|
||||
uint8_t ClearCommFeature(uint16_t fid);
|
||||
uint8_t SetLineCoding(const LINE_CODING *dataptr);
|
||||
uint8_t GetLineCoding(LINE_CODING *dataptr);
|
||||
uint8_t SetControlLineState(uint8_t state);
|
||||
uint8_t SendBreak(uint16_t duration);
|
||||
|
||||
// Methods for recieving and sending data
|
||||
uint8_t RcvData(uint16_t *nbytesptr, uint8_t *dataptr);
|
||||
uint8_t SndData(uint16_t nbytes, uint8_t *dataptr);
|
||||
// Methods for recieving and sending data
|
||||
uint8_t RcvData(uint16_t *nbytesptr, uint8_t *dataptr);
|
||||
uint8_t SndData(uint16_t nbytes, uint8_t *dataptr);
|
||||
|
||||
// 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 bool isReady() { return ready; };
|
||||
// USBDeviceConfig implementation
|
||||
virtual uint8_t Init(uint8_t parent, uint8_t port, bool lowspeed);
|
||||
virtual uint8_t Release();
|
||||
virtual uint8_t Poll();
|
||||
|
||||
// UsbConfigXtracter implementation
|
||||
virtual void EndpointXtract(uint8_t conf, uint8_t iface, uint8_t alt, uint8_t proto, const USB_ENDPOINT_DESCRIPTOR *ep);
|
||||
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);
|
||||
};
|
||||
|
||||
#endif // __CDCACM_H__
|
452
cdcftdi.cpp
452
cdcftdi.cpp
|
@ -13,336 +13,320 @@ 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;
|
||||
const uint8_t FTDI::epDataOutIndex = 2;
|
||||
const uint8_t FTDI::epInterruptInIndex = 3;
|
||||
const uint8_t FTDI::epDataInIndex = 1;
|
||||
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++)
|
||||
{
|
||||
epInfo[i].epAddr = 0;
|
||||
epInfo[i].maxPktSize = (i) ? 0 : 8;
|
||||
epInfo[i].epAttribs = 0;
|
||||
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;
|
||||
|
||||
//if (!i)
|
||||
epInfo[i].bmNakPower = USB_NAK_MAX_POWER;
|
||||
}
|
||||
if (pUsb)
|
||||
pUsb->RegisterDeviceClass(this);
|
||||
//if (!i)
|
||||
epInfo[i].bmNakPower = USB_NAK_MAX_POWER;
|
||||
}
|
||||
if (pUsb)
|
||||
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 buf[constBufSize];
|
||||
uint8_t rcode;
|
||||
UsbDevice *p = NULL;
|
||||
EpInfo *oldep_ptr = NULL;
|
||||
//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_conf; // number of configurations
|
||||
//uint8_t num_of_intf; // number of interfaces
|
||||
|
||||
AddressPool &addrPool = pUsb->GetAddressPool();
|
||||
AddressPool &addrPool = pUsb->GetAddressPool();
|
||||
|
||||
USBTRACE("FTDI Init\r\n");
|
||||
USBTRACE("FTDI Init\r\n");
|
||||
|
||||
if (bAddress)
|
||||
return USB_ERROR_CLASS_INSTANCE_ALREADY_IN_USE;
|
||||
if (bAddress)
|
||||
return USB_ERROR_CLASS_INSTANCE_ALREADY_IN_USE;
|
||||
|
||||
// Get pointer to pseudo device with address 0 assigned
|
||||
p = addrPool.GetUsbDevicePtr(0);
|
||||
// Get pointer to pseudo device with address 0 assigned
|
||||
p = addrPool.GetUsbDevicePtr(0);
|
||||
|
||||
if (!p)
|
||||
return USB_ERROR_ADDRESS_NOT_FOUND_IN_POOL;
|
||||
if (!p)
|
||||
return USB_ERROR_ADDRESS_NOT_FOUND_IN_POOL;
|
||||
|
||||
if (!p->epinfo)
|
||||
{
|
||||
USBTRACE("epinfo\r\n");
|
||||
return USB_ERROR_EPINFO_IS_NULL;
|
||||
}
|
||||
if (!p->epinfo) {
|
||||
USBTRACE("epinfo\r\n");
|
||||
return USB_ERROR_EPINFO_IS_NULL;
|
||||
}
|
||||
|
||||
// Save old pointer to EP_RECORD of address 0
|
||||
oldep_ptr = p->epinfo;
|
||||
// Save old pointer to EP_RECORD of address 0
|
||||
oldep_ptr = p->epinfo;
|
||||
|
||||
// Temporary assign new pointer to epInfo to p->epinfo in order to avoid toggle inconsistence
|
||||
p->epinfo = epInfo;
|
||||
// Temporary assign new pointer to epInfo to p->epinfo in order to avoid toggle inconsistence
|
||||
p->epinfo = epInfo;
|
||||
|
||||
p->lowspeed = lowspeed;
|
||||
p->lowspeed = lowspeed;
|
||||
|
||||
// Get device descriptor
|
||||
rcode = pUsb->getDevDescr( 0, 0, sizeof(USB_DEVICE_DESCRIPTOR), (uint8_t*)buf );
|
||||
// Get device descriptor
|
||||
rcode = pUsb->getDevDescr(0, 0, sizeof (USB_DEVICE_DESCRIPTOR), (uint8_t*)buf);
|
||||
|
||||
// Restore p->epinfo
|
||||
p->epinfo = oldep_ptr;
|
||||
// Restore p->epinfo
|
||||
p->epinfo = oldep_ptr;
|
||||
|
||||
if( rcode )
|
||||
goto FailGetDevDescr;
|
||||
if (rcode)
|
||||
goto FailGetDevDescr;
|
||||
|
||||
if (((USB_DEVICE_DESCRIPTOR*)buf)->idVendor != FTDI_VID || ((USB_DEVICE_DESCRIPTOR*)buf)->idProduct != FTDI_PID)
|
||||
return USB_DEV_CONFIG_ERROR_DEVICE_NOT_SUPPORTED;
|
||||
if (((USB_DEVICE_DESCRIPTOR*)buf)->idVendor != FTDI_VID || ((USB_DEVICE_DESCRIPTOR*)buf)->idProduct != FTDI_PID)
|
||||
return USB_DEV_CONFIG_ERROR_DEVICE_NOT_SUPPORTED;
|
||||
|
||||
// Save type of FTDI chip
|
||||
wFTDIType = ((USB_DEVICE_DESCRIPTOR*)buf)->bcdDevice;
|
||||
// Save type of FTDI chip
|
||||
wFTDIType = ((USB_DEVICE_DESCRIPTOR*)buf)->bcdDevice;
|
||||
|
||||
// Allocate new address according to device class
|
||||
bAddress = addrPool.AllocAddress(parent, false, port);
|
||||
// Allocate new address according to device class
|
||||
bAddress = addrPool.AllocAddress(parent, false, port);
|
||||
|
||||
if (!bAddress)
|
||||
return USB_ERROR_OUT_OF_ADDRESS_SPACE_IN_POOL;
|
||||
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;
|
||||
// Extract Max Packet Size from the device descriptor
|
||||
epInfo[0].maxPktSize = (uint8_t)((USB_DEVICE_DESCRIPTOR*)buf)->bMaxPacketSize0;
|
||||
|
||||
// Assign new address to the device
|
||||
rcode = pUsb->setAddr( 0, 0, bAddress );
|
||||
// Assign new address to the device
|
||||
rcode = pUsb->setAddr(0, 0, bAddress);
|
||||
|
||||
if (rcode)
|
||||
{
|
||||
p->lowspeed = false;
|
||||
addrPool.FreeAddress(bAddress);
|
||||
bAddress = 0;
|
||||
USBTRACE2("setAddr:",rcode);
|
||||
return rcode;
|
||||
}
|
||||
if (rcode) {
|
||||
p->lowspeed = false;
|
||||
addrPool.FreeAddress(bAddress);
|
||||
bAddress = 0;
|
||||
USBTRACE2("setAddr:", rcode);
|
||||
return rcode;
|
||||
}
|
||||
|
||||
USBTRACE2("Addr:", bAddress);
|
||||
USBTRACE2("Addr:", bAddress);
|
||||
|
||||
p->lowspeed = false;
|
||||
p->lowspeed = false;
|
||||
|
||||
p = addrPool.GetUsbDevicePtr(bAddress);
|
||||
p = addrPool.GetUsbDevicePtr(bAddress);
|
||||
|
||||
if (!p)
|
||||
return USB_ERROR_ADDRESS_NOT_FOUND_IN_POOL;
|
||||
if (!p)
|
||||
return USB_ERROR_ADDRESS_NOT_FOUND_IN_POOL;
|
||||
|
||||
p->lowspeed = lowspeed;
|
||||
p->lowspeed = lowspeed;
|
||||
|
||||
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);
|
||||
// Assign epInfo to epinfo pointer
|
||||
rcode = pUsb->setEpInfoEntry(bAddress, 1, epInfo);
|
||||
|
||||
if (rcode)
|
||||
goto FailSetDevTblEntry;
|
||||
if (rcode)
|
||||
goto FailSetDevTblEntry;
|
||||
|
||||
USBTRACE2("NC:", num_of_conf);
|
||||
USBTRACE2("NC:", num_of_conf);
|
||||
|
||||
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);
|
||||
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);
|
||||
|
||||
rcode = pUsb->getConfDescr(bAddress, 0, i, &HexDump);
|
||||
rcode = pUsb->getConfDescr(bAddress, 0, i, &confDescrParser);
|
||||
rcode = pUsb->getConfDescr(bAddress, 0, i, &HexDump);
|
||||
|
||||
if (bNumEP > 1)
|
||||
break;
|
||||
} // for
|
||||
if (rcode)
|
||||
goto FailGetConfDescr;
|
||||
|
||||
if (bNumEP < 2)
|
||||
return USB_DEV_CONFIG_ERROR_DEVICE_NOT_SUPPORTED;
|
||||
rcode = pUsb->getConfDescr(bAddress, 0, i, &confDescrParser);
|
||||
|
||||
USBTRACE2("NumEP:", bNumEP);
|
||||
if (rcode)
|
||||
goto FailGetConfDescr;
|
||||
|
||||
// Assign epInfo to epinfo pointer
|
||||
rcode = pUsb->setEpInfoEntry(bAddress, bNumEP, epInfo);
|
||||
if (bNumEP > 1)
|
||||
break;
|
||||
} // for
|
||||
|
||||
USBTRACE2("Conf:", bConfNum);
|
||||
if (bNumEP < 2)
|
||||
return USB_DEV_CONFIG_ERROR_DEVICE_NOT_SUPPORTED;
|
||||
|
||||
// Set Configuration Value
|
||||
rcode = pUsb->setConf(bAddress, 0, bConfNum);
|
||||
USBTRACE2("NumEP:", bNumEP);
|
||||
|
||||
if (rcode)
|
||||
goto FailSetConfDescr;
|
||||
// Assign epInfo to epinfo pointer
|
||||
rcode = pUsb->setEpInfoEntry(bAddress, bNumEP, epInfo);
|
||||
|
||||
rcode = pAsync->OnInit(this);
|
||||
USBTRACE2("Conf:", bConfNum);
|
||||
|
||||
if (rcode)
|
||||
goto FailOnInit;
|
||||
// Set Configuration Value
|
||||
rcode = pUsb->setConf(bAddress, 0, bConfNum);
|
||||
|
||||
USBTRACE("FTDI configured\r\n");
|
||||
if (rcode)
|
||||
goto FailSetConfDescr;
|
||||
|
||||
bPollEnable = true;
|
||||
return 0;
|
||||
rcode = pAsync->OnInit(this);
|
||||
|
||||
if (rcode)
|
||||
goto FailOnInit;
|
||||
|
||||
USBTRACE("FTDI configured\r\n");
|
||||
|
||||
bPollEnable = true;
|
||||
return 0;
|
||||
|
||||
FailGetDevDescr:
|
||||
USBTRACE("getDevDescr:");
|
||||
goto Fail;
|
||||
USBTRACE("getDevDescr:");
|
||||
goto Fail;
|
||||
|
||||
FailSetDevTblEntry:
|
||||
USBTRACE("setDevTblEn:");
|
||||
goto Fail;
|
||||
USBTRACE("setDevTblEn:");
|
||||
goto Fail;
|
||||
|
||||
FailGetConfDescr:
|
||||
USBTRACE("getConf:");
|
||||
goto Fail;
|
||||
USBTRACE("getConf:");
|
||||
goto Fail;
|
||||
|
||||
FailSetConfDescr:
|
||||
USBTRACE("setConf:");
|
||||
goto Fail;
|
||||
|
||||
FailSetBaudRate:
|
||||
USBTRACE("SetBaudRate:");
|
||||
goto Fail;
|
||||
|
||||
FailSetFlowControl:
|
||||
USBTRACE("SetFlowControl:");
|
||||
goto Fail;
|
||||
USBTRACE("setConf:");
|
||||
goto Fail;
|
||||
|
||||
FailOnInit:
|
||||
USBTRACE("OnInit:");
|
||||
goto Fail;
|
||||
USBTRACE("OnInit:");
|
||||
goto Fail;
|
||||
|
||||
Fail:
|
||||
Serial.println(rcode, HEX);
|
||||
Release();
|
||||
return rcode;
|
||||
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;
|
||||
|
||||
bConfNum = conf;
|
||||
uint8_t index;
|
||||
|
||||
uint8_t index;
|
||||
if ((pep->bmAttributes & 0x03) == 3 && (pep->bEndpointAddress & 0x80) == 0x80)
|
||||
index = epInterruptInIndex;
|
||||
else
|
||||
if ((pep->bmAttributes & 0x02) == 2)
|
||||
index = ((pep->bEndpointAddress & 0x80) == 0x80) ? epDataInIndex : epDataOutIndex;
|
||||
else
|
||||
return;
|
||||
|
||||
if ((pep->bmAttributes & 0x03) == 3 && (pep->bEndpointAddress & 0x80) == 0x80)
|
||||
index = epInterruptInIndex;
|
||||
else
|
||||
if ((pep->bmAttributes & 0x02) == 2)
|
||||
index = ((pep->bEndpointAddress & 0x80) == 0x80) ? epDataInIndex : epDataOutIndex;
|
||||
else
|
||||
return;
|
||||
// Fill in the endpoint info structure
|
||||
epInfo[index].epAddr = (pep->bEndpointAddress & 0x0F);
|
||||
epInfo[index].maxPktSize = (uint8_t)pep->wMaxPacketSize;
|
||||
epInfo[index].epAttribs = 0;
|
||||
|
||||
// Fill in the endpoint info structure
|
||||
epInfo[index].epAddr = (pep->bEndpointAddress & 0x0F);
|
||||
epInfo[index].maxPktSize = (uint8_t)pep->wMaxPacketSize;
|
||||
//epInfo[index].epAttribs = 0;
|
||||
bNumEP++;
|
||||
|
||||
bNumEP ++;
|
||||
|
||||
PrintEndpointDescriptor(pep);
|
||||
PrintEndpointDescriptor(pep);
|
||||
}
|
||||
|
||||
uint8_t FTDI::Release()
|
||||
{
|
||||
pUsb->GetAddressPool().FreeAddress(bAddress);
|
||||
uint8_t FTDI::Release() {
|
||||
pUsb->GetAddressPool().FreeAddress(bAddress);
|
||||
|
||||
bAddress = 0;
|
||||
bNumEP = 1;
|
||||
qNextPollTime = 0;
|
||||
bPollEnable = false;
|
||||
return 0;
|
||||
bAddress = 0;
|
||||
bNumEP = 1;
|
||||
qNextPollTime = 0;
|
||||
bPollEnable = false;
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint8_t FTDI::Poll()
|
||||
{
|
||||
uint8_t rcode = 0;
|
||||
uint8_t FTDI::Poll() {
|
||||
uint8_t rcode = 0;
|
||||
|
||||
//if (!bPollEnable)
|
||||
// return 0;
|
||||
//if (!bPollEnable)
|
||||
// return 0;
|
||||
|
||||
//if (qNextPollTime <= millis())
|
||||
//{
|
||||
// Serial.println(bAddress, HEX);
|
||||
//if (qNextPollTime <= millis())
|
||||
//{
|
||||
// Serial.println(bAddress, HEX);
|
||||
|
||||
// qNextPollTime = millis() + 100;
|
||||
//}
|
||||
return rcode;
|
||||
// qNextPollTime = millis() + 100;
|
||||
//}
|
||||
return rcode;
|
||||
}
|
||||
|
||||
uint8_t FTDI::SetBaudRate(uint32_t baud)
|
||||
{
|
||||
uint16_t baud_value, baud_index = 0;
|
||||
uint32_t divisor3;
|
||||
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
|
||||
divisor3 = 48000000 / 2 / baud; // divisor shifted 3 bits to the left
|
||||
|
||||
if (wFTDIType == FT232AM)
|
||||
{
|
||||
if ((divisor3 & 0x7) == 7)
|
||||
divisor3 ++; // round x.7/8 up to x+1
|
||||
if (wFTDIType == FT232AM) {
|
||||
if ((divisor3 & 0x7) == 7)
|
||||
divisor3++; // round x.7/8 up to x+1
|
||||
|
||||
baud_value = divisor3 >> 3;
|
||||
divisor3 &= 0x7;
|
||||
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 != 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 };
|
||||
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};
|
||||
|
||||
baud_value = divisor3 >> 3;
|
||||
baud_value |= divfrac [divisor3 & 0x7] << 14;
|
||||
baud_index = divindex[divisor3 & 0x7];
|
||||
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 == 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 );
|
||||
/* Deal with special cases for highest baud rates. */
|
||||
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);
|
||||
}
|
||||
|
||||
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::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)
|
||||
{
|
||||
return pUsb->ctrlReq(bAddress, 0, bmREQ_FTDI_OUT, FTDI_SIO_SET_FLOW_CTRL, xon, xoff, protocol << 8, 0, 0, NULL, NULL);
|
||||
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)
|
||||
{
|
||||
return pUsb->ctrlReq(bAddress, 0, bmREQ_FTDI_OUT, FTDI_SIO_SET_DATA, databm & 0xff, databm >> 8, 0, 0, 0, NULL, NULL);
|
||||
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)
|
||||
{
|
||||
return pUsb->inTransfer(bAddress, epInfo[epDataInIndex].epAddr, bytes_rcvd, 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)
|
||||
{
|
||||
return pUsb->outTransfer(bAddress, epInfo[epDataOutIndex].epAddr, nbytes, 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);
|
||||
}
|
||||
|
|
71
cdcftdi.h
71
cdcftdi.h
|
@ -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,10 +94,9 @@ e-mail : support@circuitsathome.com
|
|||
|
||||
class FTDI;
|
||||
|
||||
class FTDIAsyncOper
|
||||
{
|
||||
class FTDIAsyncOper {
|
||||
public:
|
||||
virtual uint8_t OnInit(FTDI *pftdi) = 0;
|
||||
virtual uint8_t OnInit(FTDI *pftdi) = 0;
|
||||
};
|
||||
|
||||
|
||||
|
@ -105,46 +104,48 @@ public:
|
|||
// so only three endpoints are allocated.
|
||||
#define FTDI_MAX_ENDPOINTS 3
|
||||
|
||||
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
|
||||
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
|
||||
|
||||
FTDIAsyncOper *pAsync;
|
||||
USB *pUsb;
|
||||
uint8_t bAddress;
|
||||
uint8_t bConfNum; // configuration number
|
||||
uint8_t bNumIface; // number of interfaces in the configuration
|
||||
uint8_t bNumEP; // total number of EP in the configuration
|
||||
uint32_t qNextPollTime; // next poll time
|
||||
bool bPollEnable; // poll enable flag
|
||||
uint16_t wFTDIType; // Type of FTDI chip
|
||||
FTDIAsyncOper *pAsync;
|
||||
USB *pUsb;
|
||||
uint8_t bAddress;
|
||||
uint8_t bConfNum; // configuration number
|
||||
uint8_t bNumIface; // number of interfaces in the configuration
|
||||
uint8_t bNumEP; // total number of EP in the configuration
|
||||
uint32_t qNextPollTime; // next poll time
|
||||
bool bPollEnable; // poll enable flag
|
||||
uint16_t wFTDIType; // Type of FTDI chip
|
||||
|
||||
EpInfo epInfo[FTDI_MAX_ENDPOINTS];
|
||||
EpInfo epInfo[FTDI_MAX_ENDPOINTS];
|
||||
|
||||
void PrintEndpointDescriptor(const USB_ENDPOINT_DESCRIPTOR* ep_ptr);
|
||||
void PrintEndpointDescriptor(const USB_ENDPOINT_DESCRIPTOR* ep_ptr);
|
||||
|
||||
public:
|
||||
FTDI(USB *pusb, FTDIAsyncOper *pasync);
|
||||
FTDI(USB *pusb, FTDIAsyncOper *pasync);
|
||||
|
||||
uint8_t SetBaudRate(uint32_t baud);
|
||||
uint8_t SetModemControl(uint16_t control);
|
||||
uint8_t SetFlowControl(uint8_t protocol, uint8_t xon = 0x11, uint8_t xoff = 0x13);
|
||||
uint8_t SetData(uint16_t databm);
|
||||
uint8_t SetBaudRate(uint32_t baud);
|
||||
uint8_t SetModemControl(uint16_t control);
|
||||
uint8_t SetFlowControl(uint8_t protocol, uint8_t xon = 0x11, uint8_t xoff = 0x13);
|
||||
uint8_t SetData(uint16_t databm);
|
||||
|
||||
// Methods for recieving and sending data
|
||||
uint8_t RcvData(uint16_t *bytes_rcvd, uint8_t *dataptr);
|
||||
uint8_t SndData(uint16_t nbytes, uint8_t *dataptr);
|
||||
// Methods for recieving and sending data
|
||||
uint8_t RcvData(uint16_t *bytes_rcvd, uint8_t *dataptr);
|
||||
uint8_t SndData(uint16_t nbytes, uint8_t *dataptr);
|
||||
|
||||
// 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; };
|
||||
// USBDeviceConfig implementation
|
||||
virtual uint8_t Init(uint8_t parent, uint8_t port, bool lowspeed);
|
||||
virtual uint8_t Release();
|
||||
virtual uint8_t Poll();
|
||||
|
||||
// UsbConfigXtracter implementation
|
||||
virtual void EndpointXtract(uint8_t conf, uint8_t iface, uint8_t alt, uint8_t proto, const USB_ENDPOINT_DESCRIPTOR *ep);
|
||||
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);
|
||||
};
|
||||
|
||||
#endif // __CDCFTDI_H__
|
256
cdcprolific.cpp
256
cdcprolific.cpp
|
@ -13,215 +13,173 @@ 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;
|
||||
uint8_t buf[constBufSize];
|
||||
uint8_t rcode;
|
||||
UsbDevice *p = NULL;
|
||||
EpInfo *oldep_ptr = NULL;
|
||||
uint8_t num_of_conf; // number of configurations
|
||||
|
||||
AddressPool &addrPool = pUsb->GetAddressPool();
|
||||
AddressPool &addrPool = pUsb->GetAddressPool();
|
||||
|
||||
USBTRACE("PL Init\r\n");
|
||||
USBTRACE("PL Init\r\n");
|
||||
|
||||
if (bAddress)
|
||||
return USB_ERROR_CLASS_INSTANCE_ALREADY_IN_USE;
|
||||
if (bAddress)
|
||||
return USB_ERROR_CLASS_INSTANCE_ALREADY_IN_USE;
|
||||
|
||||
// Get pointer to pseudo device with address 0 assigned
|
||||
p = addrPool.GetUsbDevicePtr(0);
|
||||
// Get pointer to pseudo device with address 0 assigned
|
||||
p = addrPool.GetUsbDevicePtr(0);
|
||||
|
||||
if (!p)
|
||||
return USB_ERROR_ADDRESS_NOT_FOUND_IN_POOL;
|
||||
if (!p)
|
||||
return USB_ERROR_ADDRESS_NOT_FOUND_IN_POOL;
|
||||
|
||||
if (!p->epinfo)
|
||||
{
|
||||
USBTRACE("epinfo\r\n");
|
||||
return USB_ERROR_EPINFO_IS_NULL;
|
||||
}
|
||||
if (!p->epinfo) {
|
||||
USBTRACE("epinfo\r\n");
|
||||
return USB_ERROR_EPINFO_IS_NULL;
|
||||
}
|
||||
|
||||
// Save old pointer to EP_RECORD of address 0
|
||||
oldep_ptr = p->epinfo;
|
||||
// Save old pointer to EP_RECORD of address 0
|
||||
oldep_ptr = p->epinfo;
|
||||
|
||||
// Temporary assign new pointer to epInfo to p->epinfo in order to avoid toggle inconsistence
|
||||
p->epinfo = epInfo;
|
||||
// Temporary assign new pointer to epInfo to p->epinfo in order to avoid toggle inconsistence
|
||||
p->epinfo = epInfo;
|
||||
|
||||
p->lowspeed = lowspeed;
|
||||
p->lowspeed = lowspeed;
|
||||
|
||||
// Get device descriptor
|
||||
rcode = pUsb->getDevDescr( 0, 0, sizeof(USB_DEVICE_DESCRIPTOR), (uint8_t*)buf );
|
||||
// Get device descriptor
|
||||
rcode = pUsb->getDevDescr(0, 0, sizeof (USB_DEVICE_DESCRIPTOR), (uint8_t*)buf);
|
||||
|
||||
// Restore p->epinfo
|
||||
p->epinfo = oldep_ptr;
|
||||
// Restore p->epinfo
|
||||
p->epinfo = oldep_ptr;
|
||||
|
||||
if( rcode )
|
||||
goto FailGetDevDescr;
|
||||
if (rcode)
|
||||
goto FailGetDevDescr;
|
||||
|
||||
if (((USB_DEVICE_DESCRIPTOR*)buf)->idVendor != PL_VID && ((USB_DEVICE_DESCRIPTOR*)buf)->idProduct != PL_PID ) {
|
||||
return USB_DEV_CONFIG_ERROR_DEVICE_NOT_SUPPORTED;
|
||||
}
|
||||
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 */
|
||||
// Save type of PL chip
|
||||
wPLType = ((USB_DEVICE_DESCRIPTOR*)buf)->bcdDevice;
|
||||
|
||||
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;
|
||||
}
|
||||
// Allocate new address according to device class
|
||||
bAddress = addrPool.AllocAddress(parent, false, port);
|
||||
|
||||
// Allocate new address according to device class
|
||||
bAddress = addrPool.AllocAddress(parent, false, port);
|
||||
if (!bAddress)
|
||||
return USB_ERROR_OUT_OF_ADDRESS_SPACE_IN_POOL;
|
||||
|
||||
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;
|
||||
|
||||
// Extract Max Packet Size from the device descriptor
|
||||
epInfo[0].maxPktSize = (uint8_t)((USB_DEVICE_DESCRIPTOR*)buf)->bMaxPacketSize0;
|
||||
// Assign new address to the device
|
||||
rcode = pUsb->setAddr(0, 0, bAddress);
|
||||
|
||||
// Assign new address to the device
|
||||
rcode = pUsb->setAddr( 0, 0, bAddress );
|
||||
if (rcode) {
|
||||
p->lowspeed = false;
|
||||
addrPool.FreeAddress(bAddress);
|
||||
bAddress = 0;
|
||||
USBTRACE2("setAddr:", rcode);
|
||||
return rcode;
|
||||
}
|
||||
|
||||
if (rcode)
|
||||
{
|
||||
p->lowspeed = false;
|
||||
addrPool.FreeAddress(bAddress);
|
||||
bAddress = 0;
|
||||
USBTRACE2("setAddr:",rcode);
|
||||
return rcode;
|
||||
}
|
||||
USBTRACE2("Addr:", bAddress);
|
||||
|
||||
USBTRACE2("Addr:", bAddress);
|
||||
p->lowspeed = false;
|
||||
|
||||
p->lowspeed = false;
|
||||
p = addrPool.GetUsbDevicePtr(bAddress);
|
||||
|
||||
p = addrPool.GetUsbDevicePtr(bAddress);
|
||||
if (!p)
|
||||
return USB_ERROR_ADDRESS_NOT_FOUND_IN_POOL;
|
||||
|
||||
if (!p)
|
||||
return USB_ERROR_ADDRESS_NOT_FOUND_IN_POOL;
|
||||
p->lowspeed = lowspeed;
|
||||
|
||||
p->lowspeed = lowspeed;
|
||||
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);
|
||||
|
||||
// Assign epInfo to epinfo pointer
|
||||
rcode = pUsb->setEpInfoEntry(bAddress, 1, epInfo);
|
||||
if (rcode)
|
||||
goto FailSetDevTblEntry;
|
||||
|
||||
if (rcode)
|
||||
goto FailSetDevTblEntry;
|
||||
USBTRACE2("NC:", num_of_conf);
|
||||
|
||||
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);
|
||||
|
||||
//rcode = pUsb->getConfDescr(bAddress, 0, i, &HexDump);
|
||||
rcode = pUsb->getConfDescr(bAddress, 0, i, &confDescrParser);
|
||||
if (rcode)
|
||||
goto FailGetConfDescr;
|
||||
|
||||
if (bNumEP > 1)
|
||||
break;
|
||||
} // for
|
||||
rcode = pUsb->getConfDescr(bAddress, 0, i, &confDescrParser);
|
||||
|
||||
if ( bNumEP < 2 )
|
||||
return USB_DEV_CONFIG_ERROR_DEVICE_NOT_SUPPORTED;
|
||||
if (rcode)
|
||||
goto FailGetConfDescr;
|
||||
|
||||
// Assign epInfo to epinfo pointer
|
||||
rcode = pUsb->setEpInfoEntry( bAddress, bNumEP, epInfo );
|
||||
if (bNumEP > 1)
|
||||
break;
|
||||
} // for
|
||||
|
||||
USBTRACE2("Conf:", bConfNum);
|
||||
if (bNumEP < 2)
|
||||
return USB_DEV_CONFIG_ERROR_DEVICE_NOT_SUPPORTED;
|
||||
|
||||
// Set Configuration Value
|
||||
rcode = pUsb->setConf(bAddress, 0, bConfNum);
|
||||
// Assign epInfo to epinfo pointer
|
||||
rcode = pUsb->setEpInfoEntry(bAddress, bNumEP, epInfo);
|
||||
|
||||
if (rcode)
|
||||
goto FailSetConfDescr;
|
||||
USBTRACE2("Conf:", bConfNum);
|
||||
|
||||
#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
|
||||
// Set Configuration Value
|
||||
rcode = pUsb->setConf(bAddress, 0, bConfNum);
|
||||
|
||||
/* calling post-init callback */
|
||||
rcode = pAsync->OnInit(this);
|
||||
if (rcode)
|
||||
goto FailSetConfDescr;
|
||||
|
||||
if (rcode)
|
||||
goto FailOnInit;
|
||||
rcode = pAsync->OnInit(this);
|
||||
|
||||
USBTRACE("PL configured\r\n");
|
||||
if (rcode)
|
||||
goto FailOnInit;
|
||||
|
||||
//bPollEnable = true;
|
||||
ready = true;
|
||||
return 0;
|
||||
USBTRACE("PL configured\r\n");
|
||||
|
||||
bPollEnable = true;
|
||||
return 0;
|
||||
|
||||
FailGetDevDescr:
|
||||
USBTRACE("getDevDescr:");
|
||||
goto Fail;
|
||||
USBTRACE("getDevDescr:");
|
||||
goto Fail;
|
||||
|
||||
FailSetDevTblEntry:
|
||||
USBTRACE("setDevTblEn:");
|
||||
goto Fail;
|
||||
USBTRACE("setDevTblEn:");
|
||||
goto Fail;
|
||||
|
||||
FailGetConfDescr:
|
||||
USBTRACE("getConf:");
|
||||
goto Fail;
|
||||
USBTRACE("getConf:");
|
||||
goto Fail;
|
||||
|
||||
FailSetConfDescr:
|
||||
USBTRACE("setConf:");
|
||||
goto Fail;
|
||||
|
||||
FailSetControlLineState:
|
||||
USBTRACE("SetControlLineState:");
|
||||
goto Fail;
|
||||
|
||||
FailSetLineCoding:
|
||||
USBTRACE("SetLineCoding:");
|
||||
goto Fail;
|
||||
USBTRACE("setConf:");
|
||||
goto Fail;
|
||||
|
||||
FailOnInit:
|
||||
USBTRACE("OnInit:");
|
||||
goto Fail;
|
||||
USBTRACE("OnInit:");
|
||||
goto Fail;
|
||||
|
||||
Fail:
|
||||
Serial.println(rcode, HEX);
|
||||
Release();
|
||||
return rcode;
|
||||
PrintHex<uint8_t > (rcode, 0x80);
|
||||
Notify(PSTR("\r\n"), 0x80);
|
||||
//Serial.println(rcode, HEX);
|
||||
Release();
|
||||
return rcode;
|
||||
}
|
||||
|
||||
//uint8_t PL::Poll()
|
||||
|
|
|
@ -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
|
||||
{
|
||||
kXOnSent = -2,
|
||||
kXOffSent = -1,
|
||||
kXO_Idle = 0,
|
||||
kXOffNeeded = 1,
|
||||
kXOnNeeded = 2
|
||||
} ;
|
||||
enum tXO_State {
|
||||
kXOnSent = -2,
|
||||
kXOffSent = -1,
|
||||
kXO_Idle = 0,
|
||||
kXOffNeeded = 1,
|
||||
kXOnNeeded = 2
|
||||
};
|
||||
|
||||
#define kStateTransientMask 0x74
|
||||
#define kBreakError 0x04
|
||||
|
@ -125,55 +123,31 @@ enum tXO_State
|
|||
#define RESET_DOWNSTREAM_DATA_PIPE 0x08
|
||||
#define RESET_UPSTREAM_DATA_PIPE 0x09
|
||||
|
||||
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 */
|
||||
rev_H
|
||||
enum pl2303_type {
|
||||
unknown,
|
||||
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 */
|
||||
rev_H
|
||||
};
|
||||
|
||||
|
||||
#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);
|
||||
PL2303(USB *pusb, CDCAsyncOper *pasync);
|
||||
|
||||
// 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; };
|
||||
// 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; };
|
||||
|
||||
//// 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 );
|
||||
//// UsbConfigXtracter implementation
|
||||
//virtual void EndpointXtract(uint8_t conf, uint8_t iface, uint8_t alt, uint8_t proto, const USB_ENDPOINT_DESCRIPTOR *ep);
|
||||
};
|
||||
|
||||
/* 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__
|
288
confdescparser.h
288
confdescparser.h
|
@ -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,12 +27,11 @@ 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;
|
||||
virtual void EndpointXtract(uint8_t conf, uint8_t iface, uint8_t alt, uint8_t proto, const USB_ENDPOINT_DESCRIPTOR *ep) = 0;
|
||||
//virtual void ConfigXtract(const USB_CONFIGURATION_DESCRIPTOR *conf) = 0;
|
||||
//virtual void InterfaceXtract(uint8_t conf, const USB_INTERFACE_DESCRIPTOR *iface) = 0;
|
||||
virtual void EndpointXtract(uint8_t conf, uint8_t iface, uint8_t alt, uint8_t proto, const USB_ENDPOINT_DESCRIPTOR *ep) = 0;
|
||||
};
|
||||
|
||||
#define CP_MASK_COMPARE_CLASS 1
|
||||
|
@ -41,180 +40,173 @@ 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
|
||||
{
|
||||
UsbConfigXtracter *theXtractor;
|
||||
MultiValueBuffer theBuffer;
|
||||
MultiByteValueParser valParser;
|
||||
ByteSkipper theSkipper;
|
||||
uint8_t varBuffer[16 /*sizeof(USB_CONFIGURATION_DESCRIPTOR)*/];
|
||||
class ConfigDescParser : public USBReadParser {
|
||||
UsbConfigXtracter *theXtractor;
|
||||
MultiValueBuffer theBuffer;
|
||||
MultiByteValueParser valParser;
|
||||
ByteSkipper theSkipper;
|
||||
uint8_t varBuffer[16 /*sizeof(USB_CONFIGURATION_DESCRIPTOR)*/];
|
||||
|
||||
uint8_t stateParseDescr; // ParseDescriptor state
|
||||
uint8_t stateParseDescr; // ParseDescriptor state
|
||||
|
||||
uint8_t dscrLen; // Descriptor length
|
||||
uint8_t dscrType; // Descriptor type
|
||||
uint8_t dscrLen; // Descriptor length
|
||||
uint8_t dscrType; // Descriptor type
|
||||
|
||||
bool isGoodInterface; // Apropriate interface flag
|
||||
uint8_t confValue; // Configuration value
|
||||
uint8_t protoValue; // Protocol value
|
||||
uint8_t ifaceNumber; // Interface number
|
||||
uint8_t ifaceAltSet; // Interface alternate settings
|
||||
bool isGoodInterface; // Apropriate interface flag
|
||||
uint8_t confValue; // Configuration value
|
||||
uint8_t protoValue; // Protocol value
|
||||
uint8_t ifaceNumber; // Interface number
|
||||
uint8_t ifaceAltSet; // Interface alternate settings
|
||||
|
||||
bool ParseDescriptor(uint8_t **pp, uint16_t *pcntdn);
|
||||
bool ParseDescriptor(uint8_t **pp, uint16_t *pcntdn);
|
||||
|
||||
void PrintHidDescriptor(const USB_HID_DESCRIPTOR *pDesc);
|
||||
void PrintHidDescriptor(const USB_HID_DESCRIPTOR *pDesc);
|
||||
|
||||
public:
|
||||
ConfigDescParser(UsbConfigXtracter *xtractor);
|
||||
virtual void Parse(const uint16_t len, const uint8_t *pbuf, const uint16_t &offset);
|
||||
ConfigDescParser(UsbConfigXtracter *xtractor);
|
||||
virtual void Parse(const uint16_t len, const uint8_t *pbuf, const uint16_t &offset);
|
||||
};
|
||||
|
||||
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)
|
||||
{
|
||||
theBuffer.pValue = varBuffer;
|
||||
valParser.Initialize(&theBuffer);
|
||||
theSkipper.Initialize(&theBuffer);
|
||||
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))
|
||||
return;
|
||||
while(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)
|
||||
{
|
||||
case 0:
|
||||
theBuffer.valueSize = 2;
|
||||
valParser.Initialize(&theBuffer);
|
||||
stateParseDescr = 1;
|
||||
case 1:
|
||||
if (!valParser.Parse(pp, pcntdn))
|
||||
return false;
|
||||
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
|
||||
// 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
|
||||
// in the buffer.
|
||||
theBuffer.pValue = varBuffer + 2;
|
||||
stateParseDescr = 3;
|
||||
case 3:
|
||||
switch (dscrType)
|
||||
{
|
||||
case USB_DESCRIPTOR_INTERFACE:
|
||||
isGoodInterface = false;
|
||||
case USB_DESCRIPTOR_CONFIGURATION:
|
||||
theBuffer.valueSize = sizeof(USB_CONFIGURATION_DESCRIPTOR) - 2;
|
||||
break;
|
||||
case USB_DESCRIPTOR_ENDPOINT:
|
||||
theBuffer.valueSize = sizeof(USB_ENDPOINT_DESCRIPTOR) - 2;
|
||||
break;
|
||||
case HID_DESCRIPTOR_HID:
|
||||
theBuffer.valueSize = dscrLen - 2;
|
||||
break;
|
||||
}
|
||||
valParser.Initialize(&theBuffer);
|
||||
stateParseDescr = 4;
|
||||
case 4:
|
||||
switch (dscrType)
|
||||
{
|
||||
case USB_DESCRIPTOR_CONFIGURATION:
|
||||
if (!valParser.Parse(pp, pcntdn))
|
||||
return false;
|
||||
confValue = ((USB_CONFIGURATION_DESCRIPTOR*)varBuffer)->bConfigurationValue;
|
||||
break;
|
||||
case USB_DESCRIPTOR_INTERFACE:
|
||||
if (!valParser.Parse(pp, pcntdn))
|
||||
return false;
|
||||
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)
|
||||
break;
|
||||
if ((MASK & CP_MASK_COMPARE_PROTOCOL) && ((USB_INTERFACE_DESCRIPTOR*)varBuffer)->bInterfaceProtocol != PROTOCOL_ID)
|
||||
break;
|
||||
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))
|
||||
return false;
|
||||
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 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
|
||||
// in the buffer.
|
||||
theBuffer.pValue = varBuffer + 2;
|
||||
stateParseDescr = 3;
|
||||
case 3:
|
||||
switch(dscrType) {
|
||||
case USB_DESCRIPTOR_INTERFACE:
|
||||
isGoodInterface = false;
|
||||
case USB_DESCRIPTOR_CONFIGURATION:
|
||||
theBuffer.valueSize = sizeof(USB_CONFIGURATION_DESCRIPTOR) - 2;
|
||||
break;
|
||||
case USB_DESCRIPTOR_ENDPOINT:
|
||||
theBuffer.valueSize = sizeof(USB_ENDPOINT_DESCRIPTOR) - 2;
|
||||
break;
|
||||
case HID_DESCRIPTOR_HID:
|
||||
theBuffer.valueSize = dscrLen - 2;
|
||||
break;
|
||||
}
|
||||
valParser.Initialize(&theBuffer);
|
||||
stateParseDescr = 4;
|
||||
case 4:
|
||||
switch(dscrType) {
|
||||
case USB_DESCRIPTOR_CONFIGURATION:
|
||||
if(!valParser.Parse(pp, pcntdn))
|
||||
return false;
|
||||
confValue = ((USB_CONFIGURATION_DESCRIPTOR*) varBuffer)->bConfigurationValue;
|
||||
break;
|
||||
case USB_DESCRIPTOR_INTERFACE:
|
||||
if(!valParser.Parse(pp, pcntdn))
|
||||
return false;
|
||||
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)
|
||||
break;
|
||||
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;
|
||||
break;
|
||||
case USB_DESCRIPTOR_ENDPOINT:
|
||||
if (!valParser.Parse(pp, pcntdn))
|
||||
return false;
|
||||
if (isGoodInterface)
|
||||
if (theXtractor)
|
||||
theXtractor->EndpointXtract(confValue, ifaceNumber, ifaceAltSet, protoValue, (USB_ENDPOINT_DESCRIPTOR*)varBuffer);
|
||||
break;
|
||||
//case HID_DESCRIPTOR_HID:
|
||||
// if (!valParser.Parse(pp, pcntdn))
|
||||
// return false;
|
||||
// PrintHidDescriptor((const USB_HID_DESCRIPTOR*)varBuffer);
|
||||
// break;
|
||||
default:
|
||||
if (!theSkipper.Skip(pp, pcntdn, dscrLen-2))
|
||||
return false;
|
||||
}
|
||||
theBuffer.pValue = varBuffer;
|
||||
stateParseDescr = 0;
|
||||
}
|
||||
return true;
|
||||
isGoodInterface = true;
|
||||
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))
|
||||
return false;
|
||||
if(isGoodInterface)
|
||||
if(theXtractor)
|
||||
theXtractor->EndpointXtract(confValue, ifaceNumber, ifaceAltSet, protoValue, (USB_ENDPOINT_DESCRIPTOR*) varBuffer);
|
||||
break;
|
||||
//case HID_DESCRIPTOR_HID:
|
||||
// if (!valParser.Parse(pp, pcntdn))
|
||||
// return false;
|
||||
// PrintHidDescriptor((const USB_HID_DESCRIPTOR*)varBuffer);
|
||||
// break;
|
||||
default:
|
||||
if(!theSkipper.Skip(pp, pcntdn, dscrLen - 2))
|
||||
return false;
|
||||
}
|
||||
theBuffer.pValue = varBuffer;
|
||||
stateParseDescr = 0;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
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);
|
||||
//
|
||||
//Notify(PSTR("\r\nwDescriptorLength:\t"));
|
||||
//PrintHex<uint16_t>(pDesc->wDescriptorLength);
|
||||
//Notify(PSTR("\r\nbDescrType:\t\t"));
|
||||
//PrintHex<uint8_t>(pDesc->bDescrType);
|
||||
//
|
||||
//Notify(PSTR("\r\nwDescriptorLength:\t"));
|
||||
//PrintHex<uint16_t>(pDesc->wDescriptorLength);
|
||||
|
||||
for (uint8_t i=0; i<pDesc->bNumDescriptors; i++)
|
||||
{
|
||||
HID_CLASS_DESCRIPTOR_LEN_AND_TYPE *pLT = (HID_CLASS_DESCRIPTOR_LEN_AND_TYPE*)&(pDesc->bDescrType);
|
||||
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\n"));
|
||||
Notify(PSTR("\r\nwDescriptorLength:\t"), 0x80);
|
||||
PrintHex<uint16_t > (pLT[i].wDescriptorLength, 0x80);
|
||||
}
|
||||
Notify(PSTR("\r\n"), 0x80);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -21,96 +21,98 @@
|
|||
/*
|
||||
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 {
|
||||
LED1 = 0,
|
||||
LED2 = 1,
|
||||
LED3 = 2,
|
||||
LED4 = 3,
|
||||
LED1 = 0,
|
||||
LED2 = 1,
|
||||
LED3 = 2,
|
||||
LED4 = 3,
|
||||
|
||||
LED5 = 4,
|
||||
LED6 = 5,
|
||||
LED7 = 6,
|
||||
LED8 = 7,
|
||||
LED9 = 8,
|
||||
LED10 = 9,
|
||||
/** Used to blink all LEDs on the Xbox controller */
|
||||
ALL = 4,
|
||||
LED5 = 4,
|
||||
LED6 = 5,
|
||||
LED7 = 6,
|
||||
LED8 = 7,
|
||||
LED9 = 8,
|
||||
LED10 = 9,
|
||||
/** 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 {
|
||||
/**@{*/
|
||||
/** These buttons are available on all the the controllers */
|
||||
UP = 0,
|
||||
RIGHT = 1,
|
||||
DOWN = 2,
|
||||
LEFT = 3,
|
||||
/**@}*/
|
||||
/**@{*/
|
||||
/** These buttons are available on all the the controllers */
|
||||
UP = 0,
|
||||
RIGHT = 1,
|
||||
DOWN = 2,
|
||||
LEFT = 3,
|
||||
/**@}*/
|
||||
|
||||
/**@{*/
|
||||
/** Wii buttons */
|
||||
PLUS = 5,
|
||||
TWO = 6,
|
||||
ONE = 7,
|
||||
MINUS = 8,
|
||||
HOME = 9,
|
||||
Z = 10,
|
||||
C = 11,
|
||||
B = 12,
|
||||
A = 13,
|
||||
/**@}*/
|
||||
/**@{*/
|
||||
/** Wii buttons */
|
||||
PLUS = 5,
|
||||
TWO = 6,
|
||||
ONE = 7,
|
||||
MINUS = 8,
|
||||
HOME = 9,
|
||||
Z = 10,
|
||||
C = 11,
|
||||
B = 12,
|
||||
A = 13,
|
||||
/**@}*/
|
||||
|
||||
/**@{*/
|
||||
/** These are only available on the Wii U Pro Controller */
|
||||
L = 16,
|
||||
R = 17,
|
||||
ZL = 18,
|
||||
ZR = 19,
|
||||
/**@}*/
|
||||
/**@{*/
|
||||
/** These are only available on the Wii U Pro Controller */
|
||||
L = 16,
|
||||
R = 17,
|
||||
ZL = 18,
|
||||
ZR = 19,
|
||||
/**@}*/
|
||||
|
||||
/**@{*/
|
||||
/** PS3 controllers buttons */
|
||||
SELECT = 4,
|
||||
START = 5,
|
||||
L3 = 6,
|
||||
R3 = 7,
|
||||
/**@{*/
|
||||
/** PS3 controllers buttons */
|
||||
SELECT = 4,
|
||||
START = 5,
|
||||
L3 = 6,
|
||||
R3 = 7,
|
||||
|
||||
L2 = 8,
|
||||
R2 = 9,
|
||||
L1 = 10,
|
||||
R1 = 11,
|
||||
TRIANGLE = 12,
|
||||
CIRCLE = 13,
|
||||
CROSS = 14,
|
||||
SQUARE = 15,
|
||||
L2 = 8,
|
||||
R2 = 9,
|
||||
L1 = 10,
|
||||
R1 = 11,
|
||||
TRIANGLE = 12,
|
||||
CIRCLE = 13,
|
||||
CROSS = 14,
|
||||
SQUARE = 15,
|
||||
|
||||
PS = 16,
|
||||
PS = 16,
|
||||
|
||||
MOVE = 17, // Covers 12 bits - we only need to read the top 8
|
||||
T = 18, // Covers 12 bits - we only need to read the top 8
|
||||
/**@}*/
|
||||
MOVE = 17, // Covers 12 bits - we only need to read the top 8
|
||||
T = 18, // Covers 12 bits - we only need to read the top 8
|
||||
/**@}*/
|
||||
|
||||
/**@{*/
|
||||
/** Xbox buttons */
|
||||
BACK = 4,
|
||||
X = 14,
|
||||
Y = 15,
|
||||
XBOX = 16,
|
||||
SYNC = 17,
|
||||
/**@}*/
|
||||
/**@{*/
|
||||
/** Xbox buttons */
|
||||
BACK = 4,
|
||||
X = 14,
|
||||
Y = 15,
|
||||
XBOX = 16,
|
||||
SYNC = 17,
|
||||
/**@}*/
|
||||
};
|
||||
|
||||
/** Joysticks on the PS3 and Xbox controllers. */
|
||||
enum AnalogHat {
|
||||
/** Left joystick x-axis */
|
||||
LeftHatX = 0,
|
||||
/** Left joystick y-axis */
|
||||
LeftHatY = 1,
|
||||
/** Right joystick x-axis */
|
||||
RightHatX = 2,
|
||||
/** Right joystick y-axis */
|
||||
RightHatY = 3,
|
||||
/** Left joystick x-axis */
|
||||
LeftHatX = 0,
|
||||
/** Left joystick y-axis */
|
||||
LeftHatY = 1,
|
||||
/** Right joystick x-axis */
|
||||
RightHatX = 2,
|
||||
/** Right joystick y-axis */
|
||||
RightHatY = 3,
|
||||
};
|
||||
|
||||
#endif
|
51
hexdump.h
51
hexdump.h
|
@ -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,37 +22,38 @@ e-mail : support@circuitsathome.com
|
|||
#include "printhex.h"
|
||||
|
||||
template <class BASE_CLASS, class LEN_TYPE, class OFFSET_TYPE>
|
||||
class HexDumper : public BASE_CLASS
|
||||
{
|
||||
uint8_t byteCount;
|
||||
OFFSET_TYPE byteTotal;
|
||||
class HexDumper : public BASE_CLASS {
|
||||
uint8_t byteCount;
|
||||
OFFSET_TYPE byteTotal;
|
||||
|
||||
public:
|
||||
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);
|
||||
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);
|
||||
Serial.print(": ");
|
||||
}
|
||||
PrintHex<uint8_t>(pbuf[j]);
|
||||
Serial.print(" ");
|
||||
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(": ");
|
||||
}
|
||||
SerialPrintHex<uint8_t > (pbuf[j]);
|
||||
Serial.print(" ");
|
||||
|
||||
if (byteCount == 15)
|
||||
{
|
||||
Serial.println("");
|
||||
byteCount = 0xFF;
|
||||
}
|
||||
}
|
||||
if(byteCount == 15) {
|
||||
Serial.println("");
|
||||
byteCount = 0xFF;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif // __HEXDUMP_H__
|
136
hid.cpp
136
hid.cpp
|
@ -1,84 +1,82 @@
|
|||
#include "hid.h"
|
||||
|
||||
//get HID report descriptor
|
||||
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 HID::GetReportDescr(uint8_t ep, USBReadParser *parser) {
|
||||
const uint8_t constBufLen = 64;
|
||||
uint8_t buf[constBufLen];
|
||||
|
||||
//return ((rcode != hrSTALL) ? rcode : 0);
|
||||
return rcode;
|
||||
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;
|
||||
}
|
||||
//uint8_t HID::getHidDescr( uint8_t ep, uint16_t nbytes, uint8_t* dataptr )
|
||||
//{
|
||||
// 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);
|
||||
}
|
||||
|
|
84
hid.h
84
hid.h
|
@ -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,11 +108,10 @@ e-mail : support@circuitsathome.com
|
|||
#define HID_PROTOCOL_KEYBOARD 0x01
|
||||
#define HID_PROTOCOL_MOUSE 0x02
|
||||
|
||||
struct HidItemPrefix
|
||||
{
|
||||
uint8_t bSize : 2;
|
||||
uint8_t bType : 2;
|
||||
uint8_t bTag : 4;
|
||||
struct HidItemPrefix {
|
||||
uint8_t bSize : 2;
|
||||
uint8_t bType : 2;
|
||||
uint8_t bTag : 4;
|
||||
};
|
||||
|
||||
#define HID_ITEM_TYPE_MAIN 0
|
||||
|
@ -138,64 +137,65 @@ struct HidItemPrefix
|
|||
#define HID_MAIN_ITEM_COLLECTION_USAGE_SWITCH 5
|
||||
#define HID_MAIN_ITEM_COLLECTION_USAGE_MODIFIER 6
|
||||
|
||||
struct MainItemIOFeature
|
||||
{
|
||||
uint8_t bmIsConstantOrData : 1;
|
||||
uint8_t bmIsArrayOrVariable : 1;
|
||||
uint8_t bmIsRelativeOrAbsolute : 1;
|
||||
uint8_t bmIsWrapOrNoWrap : 1;
|
||||
uint8_t bmIsNonLonearOrLinear : 1;
|
||||
uint8_t bmIsNoPreferedOrPrefered : 1;
|
||||
uint8_t bmIsNullOrNoNull : 1;
|
||||
uint8_t bmIsVolatileOrNonVolatile : 1;
|
||||
struct MainItemIOFeature {
|
||||
uint8_t bmIsConstantOrData : 1;
|
||||
uint8_t bmIsArrayOrVariable : 1;
|
||||
uint8_t bmIsRelativeOrAbsolute : 1;
|
||||
uint8_t bmIsWrapOrNoWrap : 1;
|
||||
uint8_t bmIsNonLonearOrLinear : 1;
|
||||
uint8_t bmIsNoPreferedOrPrefered : 1;
|
||||
uint8_t bmIsNullOrNoNull : 1;
|
||||
uint8_t bmIsVolatileOrNonVolatile : 1;
|
||||
};
|
||||
|
||||
class HID;
|
||||
|
||||
class HIDReportParser
|
||||
{
|
||||
class HIDReportParser {
|
||||
public:
|
||||
virtual void Parse(HID *hid, bool is_rpt_id, uint8_t len, uint8_t *buf) = 0;
|
||||
virtual void Parse(HID *hid, bool is_rpt_id, uint8_t len, uint8_t *buf) = 0;
|
||||
};
|
||||
|
||||
#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
|
||||
USB *pUsb; // USB class instance pointer
|
||||
uint8_t bAddress; // address
|
||||
|
||||
protected:
|
||||
static const uint8_t epInterruptInIndex = 1; // InterruptIN endpoint index
|
||||
static const uint8_t epInterruptOutIndex = 2; // InterruptOUT endpoint index
|
||||
static const uint8_t epInterruptInIndex = 1; // InterruptIN endpoint index
|
||||
static const uint8_t epInterruptOutIndex = 2; // InterruptOUT endpoint index
|
||||
|
||||
static const uint8_t maxHidInterfaces = 3;
|
||||
static const uint8_t maxEpPerInterface = 2;
|
||||
static const uint8_t totalEndpoints = (maxHidInterfaces * maxEpPerInterface + 1);
|
||||
static const uint8_t maxHidInterfaces = 3;
|
||||
static const uint8_t maxEpPerInterface = 2;
|
||||
static const uint8_t totalEndpoints = (maxHidInterfaces * maxEpPerInterface + 1);
|
||||
|
||||
void PrintEndpointDescriptor(const USB_ENDPOINT_DESCRIPTOR* ep_ptr);
|
||||
void PrintHidDescriptor(const USB_HID_DESCRIPTOR *pDesc);
|
||||
void PrintEndpointDescriptor(const USB_ENDPOINT_DESCRIPTOR* ep_ptr);
|
||||
void PrintHidDescriptor(const USB_HID_DESCRIPTOR *pDesc);
|
||||
|
||||
virtual HIDReportParser* GetReportParser(uint8_t id);
|
||||
virtual HIDReportParser* GetReportParser(uint8_t id);
|
||||
|
||||
public:
|
||||
HID(USB *pusb) : pUsb(pusb) {};
|
||||
|
||||
const USB* GetUsb() { return pUsb; };
|
||||
virtual bool SetReportParser(uint8_t id, HIDReportParser *prs);
|
||||
HID(USB *pusb) : pUsb(pusb) {
|
||||
};
|
||||
|
||||
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 );
|
||||
const USB* GetUsb() {
|
||||
return pUsb;
|
||||
};
|
||||
virtual bool SetReportParser(uint8_t id, HIDReportParser *prs);
|
||||
|
||||
uint8_t GetReportDescr( uint8_t ep, USBReadParser *parser = NULL);
|
||||
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 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 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);
|
||||
};
|
||||
|
||||
#endif // __HID_H__
|
211
hidboot.cpp
211
hidboot.cpp
|
@ -13,142 +13,127 @@ 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)
|
||||
{
|
||||
MOUSEINFO *pmi = (MOUSEINFO*)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)
|
||||
OnLeftButtonDown(pmi);
|
||||
if (prevState.mouseInfo.bmLeftButton == 0 && pmi->bmLeftButton == 1)
|
||||
OnLeftButtonDown(pmi);
|
||||
|
||||
if (prevState.mouseInfo.bmLeftButton == 1 && pmi->bmLeftButton == 0)
|
||||
OnLeftButtonUp(pmi);
|
||||
if (prevState.mouseInfo.bmLeftButton == 1 && pmi->bmLeftButton == 0)
|
||||
OnLeftButtonUp(pmi);
|
||||
|
||||
if (prevState.mouseInfo.bmRightButton == 0 && pmi->bmRightButton == 1)
|
||||
OnRightButtonDown(pmi);
|
||||
if (prevState.mouseInfo.bmRightButton == 0 && pmi->bmRightButton == 1)
|
||||
OnRightButtonDown(pmi);
|
||||
|
||||
if (prevState.mouseInfo.bmRightButton == 1 && pmi->bmRightButton == 0)
|
||||
OnRightButtonUp(pmi);
|
||||
if (prevState.mouseInfo.bmRightButton == 1 && pmi->bmRightButton == 0)
|
||||
OnRightButtonUp(pmi);
|
||||
|
||||
if (prevState.mouseInfo.bmMiddleButton == 0 && pmi->bmMiddleButton == 1)
|
||||
OnMiddleButtonDown(pmi);
|
||||
if (prevState.mouseInfo.bmMiddleButton == 0 && pmi->bmMiddleButton == 1)
|
||||
OnMiddleButtonDown(pmi);
|
||||
|
||||
if (prevState.mouseInfo.bmMiddleButton == 1 && pmi->bmMiddleButton == 0)
|
||||
OnMiddleButtonUp(pmi);
|
||||
if (prevState.mouseInfo.bmMiddleButton == 1 && pmi->bmMiddleButton == 0)
|
||||
OnMiddleButtonUp(pmi);
|
||||
|
||||
if (prevState.mouseInfo.dX != pmi->dX || prevState.mouseInfo.dY != pmi->dY)
|
||||
OnMouseMove(pmi);
|
||||
if (prevState.mouseInfo.dX != pmi->dX || prevState.mouseInfo.dY != pmi->dY)
|
||||
OnMouseMove(pmi);
|
||||
|
||||
for (uint8_t i=0; i<3; i++)
|
||||
prevState.bInfo[i] = buf[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)
|
||||
{
|
||||
// On error - return
|
||||
if (buf[2] == 1)
|
||||
return;
|
||||
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++)
|
||||
{
|
||||
bool down = false;
|
||||
bool up = false;
|
||||
for (uint8_t i = 2; i < 8; i++) {
|
||||
bool down = false;
|
||||
bool up = false;
|
||||
|
||||
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)
|
||||
{
|
||||
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++)
|
||||
prevState.bInfo[i] = buf[i];
|
||||
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) {
|
||||
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++)
|
||||
prevState.bInfo[i] = buf[i];
|
||||
};
|
||||
|
||||
uint8_t KeyboardReportParser::HandleLockingKeys(HID *hid, uint8_t key)
|
||||
{
|
||||
uint8_t old_keys = kbdLockingKeys.bLeds;
|
||||
uint8_t KeyboardReportParser::HandleLockingKeys(HID *hid, uint8_t key) {
|
||||
uint8_t old_keys = kbdLockingKeys.bLeds;
|
||||
|
||||
switch (key)
|
||||
{
|
||||
case KEY_NUM_LOCK:
|
||||
kbdLockingKeys.kbdLeds.bmNumLock = ~kbdLockingKeys.kbdLeds.bmNumLock;
|
||||
break;
|
||||
case KEY_CAPS_LOCK:
|
||||
kbdLockingKeys.kbdLeds.bmCapsLock = ~kbdLockingKeys.kbdLeds.bmCapsLock;
|
||||
break;
|
||||
case KEY_SCROLL_LOCK:
|
||||
kbdLockingKeys.kbdLeds.bmScrollLock = ~kbdLockingKeys.kbdLeds.bmScrollLock;
|
||||
break;
|
||||
}
|
||||
switch (key) {
|
||||
case KEY_NUM_LOCK:
|
||||
kbdLockingKeys.kbdLeds.bmNumLock = ~kbdLockingKeys.kbdLeds.bmNumLock;
|
||||
break;
|
||||
case KEY_CAPS_LOCK:
|
||||
kbdLockingKeys.kbdLeds.bmCapsLock = ~kbdLockingKeys.kbdLeds.bmCapsLock;
|
||||
break;
|
||||
case KEY_SCROLL_LOCK:
|
||||
kbdLockingKeys.kbdLeds.bmScrollLock = ~kbdLockingKeys.kbdLeds.bmScrollLock;
|
||||
break;
|
||||
}
|
||||
|
||||
if (old_keys != kbdLockingKeys.bLeds && hid)
|
||||
return (hid->SetReport(0, 0/*hid->GetIface()*/, 2, 0, 1, &kbdLockingKeys.bLeds));
|
||||
if (old_keys != kbdLockingKeys.bLeds && hid)
|
||||
return (hid->SetReport(0, 0/*hid->GetIface()*/, 2, 0, 1, &kbdLockingKeys.bLeds));
|
||||
|
||||
return 0;
|
||||
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 shift = (mod & 0x22);
|
||||
uint8_t KeyboardReportParser::OemToAscii(uint8_t mod, uint8_t key) {
|
||||
uint8_t shift = (mod & 0x22);
|
||||
|
||||
// [a-z]
|
||||
if (key > 0x03 && key < 0x1e)
|
||||
{
|
||||
// Upper case letters
|
||||
if ( (kbdLockingKeys.kbdLeds.bmCapsLock == 0 && (mod & 2)) ||
|
||||
(kbdLockingKeys.kbdLeds.bmCapsLock == 1 && (mod & 2) == 0) )
|
||||
return (key - 4 + 'A');
|
||||
// [a-z]
|
||||
if (key > 0x03 && key < 0x1e) {
|
||||
// Upper case letters
|
||||
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)
|
||||
{
|
||||
if (shift)
|
||||
return ((uint8_t)pgm_read_byte(&numKeys[key - 0x1e]));
|
||||
else
|
||||
return (key - 0x1e + '1');
|
||||
}
|
||||
// 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 > 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);
|
||||
}
|
||||
}
|
||||
return( 0 );
|
||||
// Lower case letters
|
||||
else
|
||||
return (key - 4 + 'a');
|
||||
}// 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) {
|
||||
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 > 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);
|
||||
}
|
||||
}
|
||||
return ( 0);
|
||||
}
|
||||
|
|
619
hidboot.h
619
hidboot.h
|
@ -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,115 +44,128 @@ e-mail : support@circuitsathome.com
|
|||
#define KEY_ENTER 0x28
|
||||
#define KEY_PERIOD 0x63
|
||||
|
||||
struct MOUSEINFO
|
||||
{
|
||||
struct
|
||||
{
|
||||
uint8_t bmLeftButton : 1;
|
||||
uint8_t bmRightButton : 1;
|
||||
uint8_t bmMiddleButton : 1;
|
||||
uint8_t bmDummy : 1;
|
||||
};
|
||||
int8_t dX;
|
||||
int8_t dY;
|
||||
struct MOUSEINFO {
|
||||
|
||||
struct {
|
||||
uint8_t bmLeftButton : 1;
|
||||
uint8_t bmRightButton : 1;
|
||||
uint8_t bmMiddleButton : 1;
|
||||
uint8_t bmDummy : 1;
|
||||
};
|
||||
int8_t dX;
|
||||
int8_t dY;
|
||||
};
|
||||
|
||||
class MouseReportParser : public HIDReportParser
|
||||
{
|
||||
union
|
||||
{
|
||||
MOUSEINFO mouseInfo;
|
||||
uint8_t bInfo[3];
|
||||
} prevState;
|
||||
class MouseReportParser : public HIDReportParser {
|
||||
|
||||
union {
|
||||
MOUSEINFO mouseInfo;
|
||||
uint8_t bInfo[sizeof(MOUSEINFO)];
|
||||
} prevState;
|
||||
|
||||
public:
|
||||
virtual void Parse(HID *hid, bool is_rpt_id, uint8_t len, uint8_t *buf);
|
||||
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
|
||||
{
|
||||
uint8_t bmLeftCtrl : 1;
|
||||
uint8_t bmLeftShift : 1;
|
||||
uint8_t bmLeftAlt : 1;
|
||||
uint8_t bmLeftGUI : 1;
|
||||
uint8_t bmRightCtrl : 1;
|
||||
uint8_t bmRightShift : 1;
|
||||
uint8_t bmRightAlt : 1;
|
||||
uint8_t bmRightGUI : 1;
|
||||
struct MODIFIERKEYS {
|
||||
uint8_t bmLeftCtrl : 1;
|
||||
uint8_t bmLeftShift : 1;
|
||||
uint8_t bmLeftAlt : 1;
|
||||
uint8_t bmLeftGUI : 1;
|
||||
uint8_t bmRightCtrl : 1;
|
||||
uint8_t bmRightShift : 1;
|
||||
uint8_t bmRightAlt : 1;
|
||||
uint8_t bmRightGUI : 1;
|
||||
};
|
||||
|
||||
struct KBDINFO
|
||||
{
|
||||
struct
|
||||
{
|
||||
uint8_t bmLeftCtrl : 1;
|
||||
uint8_t bmLeftShift : 1;
|
||||
uint8_t bmLeftAlt : 1;
|
||||
uint8_t bmLeftGUI : 1;
|
||||
uint8_t bmRightCtrl : 1;
|
||||
uint8_t bmRightShift : 1;
|
||||
uint8_t bmRightAlt : 1;
|
||||
uint8_t bmRightGUI : 1;
|
||||
};
|
||||
uint8_t bReserved;
|
||||
uint8_t Keys[6];
|
||||
struct KBDINFO {
|
||||
|
||||
struct {
|
||||
uint8_t bmLeftCtrl : 1;
|
||||
uint8_t bmLeftShift : 1;
|
||||
uint8_t bmLeftAlt : 1;
|
||||
uint8_t bmLeftGUI : 1;
|
||||
uint8_t bmRightCtrl : 1;
|
||||
uint8_t bmRightShift : 1;
|
||||
uint8_t bmRightAlt : 1;
|
||||
uint8_t bmRightGUI : 1;
|
||||
};
|
||||
uint8_t bReserved;
|
||||
uint8_t Keys[6];
|
||||
};
|
||||
|
||||
struct KBDLEDS
|
||||
{
|
||||
uint8_t bmNumLock : 1;
|
||||
uint8_t bmCapsLock : 1;
|
||||
uint8_t bmScrollLock : 1;
|
||||
uint8_t bmCompose : 1;
|
||||
uint8_t bmKana : 1;
|
||||
uint8_t bmReserved : 3;
|
||||
struct KBDLEDS {
|
||||
uint8_t bmNumLock : 1;
|
||||
uint8_t bmCapsLock : 1;
|
||||
uint8_t bmScrollLock : 1;
|
||||
uint8_t bmCompose : 1;
|
||||
uint8_t bmKana : 1;
|
||||
uint8_t bmReserved : 3;
|
||||
};
|
||||
|
||||
#define KEY_NUM_LOCK 0x53
|
||||
#define KEY_CAPS_LOCK 0x39
|
||||
#define KEY_SCROLL_LOCK 0x47
|
||||
|
||||
class KeyboardReportParser : public HIDReportParser
|
||||
{
|
||||
static const uint8_t numKeys[];
|
||||
static const uint8_t symKeysUp[];
|
||||
static const uint8_t symKeysLo[];
|
||||
static const uint8_t padKeys[];
|
||||
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
|
||||
{
|
||||
KBDINFO kbdInfo;
|
||||
uint8_t bInfo[sizeof(KBDINFO)];
|
||||
} prevState;
|
||||
|
||||
union
|
||||
{
|
||||
KBDLEDS kbdLeds;
|
||||
uint8_t bLeds;
|
||||
} kbdLockingKeys;
|
||||
union {
|
||||
KBDINFO kbdInfo;
|
||||
uint8_t bInfo[sizeof(KBDINFO)];
|
||||
} prevState;
|
||||
|
||||
uint8_t OemToAscii(uint8_t mod, uint8_t key);
|
||||
union {
|
||||
KBDLEDS kbdLeds;
|
||||
uint8_t bLeds;
|
||||
} kbdLockingKeys;
|
||||
|
||||
uint8_t OemToAscii(uint8_t mod, uint8_t key);
|
||||
|
||||
public:
|
||||
KeyboardReportParser() { kbdLockingKeys.bLeds = 0; };
|
||||
|
||||
virtual void Parse(HID *hid, bool is_rpt_id, uint8_t len, uint8_t *buf);
|
||||
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);
|
||||
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
|
||||
|
@ -162,333 +175,319 @@ protected:
|
|||
template <const uint8_t BOOT_PROTOCOL>
|
||||
class HIDBoot : public HID //public USBDeviceConfig, public UsbConfigXtracter
|
||||
{
|
||||
EpInfo epInfo[totalEndpoints];
|
||||
EpInfo epInfo[totalEndpoints];
|
||||
|
||||
HIDReportParser *pRptParser;
|
||||
HIDReportParser *pRptParser;
|
||||
|
||||
uint8_t bConfNum; // configuration number
|
||||
uint8_t bIfaceNum; // Interface Number
|
||||
uint8_t bNumIface; // number of interfaces in the configuration
|
||||
uint8_t bNumEP; // total number of EP in the configuration
|
||||
uint32_t qNextPollTime; // next poll time
|
||||
bool bPollEnable; // poll enable flag
|
||||
uint8_t bConfNum; // configuration number
|
||||
uint8_t bIfaceNum; // Interface Number
|
||||
uint8_t bNumIface; // number of interfaces in the configuration
|
||||
uint8_t bNumEP; // total number of EP in the configuration
|
||||
uint32_t qNextPollTime; // next poll time
|
||||
bool bPollEnable; // poll enable flag
|
||||
|
||||
void Initialize();
|
||||
void Initialize();
|
||||
|
||||
virtual HIDReportParser* GetReportParser(uint8_t id) { return pRptParser; };
|
||||
virtual HIDReportParser* GetReportParser(uint8_t id) {
|
||||
return pRptParser;
|
||||
};
|
||||
|
||||
public:
|
||||
HIDBoot(USB *p);
|
||||
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; };
|
||||
// USBDeviceConfig implementation
|
||||
virtual uint8_t Init(uint8_t parent, uint8_t port, bool lowspeed);
|
||||
virtual uint8_t Release();
|
||||
virtual uint8_t Poll();
|
||||
|
||||
// UsbConfigXtracter implementation
|
||||
virtual void EndpointXtract(uint8_t conf, uint8_t iface, uint8_t alt, uint8_t proto, const USB_ENDPOINT_DESCRIPTOR *ep);
|
||||
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);
|
||||
};
|
||||
|
||||
template <const uint8_t BOOT_PROTOCOL>
|
||||
HIDBoot<BOOT_PROTOCOL>::HIDBoot(USB *p) :
|
||||
HID(p),
|
||||
qNextPollTime(0),
|
||||
bPollEnable(false),
|
||||
pRptParser(NULL)
|
||||
{
|
||||
Initialize();
|
||||
HID(p),
|
||||
qNextPollTime(0),
|
||||
bPollEnable(false),
|
||||
pRptParser(NULL) {
|
||||
Initialize();
|
||||
|
||||
if (pUsb)
|
||||
pUsb->RegisterDeviceClass(this);
|
||||
if(pUsb)
|
||||
pUsb->RegisterDeviceClass(this);
|
||||
}
|
||||
|
||||
template <const uint8_t BOOT_PROTOCOL>
|
||||
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;
|
||||
epInfo[i].bmNakPower = (i) ? USB_NAK_NOWAIT : USB_NAK_MAX_POWER;
|
||||
}
|
||||
bNumEP = 1;
|
||||
bNumIface = 0;
|
||||
bConfNum = 0;
|
||||
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;
|
||||
epInfo[i].bmNakPower = (i) ? USB_NAK_NOWAIT : USB_NAK_MAX_POWER;
|
||||
}
|
||||
bNumEP = 1;
|
||||
bNumIface = 0;
|
||||
bConfNum = 0;
|
||||
}
|
||||
|
||||
template <const uint8_t BOOT_PROTOCOL>
|
||||
uint8_t HIDBoot<BOOT_PROTOCOL>::Init(uint8_t parent, uint8_t port, bool lowspeed)
|
||||
{
|
||||
const uint8_t constBufSize = sizeof(USB_DEVICE_DESCRIPTOR);
|
||||
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];
|
||||
uint8_t rcode;
|
||||
UsbDevice *p = NULL;
|
||||
EpInfo *oldep_ptr = NULL;
|
||||
uint8_t len = 0;
|
||||
uint16_t cd_len = 0;
|
||||
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 num_of_conf; // number of configurations
|
||||
uint8_t num_of_intf; // number of interfaces
|
||||
uint8_t num_of_conf; // number of configurations
|
||||
uint8_t num_of_intf; // number of interfaces
|
||||
|
||||
AddressPool &addrPool = pUsb->GetAddressPool();
|
||||
AddressPool &addrPool = pUsb->GetAddressPool();
|
||||
|
||||
USBTRACE("BM Init\r\n");
|
||||
USBTRACE("BM Init\r\n");
|
||||
|
||||
if (bAddress)
|
||||
return USB_ERROR_CLASS_INSTANCE_ALREADY_IN_USE;
|
||||
if(bAddress)
|
||||
return USB_ERROR_CLASS_INSTANCE_ALREADY_IN_USE;
|
||||
|
||||
// Get pointer to pseudo device with address 0 assigned
|
||||
p = addrPool.GetUsbDevicePtr(0);
|
||||
// Get pointer to pseudo device with address 0 assigned
|
||||
p = addrPool.GetUsbDevicePtr(0);
|
||||
|
||||
if (!p)
|
||||
return USB_ERROR_ADDRESS_NOT_FOUND_IN_POOL;
|
||||
if(!p)
|
||||
return USB_ERROR_ADDRESS_NOT_FOUND_IN_POOL;
|
||||
|
||||
if (!p->epinfo)
|
||||
{
|
||||
USBTRACE("epinfo\r\n");
|
||||
return USB_ERROR_EPINFO_IS_NULL;
|
||||
}
|
||||
if(!p->epinfo) {
|
||||
USBTRACE("epinfo\r\n");
|
||||
return USB_ERROR_EPINFO_IS_NULL;
|
||||
}
|
||||
|
||||
// Save old pointer to EP_RECORD of address 0
|
||||
oldep_ptr = p->epinfo;
|
||||
// Save old pointer to EP_RECORD of address 0
|
||||
oldep_ptr = p->epinfo;
|
||||
|
||||
// Temporary assign new pointer to epInfo to p->epinfo in order to avoid toggle inconsistence
|
||||
p->epinfo = epInfo;
|
||||
// Temporary assign new pointer to epInfo to p->epinfo in order to avoid toggle inconsistence
|
||||
p->epinfo = epInfo;
|
||||
|
||||
p->lowspeed = lowspeed;
|
||||
p->lowspeed = lowspeed;
|
||||
|
||||
// Get device descriptor
|
||||
rcode = pUsb->getDevDescr( 0, 0, 8, (uint8_t*)buf );
|
||||
// Get device descriptor
|
||||
rcode = pUsb->getDevDescr(0, 0, 8, (uint8_t*) buf);
|
||||
|
||||
if (!rcode)
|
||||
len = (buf[0] > constBufSize) ? constBufSize : buf[0];
|
||||
if(!rcode)
|
||||
len = (buf[0] > constBufSize) ? constBufSize : buf[0];
|
||||
|
||||
if( rcode )
|
||||
{
|
||||
// Restore p->epinfo
|
||||
p->epinfo = oldep_ptr;
|
||||
if(rcode) {
|
||||
// Restore p->epinfo
|
||||
p->epinfo = oldep_ptr;
|
||||
|
||||
goto FailGetDevDescr;
|
||||
}
|
||||
goto FailGetDevDescr;
|
||||
}
|
||||
|
||||
// Restore p->epinfo
|
||||
p->epinfo = oldep_ptr;
|
||||
// Restore p->epinfo
|
||||
p->epinfo = oldep_ptr;
|
||||
|
||||
// Allocate new address according to device class
|
||||
bAddress = addrPool.AllocAddress(parent, false, port);
|
||||
// Allocate new address according to device class
|
||||
bAddress = addrPool.AllocAddress(parent, false, port);
|
||||
|
||||
if (!bAddress)
|
||||
return USB_ERROR_OUT_OF_ADDRESS_SPACE_IN_POOL;
|
||||
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;
|
||||
// Extract Max Packet Size from the device descriptor
|
||||
epInfo[0].maxPktSize = (uint8_t) ((USB_DEVICE_DESCRIPTOR*) buf)->bMaxPacketSize0;
|
||||
|
||||
// Assign new address to the device
|
||||
rcode = pUsb->setAddr( 0, 0, bAddress );
|
||||
// Assign new address to the device
|
||||
rcode = pUsb->setAddr(0, 0, bAddress);
|
||||
|
||||
if (rcode)
|
||||
{
|
||||
p->lowspeed = false;
|
||||
addrPool.FreeAddress(bAddress);
|
||||
bAddress = 0;
|
||||
USBTRACE2("setAddr:",rcode);
|
||||
return rcode;
|
||||
}
|
||||
if(rcode) {
|
||||
p->lowspeed = false;
|
||||
addrPool.FreeAddress(bAddress);
|
||||
bAddress = 0;
|
||||
USBTRACE2("setAddr:", rcode);
|
||||
return rcode;
|
||||
}
|
||||
|
||||
USBTRACE2("Addr:", bAddress);
|
||||
USBTRACE2("Addr:", bAddress);
|
||||
|
||||
p->lowspeed = false;
|
||||
p->lowspeed = false;
|
||||
|
||||
p = addrPool.GetUsbDevicePtr(bAddress);
|
||||
p = addrPool.GetUsbDevicePtr(bAddress);
|
||||
|
||||
if (!p)
|
||||
return USB_ERROR_ADDRESS_NOT_FOUND_IN_POOL;
|
||||
if(!p)
|
||||
return USB_ERROR_ADDRESS_NOT_FOUND_IN_POOL;
|
||||
|
||||
p->lowspeed = lowspeed;
|
||||
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;
|
||||
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);
|
||||
// Assign epInfo to epinfo pointer
|
||||
rcode = pUsb->setEpInfoEntry(bAddress, 1, epInfo);
|
||||
|
||||
if (rcode)
|
||||
goto FailSetDevTblEntry;
|
||||
if(rcode)
|
||||
goto FailSetDevTblEntry;
|
||||
|
||||
//USBTRACE2("NC:", num_of_conf);
|
||||
//USBTRACE2("NC:", num_of_conf);
|
||||
|
||||
for (uint8_t i=0; i<num_of_conf; i++)
|
||||
{
|
||||
//HexDumper<USBReadParser, uint16_t, uint16_t> HexDump;
|
||||
ConfigDescParser<
|
||||
USB_CLASS_HID,
|
||||
HID_BOOT_INTF_SUBCLASS,
|
||||
BOOT_PROTOCOL,
|
||||
CP_MASK_COMPARE_ALL> confDescrParser(this);
|
||||
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);
|
||||
rcode = pUsb->getConfDescr(bAddress, 0, i, &confDescrParser);
|
||||
|
||||
if (bNumEP > 1)
|
||||
break;
|
||||
} // for
|
||||
if(bNumEP > 1)
|
||||
break;
|
||||
} // for
|
||||
|
||||
if (bNumEP < 2)
|
||||
return USB_DEV_CONFIG_ERROR_DEVICE_NOT_SUPPORTED;
|
||||
if(bNumEP < 2)
|
||||
return USB_DEV_CONFIG_ERROR_DEVICE_NOT_SUPPORTED;
|
||||
|
||||
//USBTRACE2("\r\nbAddr:", bAddress);
|
||||
//USBTRACE2("\r\nbNumEP:", bNumEP);
|
||||
//USBTRACE2("\r\nbAddr:", bAddress);
|
||||
//USBTRACE2("\r\nbNumEP:", bNumEP);
|
||||
|
||||
// Assign epInfo to epinfo pointer
|
||||
rcode = pUsb->setEpInfoEntry(bAddress, bNumEP, epInfo);
|
||||
// Assign epInfo to epinfo pointer
|
||||
rcode = pUsb->setEpInfoEntry(bAddress, bNumEP, epInfo);
|
||||
|
||||
//USBTRACE2("\r\nCnf:", bConfNum);
|
||||
//USBTRACE2("\r\nCnf:", bConfNum);
|
||||
|
||||
// Set Configuration Value
|
||||
rcode = pUsb->setConf(bAddress, 0, bConfNum);
|
||||
// Set Configuration Value
|
||||
rcode = pUsb->setConf(bAddress, 0, bConfNum);
|
||||
|
||||
if (rcode)
|
||||
goto FailSetConfDescr;
|
||||
if(rcode)
|
||||
goto FailSetConfDescr;
|
||||
|
||||
//USBTRACE2("\r\nIf:", bIfaceNum);
|
||||
//USBTRACE2("\r\nIf:", bIfaceNum);
|
||||
|
||||
rcode = SetProtocol(bIfaceNum, HID_BOOT_PROTOCOL);
|
||||
rcode = SetProtocol(bIfaceNum, HID_BOOT_PROTOCOL);
|
||||
|
||||
if (rcode)
|
||||
goto FailSetProtocol;
|
||||
if(rcode)
|
||||
goto FailSetProtocol;
|
||||
|
||||
if (BOOT_PROTOCOL == 1)
|
||||
{
|
||||
rcode = SetIdle(bIfaceNum, 0, 0);
|
||||
if(BOOT_PROTOCOL == 1) {
|
||||
rcode = SetIdle(bIfaceNum, 0, 0);
|
||||
|
||||
if (rcode)
|
||||
goto FailSetIdle;
|
||||
}
|
||||
USBTRACE("BM configured\r\n");
|
||||
if(rcode)
|
||||
goto FailSetIdle;
|
||||
}
|
||||
USBTRACE("BM configured\r\n");
|
||||
|
||||
bPollEnable = true;
|
||||
return 0;
|
||||
bPollEnable = true;
|
||||
return 0;
|
||||
|
||||
FailGetDevDescr:
|
||||
USBTRACE("getDevDescr:");
|
||||
goto Fail;
|
||||
USBTRACE("getDevDescr:");
|
||||
goto Fail;
|
||||
|
||||
FailSetDevTblEntry:
|
||||
USBTRACE("setDevTblEn:");
|
||||
goto Fail;
|
||||
USBTRACE("setDevTblEn:");
|
||||
goto Fail;
|
||||
|
||||
FailGetConfDescr:
|
||||
USBTRACE("getConf:");
|
||||
goto Fail;
|
||||
USBTRACE("getConf:");
|
||||
goto Fail;
|
||||
|
||||
FailSetProtocol:
|
||||
USBTRACE("SetProto:");
|
||||
goto Fail;
|
||||
USBTRACE("SetProto:");
|
||||
goto Fail;
|
||||
|
||||
FailSetIdle:
|
||||
USBTRACE("SetIdle:");
|
||||
goto Fail;
|
||||
USBTRACE("SetIdle:");
|
||||
goto Fail;
|
||||
|
||||
FailSetConfDescr:
|
||||
USBTRACE("setConf:");
|
||||
goto Fail;
|
||||
USBTRACE("setConf:");
|
||||
goto Fail;
|
||||
|
||||
Fail:
|
||||
Serial.println(rcode, HEX);
|
||||
Release();
|
||||
return rcode;
|
||||
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)
|
||||
{
|
||||
// If the first configuration satisfies, the others are not concidered.
|
||||
if (bNumEP > 1 && conf != bConfNum)
|
||||
return;
|
||||
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)
|
||||
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;
|
||||
|
||||
bConfNum = conf;
|
||||
bIfaceNum = iface;
|
||||
uint8_t index;
|
||||
|
||||
uint8_t index;
|
||||
if((pep->bmAttributes & 0x03) == 3 && (pep->bEndpointAddress & 0x80) == 0x80) {
|
||||
index = epInterruptInIndex;
|
||||
|
||||
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].epAttribs = 0;
|
||||
|
||||
// Fill in the endpoint info structure
|
||||
epInfo[index].epAddr = (pep->bEndpointAddress & 0x0F);
|
||||
epInfo[index].maxPktSize = (uint8_t)pep->wMaxPacketSize;
|
||||
epInfo[index].epAttribs = 0;
|
||||
|
||||
bNumEP ++;
|
||||
|
||||
//PrintEndpointDescriptor(pep);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
template <const uint8_t BOOT_PROTOCOL>
|
||||
uint8_t HIDBoot<BOOT_PROTOCOL>::Release()
|
||||
{
|
||||
pUsb->GetAddressPool().FreeAddress(bAddress);
|
||||
|
||||
bConfNum = 0;
|
||||
bIfaceNum = 0;
|
||||
bNumEP = 1;
|
||||
bAddress = 0;
|
||||
qNextPollTime = 0;
|
||||
bPollEnable = false;
|
||||
return 0;
|
||||
bNumEP++;
|
||||
}
|
||||
}
|
||||
|
||||
template <const uint8_t BOOT_PROTOCOL>
|
||||
uint8_t HIDBoot<BOOT_PROTOCOL>::Poll()
|
||||
{
|
||||
uint8_t rcode = 0;
|
||||
uint8_t HIDBoot<BOOT_PROTOCOL>::Release() {
|
||||
pUsb->GetAddressPool().FreeAddress(bAddress);
|
||||
|
||||
if (!bPollEnable)
|
||||
return 0;
|
||||
bConfNum = 0;
|
||||
bIfaceNum = 0;
|
||||
bNumEP = 1;
|
||||
bAddress = 0;
|
||||
qNextPollTime = 0;
|
||||
bPollEnable = false;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (qNextPollTime <= millis())
|
||||
{
|
||||
qNextPollTime = millis() + 10;
|
||||
template <const uint8_t BOOT_PROTOCOL>
|
||||
uint8_t HIDBoot<BOOT_PROTOCOL>::Poll() {
|
||||
uint8_t rcode = 0;
|
||||
|
||||
const uint8_t const_buff_len = 16;
|
||||
uint8_t buf[const_buff_len];
|
||||
if(!bPollEnable)
|
||||
return 0;
|
||||
|
||||
uint16_t read = (uint16_t)epInfo[epInterruptInIndex].maxPktSize;
|
||||
if(qNextPollTime <= millis()) {
|
||||
qNextPollTime = millis() + 10;
|
||||
|
||||
uint8_t rcode = pUsb->inTransfer(bAddress, epInfo[epInterruptInIndex].epAddr, &read, buf);
|
||||
const uint8_t const_buff_len = 16;
|
||||
uint8_t buf[const_buff_len];
|
||||
|
||||
if (rcode)
|
||||
{
|
||||
if (rcode != hrNAK)
|
||||
USBTRACE2("Poll:", rcode);
|
||||
return rcode;
|
||||
}
|
||||
//for (uint8_t i=0; i<read; i++)
|
||||
// PrintHex<uint8_t>(buf[i]);
|
||||
//if (read)
|
||||
// Serial.println("");
|
||||
uint16_t read = (uint16_t) epInfo[epInterruptInIndex].maxPktSize;
|
||||
|
||||
if (pRptParser)
|
||||
pRptParser->Parse((HID*)this, 0, (uint8_t)read, buf);
|
||||
}
|
||||
return rcode;
|
||||
uint8_t rcode = pUsb->inTransfer(bAddress, epInfo[epInterruptInIndex].epAddr, &read, buf);
|
||||
|
||||
if(rcode) {
|
||||
if(rcode != hrNAK)
|
||||
USBTRACE2("Poll:", rcode);
|
||||
return rcode;
|
||||
}
|
||||
//for (uint8_t i=0; i<read; i++)
|
||||
// PrintHex<uint8_t>(buf[i]);
|
||||
//if (read)
|
||||
// Serial.println("");
|
||||
|
||||
if(pRptParser)
|
||||
pRptParser->Parse((HID*)this, 0, (uint8_t) read, buf);
|
||||
}
|
||||
return rcode;
|
||||
}
|
||||
|
||||
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -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,159 +37,155 @@ 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);
|
||||
typedef void (*UsagePageFunc)(uint16_t usage);
|
||||
|
||||
static void PrintGenericDesktopPageUsage(uint16_t usage);
|
||||
static void PrintSimulationControlsPageUsage(uint16_t usage);
|
||||
static void PrintVRControlsPageUsage(uint16_t usage);
|
||||
static void PrintSportsControlsPageUsage(uint16_t usage);
|
||||
static void PrintGameControlsPageUsage(uint16_t usage);
|
||||
static void PrintGenericDeviceControlsPageUsage(uint16_t usage);
|
||||
static void PrintLEDPageUsage(uint16_t usage);
|
||||
static void PrintButtonPageUsage(uint16_t usage);
|
||||
static void PrintOrdinalPageUsage(uint16_t usage);
|
||||
static void PrintTelephonyPageUsage(uint16_t usage);
|
||||
static void PrintConsumerPageUsage(uint16_t usage);
|
||||
static void PrintDigitizerPageUsage(uint16_t usage);
|
||||
static void PrintAlphanumDisplayPageUsage(uint16_t usage);
|
||||
static void PrintMedicalInstrumentPageUsage(uint16_t usage);
|
||||
static void PrintGenericDesktopPageUsage(uint16_t usage);
|
||||
static void PrintSimulationControlsPageUsage(uint16_t usage);
|
||||
static void PrintVRControlsPageUsage(uint16_t usage);
|
||||
static void PrintSportsControlsPageUsage(uint16_t usage);
|
||||
static void PrintGameControlsPageUsage(uint16_t usage);
|
||||
static void PrintGenericDeviceControlsPageUsage(uint16_t usage);
|
||||
static void PrintLEDPageUsage(uint16_t usage);
|
||||
static void PrintButtonPageUsage(uint16_t usage);
|
||||
static void PrintOrdinalPageUsage(uint16_t usage);
|
||||
static void PrintTelephonyPageUsage(uint16_t usage);
|
||||
static void PrintConsumerPageUsage(uint16_t usage);
|
||||
static void PrintDigitizerPageUsage(uint16_t usage);
|
||||
static void PrintAlphanumDisplayPageUsage(uint16_t usage);
|
||||
static void PrintMedicalInstrumentPageUsage(uint16_t usage);
|
||||
|
||||
static void PrintValue(uint8_t *p, uint8_t len);
|
||||
static void PrintByteValue(uint8_t data);
|
||||
static void PrintValue(uint8_t *p, uint8_t len);
|
||||
static void PrintByteValue(uint8_t data);
|
||||
|
||||
static void PrintItemTitle(uint8_t prefix);
|
||||
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[];
|
||||
static UsagePageFunc usagePageFunctions[];
|
||||
|
||||
MultiValueBuffer theBuffer;
|
||||
MultiByteValueParser valParser;
|
||||
ByteSkipper theSkipper;
|
||||
uint8_t varBuffer[sizeof(USB_CONFIGURATION_DESCRIPTOR)];
|
||||
MultiValueBuffer theBuffer;
|
||||
MultiByteValueParser valParser;
|
||||
ByteSkipper theSkipper;
|
||||
uint8_t varBuffer[sizeof(USB_CONFIGURATION_DESCRIPTOR)];
|
||||
|
||||
uint8_t itemParseState; // Item parser state variable
|
||||
uint8_t itemSize; // Item size
|
||||
uint8_t itemPrefix; // Item prefix (first byte)
|
||||
uint8_t rptSize; // Report Size
|
||||
uint8_t rptCount; // Report Count
|
||||
uint8_t itemParseState; // Item parser state variable
|
||||
uint8_t itemSize; // Item size
|
||||
uint8_t itemPrefix; // Item prefix (first byte)
|
||||
uint8_t rptSize; // Report Size
|
||||
uint8_t rptCount; // Report Count
|
||||
|
||||
uint16_t totalSize; // Report size in bits
|
||||
uint16_t totalSize; // Report size in bits
|
||||
|
||||
virtual uint8_t ParseItem(uint8_t **pp, uint16_t *pcntdn);
|
||||
virtual uint8_t ParseItem(uint8_t **pp, uint16_t *pcntdn);
|
||||
|
||||
UsagePageFunc pfUsage;
|
||||
UsagePageFunc pfUsage;
|
||||
|
||||
static void PrintUsagePage(uint16_t page);
|
||||
void SetUsagePage(uint16_t page);
|
||||
static void PrintUsagePage(uint16_t page);
|
||||
void SetUsagePage(uint16_t page);
|
||||
|
||||
public:
|
||||
ReportDescParserBase() :
|
||||
itemParseState(0),
|
||||
itemSize(0),
|
||||
itemPrefix(0),
|
||||
rptSize(0),
|
||||
rptCount(0),
|
||||
pfUsage(NULL)
|
||||
{
|
||||
theBuffer.pValue = varBuffer;
|
||||
valParser.Initialize(&theBuffer);
|
||||
theSkipper.Initialize(&theBuffer);
|
||||
};
|
||||
|
||||
virtual void Parse(const uint16_t len, const uint8_t *pbuf, const uint16_t &offset);
|
||||
ReportDescParserBase() :
|
||||
itemParseState(0),
|
||||
itemSize(0),
|
||||
itemPrefix(0),
|
||||
rptSize(0),
|
||||
rptCount(0),
|
||||
pfUsage(NULL) {
|
||||
theBuffer.pValue = varBuffer;
|
||||
valParser.Initialize(&theBuffer);
|
||||
theSkipper.Initialize(&theBuffer);
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
enErrorSuccess = 0
|
||||
, enErrorIncomplete // value or record is partialy read in buffer
|
||||
, enErrorBufferTooSmall
|
||||
};
|
||||
virtual void Parse(const uint16_t len, const uint8_t *pbuf, const uint16_t &offset);
|
||||
|
||||
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
|
||||
{
|
||||
uint8_t rptId; // Report ID
|
||||
uint8_t useMin; // Usage Minimum
|
||||
uint8_t useMax; // Usage Maximum
|
||||
uint8_t fieldCount; // Number of field being currently processed
|
||||
class ReportDescParser2 : public ReportDescParserBase {
|
||||
uint8_t rptId; // Report ID
|
||||
uint8_t useMin; // Usage Minimum
|
||||
uint8_t useMax; // Usage Maximum
|
||||
uint8_t fieldCount; // Number of field being currently processed
|
||||
|
||||
void OnInputItem(uint8_t itm); // Method which is called every time Input item is found
|
||||
void OnInputItem(uint8_t itm); // Method which is called every time Input item is found
|
||||
|
||||
uint8_t *pBuf; // Report buffer pointer
|
||||
uint8_t bLen; // Report length
|
||||
uint8_t *pBuf; // Report buffer pointer
|
||||
uint8_t bLen; // Report length
|
||||
|
||||
protected:
|
||||
virtual uint8_t ParseItem(uint8_t **pp, uint16_t *pcntdn);
|
||||
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)
|
||||
{};
|
||||
|
||||
ReportDescParser2(uint16_t len, uint8_t *pbuf) :
|
||||
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);
|
||||
virtual void Parse(HID *hid, bool is_rpt_id, uint8_t len, uint8_t *buf);
|
||||
};
|
||||
|
||||
#endif // __HIDDESCRIPTORPARSER_H__
|
600
hiduniversal.cpp
600
hiduniversal.cpp
|
@ -1,418 +1,378 @@
|
|||
#include "hiduniversal.h"
|
||||
|
||||
HIDUniversal::HIDUniversal(USB *p) :
|
||||
HID(p),
|
||||
qNextPollTime(0),
|
||||
bPollEnable(false),
|
||||
bHasReportId(false)
|
||||
{
|
||||
Initialize();
|
||||
HID(p),
|
||||
qNextPollTime(0),
|
||||
bPollEnable(false),
|
||||
bHasReportId(false) {
|
||||
Initialize();
|
||||
|
||||
if (pUsb)
|
||||
pUsb->RegisterDeviceClass(this);
|
||||
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)
|
||||
{
|
||||
if (n == num)
|
||||
return descrInfo[i].wDescriptorLength;
|
||||
n ++;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
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++;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
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++)
|
||||
{
|
||||
descrInfo[i].bDescrType = 0;
|
||||
descrInfo[i].wDescriptorLength = 0;
|
||||
}
|
||||
for (uint8_t i=0; i<maxHidInterfaces; i++)
|
||||
{
|
||||
hidInterfaces[i].bmInterface = 0;
|
||||
hidInterfaces[i].bmProtocol = 0;
|
||||
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++) {
|
||||
descrInfo[i].bDescrType = 0;
|
||||
descrInfo[i].wDescriptorLength = 0;
|
||||
}
|
||||
for (uint8_t i = 0; i < maxHidInterfaces; i++) {
|
||||
hidInterfaces[i].bmInterface = 0;
|
||||
hidInterfaces[i].bmProtocol = 0;
|
||||
|
||||
for (uint8_t j=0; j<maxEpPerInterface; j++)
|
||||
hidInterfaces[i].epIndex[j] = 0;
|
||||
}
|
||||
for(uint8_t i=0; i<totalEndpoints; 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;
|
||||
}
|
||||
bNumEP = 1;
|
||||
bNumIface = 0;
|
||||
bConfNum = 0;
|
||||
for (uint8_t j = 0; j < maxEpPerInterface; j++)
|
||||
hidInterfaces[i].epIndex[j] = 0;
|
||||
}
|
||||
for (uint8_t i = 0; i < totalEndpoints; 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;
|
||||
}
|
||||
bNumEP = 1;
|
||||
bNumIface = 0;
|
||||
bConfNum = 0;
|
||||
|
||||
ZeroMemory(constBuffLen, prevBuf);
|
||||
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)
|
||||
{
|
||||
rptParsers[i].rptId = id;
|
||||
rptParsers[i].rptParser = prs;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
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;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
HIDReportParser* HIDUniversal::GetReportParser(uint8_t id)
|
||||
{
|
||||
if (!bHasReportId)
|
||||
return ((rptParsers[0].rptParser) ? rptParsers[0].rptParser : NULL);
|
||||
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++)
|
||||
{
|
||||
if (rptParsers[i].rptId == id)
|
||||
return rptParsers[i].rptParser;
|
||||
}
|
||||
return NULL;
|
||||
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;
|
||||
UsbDevice *p = NULL;
|
||||
EpInfo *oldep_ptr = NULL;
|
||||
uint8_t len = 0;
|
||||
uint8_t buf[constBufSize];
|
||||
uint8_t rcode;
|
||||
UsbDevice *p = NULL;
|
||||
EpInfo *oldep_ptr = NULL;
|
||||
uint8_t len = 0;
|
||||
|
||||
uint8_t num_of_conf; // number of configurations
|
||||
uint8_t num_of_intf; // number of interfaces
|
||||
uint8_t num_of_conf; // number of configurations
|
||||
//uint8_t num_of_intf; // number of interfaces
|
||||
|
||||
AddressPool &addrPool = pUsb->GetAddressPool();
|
||||
AddressPool &addrPool = pUsb->GetAddressPool();
|
||||
|
||||
USBTRACE("HU Init\r\n");
|
||||
USBTRACE("HU Init\r\n");
|
||||
|
||||
if (bAddress)
|
||||
return USB_ERROR_CLASS_INSTANCE_ALREADY_IN_USE;
|
||||
if (bAddress)
|
||||
return USB_ERROR_CLASS_INSTANCE_ALREADY_IN_USE;
|
||||
|
||||
// Get pointer to pseudo device with address 0 assigned
|
||||
p = addrPool.GetUsbDevicePtr(0);
|
||||
// Get pointer to pseudo device with address 0 assigned
|
||||
p = addrPool.GetUsbDevicePtr(0);
|
||||
|
||||
if (!p)
|
||||
return USB_ERROR_ADDRESS_NOT_FOUND_IN_POOL;
|
||||
if (!p)
|
||||
return USB_ERROR_ADDRESS_NOT_FOUND_IN_POOL;
|
||||
|
||||
if (!p->epinfo)
|
||||
{
|
||||
USBTRACE("epinfo\r\n");
|
||||
return USB_ERROR_EPINFO_IS_NULL;
|
||||
}
|
||||
if (!p->epinfo) {
|
||||
USBTRACE("epinfo\r\n");
|
||||
return USB_ERROR_EPINFO_IS_NULL;
|
||||
}
|
||||
|
||||
// Save old pointer to EP_RECORD of address 0
|
||||
oldep_ptr = p->epinfo;
|
||||
// Save old pointer to EP_RECORD of address 0
|
||||
oldep_ptr = p->epinfo;
|
||||
|
||||
// Temporary assign new pointer to epInfo to p->epinfo in order to avoid toggle inconsistence
|
||||
p->epinfo = epInfo;
|
||||
// Temporary assign new pointer to epInfo to p->epinfo in order to avoid toggle inconsistence
|
||||
p->epinfo = epInfo;
|
||||
|
||||
p->lowspeed = lowspeed;
|
||||
p->lowspeed = lowspeed;
|
||||
|
||||
//delay(200);
|
||||
// Get device descriptor
|
||||
rcode = pUsb->getDevDescr(0, 0, 8, (uint8_t*)buf);
|
||||
|
||||
// Get device descriptor
|
||||
rcode = pUsb->getDevDescr( 0, 0, 8, (uint8_t*)buf );
|
||||
if (!rcode)
|
||||
len = (buf[0] > constBufSize) ? constBufSize : buf[0];
|
||||
|
||||
if (!rcode)
|
||||
len = (buf[0] > constBufSize) ? constBufSize : buf[0];
|
||||
if (rcode) {
|
||||
// Restore p->epinfo
|
||||
p->epinfo = oldep_ptr;
|
||||
|
||||
if( rcode )
|
||||
{
|
||||
// Restore p->epinfo
|
||||
p->epinfo = oldep_ptr;
|
||||
goto FailGetDevDescr;
|
||||
}
|
||||
|
||||
goto FailGetDevDescr;
|
||||
}
|
||||
// Restore p->epinfo
|
||||
p->epinfo = oldep_ptr;
|
||||
|
||||
// Restore p->epinfo
|
||||
p->epinfo = oldep_ptr;
|
||||
// Allocate new address according to device class
|
||||
bAddress = addrPool.AllocAddress(parent, false, port);
|
||||
|
||||
// Allocate new address according to device class
|
||||
bAddress = addrPool.AllocAddress(parent, false, port);
|
||||
if (!bAddress)
|
||||
return USB_ERROR_OUT_OF_ADDRESS_SPACE_IN_POOL;
|
||||
|
||||
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;
|
||||
|
||||
// Extract Max Packet Size from the device descriptor
|
||||
epInfo[0].maxPktSize = (uint8_t)((USB_DEVICE_DESCRIPTOR*)buf)->bMaxPacketSize0;
|
||||
// Assign new address to the device
|
||||
rcode = pUsb->setAddr(0, 0, bAddress);
|
||||
|
||||
// Assign new address to the device
|
||||
rcode = pUsb->setAddr( 0, 0, bAddress );
|
||||
if (rcode) {
|
||||
p->lowspeed = false;
|
||||
addrPool.FreeAddress(bAddress);
|
||||
bAddress = 0;
|
||||
USBTRACE2("setAddr:", rcode);
|
||||
return rcode;
|
||||
}
|
||||
|
||||
if (rcode)
|
||||
{
|
||||
p->lowspeed = false;
|
||||
addrPool.FreeAddress(bAddress);
|
||||
bAddress = 0;
|
||||
USBTRACE2("setAddr:",rcode);
|
||||
return rcode;
|
||||
}
|
||||
USBTRACE2("Addr:", bAddress);
|
||||
|
||||
USBTRACE2("Addr:", bAddress);
|
||||
p->lowspeed = false;
|
||||
|
||||
p->lowspeed = false;
|
||||
p = addrPool.GetUsbDevicePtr(bAddress);
|
||||
|
||||
p = addrPool.GetUsbDevicePtr(bAddress);
|
||||
if (!p)
|
||||
return USB_ERROR_ADDRESS_NOT_FOUND_IN_POOL;
|
||||
|
||||
if (!p)
|
||||
return USB_ERROR_ADDRESS_NOT_FOUND_IN_POOL;
|
||||
p->lowspeed = lowspeed;
|
||||
|
||||
p->lowspeed = lowspeed;
|
||||
if (len)
|
||||
rcode = pUsb->getDevDescr(bAddress, 0, len, (uint8_t*)buf);
|
||||
|
||||
delay(500);
|
||||
if (rcode)
|
||||
goto FailGetDevDescr;
|
||||
|
||||
if (len)
|
||||
rcode = pUsb->getDevDescr( bAddress, 0, len, (uint8_t*)buf );
|
||||
num_of_conf = ((USB_DEVICE_DESCRIPTOR*)buf)->bNumConfigurations;
|
||||
|
||||
if(rcode)
|
||||
goto FailGetDevDescr;
|
||||
// Assign epInfo to epinfo pointer
|
||||
rcode = pUsb->setEpInfoEntry(bAddress, 1, epInfo);
|
||||
|
||||
num_of_conf = ((USB_DEVICE_DESCRIPTOR*)buf)->bNumConfigurations;
|
||||
if (rcode)
|
||||
goto FailSetDevTblEntry;
|
||||
|
||||
// Assign epInfo to epinfo pointer
|
||||
rcode = pUsb->setEpInfoEntry(bAddress, 1, epInfo);
|
||||
USBTRACE2("NC:", num_of_conf);
|
||||
|
||||
if (rcode)
|
||||
goto FailSetDevTblEntry;
|
||||
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);
|
||||
|
||||
USBTRACE2("NC:", num_of_conf);
|
||||
//rcode = pUsb->getConfDescr(bAddress, 0, i, &HexDump);
|
||||
rcode = pUsb->getConfDescr(bAddress, 0, i, &confDescrParser);
|
||||
|
||||
for (uint8_t i=0; i<num_of_conf; i++)
|
||||
{
|
||||
//delay(1000);
|
||||
//HexDumper<USBReadParser, uint16_t, uint16_t> HexDump;
|
||||
ConfigDescParser<USB_CLASS_HID, 0, 0,
|
||||
CP_MASK_COMPARE_CLASS> confDescrParser(this);
|
||||
if (rcode)
|
||||
goto FailGetConfDescr;
|
||||
|
||||
//rcode = pUsb->getConfDescr(bAddress, 0, i, &HexDump);
|
||||
rcode = pUsb->getConfDescr(bAddress, 0, i, &confDescrParser);
|
||||
if (bNumEP > 1)
|
||||
break;
|
||||
} // for
|
||||
|
||||
if (bNumEP > 1)
|
||||
break;
|
||||
} // for
|
||||
if (bNumEP < 2)
|
||||
return USB_DEV_CONFIG_ERROR_DEVICE_NOT_SUPPORTED;
|
||||
|
||||
if (bNumEP < 2)
|
||||
return USB_DEV_CONFIG_ERROR_DEVICE_NOT_SUPPORTED;
|
||||
// Assign epInfo to epinfo pointer
|
||||
rcode = pUsb->setEpInfoEntry(bAddress, bNumEP, epInfo);
|
||||
|
||||
// Assign epInfo to epinfo pointer
|
||||
rcode = pUsb->setEpInfoEntry(bAddress, bNumEP, epInfo);
|
||||
USBTRACE2("\r\nCnf:", bConfNum);
|
||||
|
||||
USBTRACE2("\r\nCnf:", bConfNum);
|
||||
// Set Configuration Value
|
||||
rcode = pUsb->setConf(bAddress, 0, bConfNum);
|
||||
|
||||
// Set Configuration Value
|
||||
rcode = pUsb->setConf(bAddress, 0, bConfNum);
|
||||
if (rcode)
|
||||
goto FailSetConfDescr;
|
||||
|
||||
if (rcode)
|
||||
goto FailSetConfDescr;
|
||||
for (uint8_t i = 0; i < bNumIface; i++) {
|
||||
if (hidInterfaces[i].epIndex[epInterruptInIndex] == 0)
|
||||
continue;
|
||||
|
||||
for (uint8_t i=0; i<bNumIface; i++)
|
||||
{
|
||||
if (hidInterfaces[i].epIndex[epInterruptInIndex] == 0)
|
||||
continue;
|
||||
rcode = SetIdle(hidInterfaces[i].bmInterface, 0, 0);
|
||||
|
||||
rcode = SetIdle(hidInterfaces[i].bmInterface, 0, 0);
|
||||
if (rcode && rcode != hrSTALL)
|
||||
goto FailSetIdle;
|
||||
}
|
||||
|
||||
if (rcode && rcode != hrSTALL)
|
||||
goto FailSetIdle;
|
||||
}
|
||||
USBTRACE("HU configured\r\n");
|
||||
|
||||
USBTRACE("HU configured\r\n");
|
||||
OnInitSuccessful();
|
||||
|
||||
OnInitSuccessful();
|
||||
|
||||
bPollEnable = true;
|
||||
return 0;
|
||||
bPollEnable = true;
|
||||
return 0;
|
||||
|
||||
FailGetDevDescr:
|
||||
USBTRACE("getDevDescr:");
|
||||
goto Fail;
|
||||
USBTRACE("getDevDescr:");
|
||||
goto Fail;
|
||||
|
||||
FailSetDevTblEntry:
|
||||
USBTRACE("setDevTblEn:");
|
||||
goto Fail;
|
||||
USBTRACE("setDevTblEn:");
|
||||
goto Fail;
|
||||
|
||||
FailGetConfDescr:
|
||||
USBTRACE("getConf:");
|
||||
goto Fail;
|
||||
USBTRACE("getConf:");
|
||||
goto Fail;
|
||||
|
||||
FailSetConfDescr:
|
||||
USBTRACE("setConf:");
|
||||
goto Fail;
|
||||
|
||||
FailSetProtocol:
|
||||
USBTRACE("SetProto:");
|
||||
goto Fail;
|
||||
USBTRACE("setConf:");
|
||||
goto Fail;
|
||||
|
||||
FailSetIdle:
|
||||
USBTRACE("SetIdle:");
|
||||
goto Fail;
|
||||
|
||||
FailGetReportDescr:
|
||||
USBTRACE("GetReportDescr:");
|
||||
goto Fail;
|
||||
USBTRACE("SetIdle:");
|
||||
goto Fail;
|
||||
|
||||
Fail:
|
||||
Serial.println(rcode, HEX);
|
||||
Release();
|
||||
return rcode;
|
||||
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++)
|
||||
if (hidInterfaces[i].bmInterface == iface && hidInterfaces[i].bmAltSet == alt
|
||||
&& hidInterfaces[i].bmProtocol == proto)
|
||||
return hidInterfaces + i;
|
||||
return NULL;
|
||||
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)
|
||||
{
|
||||
// If the first configuration satisfies, the others are not concidered.
|
||||
if (bNumEP > 1 && conf != bConfNum)
|
||||
return;
|
||||
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;
|
||||
|
||||
//ErrorMessage<uint8_t>(PSTR("\r\nConf.Val"), conf);
|
||||
//ErrorMessage<uint8_t>(PSTR("Iface Num"), iface);
|
||||
//ErrorMessage<uint8_t>(PSTR("Alt.Set"), alt);
|
||||
//ErrorMessage<uint8_t>(PSTR("\r\nConf.Val"), conf);
|
||||
//ErrorMessage<uint8_t>(PSTR("Iface Num"), iface);
|
||||
//ErrorMessage<uint8_t>(PSTR("Alt.Set"), alt);
|
||||
|
||||
bConfNum = conf;
|
||||
bConfNum = conf;
|
||||
|
||||
uint8_t index = 0;
|
||||
HIDInterface *piface = FindInterface(iface, alt, proto);
|
||||
uint8_t index = 0;
|
||||
HIDInterface *piface = FindInterface(iface, alt, proto);
|
||||
|
||||
// Fill in interface structure in case of new interface
|
||||
if (!piface)
|
||||
{
|
||||
piface = hidInterfaces + bNumIface;
|
||||
piface->bmInterface = iface;
|
||||
piface->bmAltSet = alt;
|
||||
piface->bmProtocol = proto;
|
||||
bNumIface ++;
|
||||
}
|
||||
// Fill in interface structure in case of new interface
|
||||
if (!piface) {
|
||||
piface = hidInterfaces + bNumIface;
|
||||
piface->bmInterface = iface;
|
||||
piface->bmAltSet = alt;
|
||||
piface->bmProtocol = proto;
|
||||
bNumIface++;
|
||||
}
|
||||
|
||||
if ((pep->bmAttributes & 0x03) == 3 && (pep->bEndpointAddress & 0x80) == 0x80)
|
||||
index = epInterruptInIndex;
|
||||
else
|
||||
index = epInterruptOutIndex;
|
||||
if ((pep->bmAttributes & 0x03) == 3 && (pep->bEndpointAddress & 0x80) == 0x80)
|
||||
index = epInterruptInIndex;
|
||||
else
|
||||
index = epInterruptOutIndex;
|
||||
|
||||
if (index)
|
||||
{
|
||||
// Fill in the endpoint info structure
|
||||
epInfo[bNumEP].epAddr = (pep->bEndpointAddress & 0x0F);
|
||||
epInfo[bNumEP].maxPktSize = (uint8_t)pep->wMaxPacketSize;
|
||||
epInfo[bNumEP].epAttribs = 0;
|
||||
epInfo[bNumEP].bmNakPower = USB_NAK_NOWAIT;
|
||||
if (index) {
|
||||
// Fill in the endpoint info structure
|
||||
epInfo[bNumEP].epAddr = (pep->bEndpointAddress & 0x0F);
|
||||
epInfo[bNumEP].maxPktSize = (uint8_t)pep->wMaxPacketSize;
|
||||
epInfo[bNumEP].epAttribs = 0;
|
||||
epInfo[bNumEP].bmNakPower = USB_NAK_NOWAIT;
|
||||
|
||||
// Fill in the endpoint index list
|
||||
piface->epIndex[index] = bNumEP; //(pep->bEndpointAddress & 0x0F);
|
||||
// Fill in the endpoint index list
|
||||
piface->epIndex[index] = bNumEP; //(pep->bEndpointAddress & 0x0F);
|
||||
|
||||
bNumEP ++;
|
||||
}
|
||||
//PrintEndpointDescriptor(pep);
|
||||
bNumEP++;
|
||||
}
|
||||
//PrintEndpointDescriptor(pep);
|
||||
}
|
||||
|
||||
uint8_t HIDUniversal::Release() {
|
||||
pUsb->GetAddressPool().FreeAddress(bAddress);
|
||||
|
||||
uint8_t HIDUniversal::Release()
|
||||
{
|
||||
pUsb->GetAddressPool().FreeAddress(bAddress);
|
||||
|
||||
bNumEP = 1;
|
||||
bAddress = 0;
|
||||
qNextPollTime = 0;
|
||||
bPollEnable = false;
|
||||
return 0;
|
||||
bNumEP = 1;
|
||||
bAddress = 0;
|
||||
qNextPollTime = 0;
|
||||
bPollEnable = false;
|
||||
return 0;
|
||||
}
|
||||
|
||||
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;
|
||||
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++)
|
||||
buf[i] = 0;
|
||||
}
|
||||
void HIDUniversal::SaveBuffer(uint8_t len, uint8_t *src, uint8_t *dest)
|
||||
{
|
||||
for (uint8_t i=0; i<len; i++)
|
||||
dest[i] = src[i];
|
||||
void HIDUniversal::ZeroMemory(uint8_t len, uint8_t *buf) {
|
||||
for (uint8_t i = 0; i < len; i++)
|
||||
buf[i] = 0;
|
||||
}
|
||||
|
||||
uint8_t HIDUniversal::Poll()
|
||||
{
|
||||
uint8_t rcode = 0;
|
||||
|
||||
if (!bPollEnable)
|
||||
return 0;
|
||||
|
||||
if (qNextPollTime <= millis())
|
||||
{
|
||||
qNextPollTime = millis() + 50;
|
||||
|
||||
uint8_t buf[constBuffLen];
|
||||
|
||||
for (uint8_t i=0; i<bNumIface; i++)
|
||||
{
|
||||
uint8_t index = hidInterfaces[i].epIndex[epInterruptInIndex];
|
||||
uint16_t read = (uint16_t)epInfo[index].maxPktSize;
|
||||
|
||||
ZeroMemory(constBuffLen, buf);
|
||||
|
||||
uint8_t rcode = pUsb->inTransfer(bAddress, epInfo[index].epAddr, &read, buf);
|
||||
|
||||
if (rcode)
|
||||
{
|
||||
if (rcode != hrNAK)
|
||||
USBTRACE2("Poll:", rcode);
|
||||
return rcode;
|
||||
}
|
||||
|
||||
if (read > constBuffLen)
|
||||
read = constBuffLen;
|
||||
|
||||
bool identical = BuffersIdentical(read, buf, prevBuf);
|
||||
|
||||
SaveBuffer(read, buf, prevBuf);
|
||||
|
||||
if (identical)
|
||||
return 0;
|
||||
|
||||
Serial.print("\r\nBuf: ");
|
||||
|
||||
for (uint8_t i=0; i<read; i++)
|
||||
PrintHex<uint8_t>(buf[i]);
|
||||
|
||||
Serial.println("");
|
||||
|
||||
HIDReportParser *prs = GetReportParser( ((bHasReportId) ? *buf : 0) );
|
||||
|
||||
if (prs)
|
||||
prs->Parse(this, bHasReportId, (uint8_t)read, buf);
|
||||
}
|
||||
}
|
||||
return rcode;
|
||||
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 rcode = 0;
|
||||
|
||||
if (!bPollEnable)
|
||||
return 0;
|
||||
|
||||
if (qNextPollTime <= millis()) {
|
||||
qNextPollTime = millis() + 50;
|
||||
|
||||
uint8_t buf[constBuffLen];
|
||||
|
||||
for (uint8_t i = 0; i < bNumIface; i++) {
|
||||
uint8_t index = hidInterfaces[i].epIndex[epInterruptInIndex];
|
||||
uint16_t read = (uint16_t)epInfo[index].maxPktSize;
|
||||
|
||||
ZeroMemory(constBuffLen, buf);
|
||||
|
||||
uint8_t rcode = pUsb->inTransfer(bAddress, epInfo[index].epAddr, &read, buf);
|
||||
|
||||
if (rcode) {
|
||||
if (rcode != hrNAK)
|
||||
USBTRACE2("Poll:", rcode);
|
||||
return rcode;
|
||||
}
|
||||
|
||||
if (read > constBuffLen)
|
||||
read = constBuffLen;
|
||||
|
||||
bool identical = BuffersIdentical(read, buf, prevBuf);
|
||||
|
||||
SaveBuffer(read, buf, prevBuf);
|
||||
|
||||
if (identical)
|
||||
return 0;
|
||||
|
||||
Notify(PSTR("\r\nBuf: "), 0x80);
|
||||
|
||||
for (uint8_t i = 0; i < read; i++)
|
||||
PrintHex<uint8_t > (buf[i], 0x80);
|
||||
|
||||
Notify(PSTR("\r\n"), 0x80);
|
||||
|
||||
HIDReportParser *prs = GetReportParser(((bHasReportId) ? *buf : 0));
|
||||
|
||||
if (prs)
|
||||
prs->Parse(this, bHasReportId, (uint8_t)read, buf);
|
||||
}
|
||||
}
|
||||
return rcode;
|
||||
}
|
||||
|
|
102
hiduniversal.h
102
hiduniversal.h
|
@ -4,72 +4,76 @@
|
|||
#include "hid.h"
|
||||
//#include "hidescriptorparser.h"
|
||||
|
||||
class HIDUniversal : public HID
|
||||
{
|
||||
struct ReportParser
|
||||
{
|
||||
uint8_t rptId;
|
||||
HIDReportParser *rptParser;
|
||||
} rptParsers[MAX_REPORT_PARSERS];
|
||||
class HIDUniversal : public HID {
|
||||
|
||||
// HID class specific descriptor type and length info obtained from HID descriptor
|
||||
HID_CLASS_DESCRIPTOR_LEN_AND_TYPE descrInfo[HID_MAX_HID_CLASS_DESCRIPTORS];
|
||||
struct ReportParser {
|
||||
uint8_t rptId;
|
||||
HIDReportParser *rptParser;
|
||||
} rptParsers[MAX_REPORT_PARSERS];
|
||||
|
||||
// Returns HID class specific descriptor length by its type and order number
|
||||
uint16_t GetHidClassDescrLen(uint8_t type, uint8_t num);
|
||||
// HID class specific descriptor type and length info obtained from HID descriptor
|
||||
HID_CLASS_DESCRIPTOR_LEN_AND_TYPE descrInfo[HID_MAX_HID_CLASS_DESCRIPTORS];
|
||||
|
||||
EpInfo epInfo[totalEndpoints];
|
||||
// Returns HID class specific descriptor length by its type and order number
|
||||
uint16_t GetHidClassDescrLen(uint8_t type, uint8_t num);
|
||||
|
||||
struct HIDInterface
|
||||
{
|
||||
struct
|
||||
{
|
||||
uint8_t bmInterface : 3;
|
||||
uint8_t bmAltSet : 3;
|
||||
uint8_t bmProtocol : 2;
|
||||
};
|
||||
uint8_t epIndex[maxEpPerInterface];
|
||||
};
|
||||
EpInfo epInfo[totalEndpoints];
|
||||
|
||||
HIDInterface hidInterfaces[maxHidInterfaces];
|
||||
struct HIDInterface {
|
||||
|
||||
uint8_t bConfNum; // configuration number
|
||||
uint8_t bNumIface; // number of interfaces in the configuration
|
||||
uint8_t bNumEP; // total number of EP in the configuration
|
||||
uint32_t qNextPollTime; // next poll time
|
||||
bool bPollEnable; // poll enable flag
|
||||
struct {
|
||||
uint8_t bmInterface : 3;
|
||||
uint8_t bmAltSet : 3;
|
||||
uint8_t bmProtocol : 2;
|
||||
};
|
||||
uint8_t epIndex[maxEpPerInterface];
|
||||
};
|
||||
|
||||
static const uint16_t constBuffLen = 64; // event buffer length
|
||||
uint8_t prevBuf[constBuffLen]; // previous event buffer
|
||||
HIDInterface hidInterfaces[maxHidInterfaces];
|
||||
|
||||
void Initialize();
|
||||
HIDInterface* FindInterface(uint8_t iface, uint8_t alt, uint8_t proto);
|
||||
uint8_t bConfNum; // configuration number
|
||||
uint8_t bNumIface; // number of interfaces in the configuration
|
||||
uint8_t bNumEP; // total number of EP in the configuration
|
||||
uint32_t qNextPollTime; // next poll time
|
||||
bool bPollEnable; // poll enable flag
|
||||
|
||||
void ZeroMemory(uint8_t len, uint8_t *buf);
|
||||
bool BuffersIdentical(uint8_t len, uint8_t *buf1, uint8_t *buf2);
|
||||
void SaveBuffer(uint8_t len, uint8_t *src, uint8_t *dest);
|
||||
static const uint16_t constBuffLen = 64; // event buffer length
|
||||
uint8_t prevBuf[constBuffLen]; // previous event buffer
|
||||
|
||||
void Initialize();
|
||||
HIDInterface* FindInterface(uint8_t iface, uint8_t alt, uint8_t proto);
|
||||
|
||||
void ZeroMemory(uint8_t len, uint8_t *buf);
|
||||
bool BuffersIdentical(uint8_t len, uint8_t *buf1, uint8_t *buf2);
|
||||
void SaveBuffer(uint8_t len, uint8_t *src, uint8_t *dest);
|
||||
|
||||
protected:
|
||||
bool bHasReportId;
|
||||
bool bHasReportId;
|
||||
|
||||
// HID implementation
|
||||
virtual HIDReportParser* GetReportParser(uint8_t id);
|
||||
virtual uint8_t OnInitSuccessful() { return 0; };
|
||||
// HID implementation
|
||||
virtual HIDReportParser* GetReportParser(uint8_t id);
|
||||
|
||||
virtual uint8_t OnInitSuccessful() {
|
||||
return 0;
|
||||
};
|
||||
|
||||
public:
|
||||
HIDUniversal(USB *p);
|
||||
HIDUniversal(USB *p);
|
||||
|
||||
// HID implementation
|
||||
virtual bool SetReportParser(uint8_t id, HIDReportParser *prs);
|
||||
// HID implementation
|
||||
virtual bool SetReportParser(uint8_t id, HIDReportParser *prs);
|
||||
|
||||
// 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; };
|
||||
// USBDeviceConfig implementation
|
||||
virtual uint8_t Init(uint8_t parent, uint8_t port, bool lowspeed);
|
||||
virtual uint8_t Release();
|
||||
virtual uint8_t Poll();
|
||||
|
||||
// UsbConfigXtracter implementation
|
||||
virtual void EndpointXtract(uint8_t conf, uint8_t iface, uint8_t alt, uint8_t proto, const USB_ENDPOINT_DESCRIPTOR *ep);
|
||||
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);
|
||||
};
|
||||
|
||||
#endif // __HIDUNIVERSAL_H__
|
1720
hidusagestr.h
1720
hidusagestr.h
File diff suppressed because it is too large
Load diff
|
@ -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__
|
||||
|
||||
|
|
1253
masstorage.cpp
1253
masstorage.cpp
File diff suppressed because it is too large
Load diff
380
masstorage.h
380
masstorage.h
|
@ -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)))
|
||||
|
||||
|
@ -27,226 +27,250 @@
|
|||
#define bmREQ_MASSIN USB_SETUP_DEVICE_TO_HOST|USB_SETUP_TYPE_CLASS|USB_SETUP_RECIPIENT_INTERFACE
|
||||
|
||||
// Mass Storage Subclass Constants
|
||||
#define MASS_SUBCLASS_SCSI_NOT_REPORTED 0x00 // De facto use
|
||||
#define MASS_SUBCLASS_RBC 0x01
|
||||
#define MASS_SUBCLASS_ATAPI 0x02 // MMC-5 (ATAPI)
|
||||
#define MASS_SUBCLASS_OBSOLETE1 0x03 // Was QIC-157
|
||||
#define MASS_SUBCLASS_UFI 0x04 // Specifies how to interface Floppy Disk Drives to USB
|
||||
#define MASS_SUBCLASS_OBSOLETE2 0x05 // Was SFF-8070i
|
||||
#define MASS_SUBCLASS_SCSI 0x06 // SCSI Transparent Command Set
|
||||
#define MASS_SUBCLASS_LSDFS 0x07 // Specifies how host has to negotiate access before trying SCSI
|
||||
#define MASS_SUBCLASS_IEEE1667 0x08
|
||||
#define MASS_SUBCLASS_SCSI_NOT_REPORTED 0x00 // De facto use
|
||||
#define MASS_SUBCLASS_RBC 0x01
|
||||
#define MASS_SUBCLASS_ATAPI 0x02 // MMC-5 (ATAPI)
|
||||
#define MASS_SUBCLASS_OBSOLETE1 0x03 // Was QIC-157
|
||||
#define MASS_SUBCLASS_UFI 0x04 // Specifies how to interface Floppy Disk Drives to USB
|
||||
#define MASS_SUBCLASS_OBSOLETE2 0x05 // Was SFF-8070i
|
||||
#define MASS_SUBCLASS_SCSI 0x06 // SCSI Transparent Command Set
|
||||
#define MASS_SUBCLASS_LSDFS 0x07 // Specifies how host has to negotiate access before trying SCSI
|
||||
#define MASS_SUBCLASS_IEEE1667 0x08
|
||||
|
||||
// Mass Storage Class Protocols
|
||||
#define MASS_PROTO_CBI 0x00 // CBI (with command completion interrupt)
|
||||
#define MASS_PROTO_CBI_NO_INT 0x01 // CBI (without command completion interrupt)
|
||||
#define MASS_PROTO_OBSOLETE 0x02
|
||||
#define MASS_PROTO_BBB 0x50 // Bulk Only Transport
|
||||
#define MASS_PROTO_UAS 0x62
|
||||
#define MASS_PROTO_CBI 0x00 // CBI (with command completion interrupt)
|
||||
#define MASS_PROTO_CBI_NO_INT 0x01 // CBI (without command completion interrupt)
|
||||
#define MASS_PROTO_OBSOLETE 0x02
|
||||
#define MASS_PROTO_BBB 0x50 // Bulk Only Transport
|
||||
#define MASS_PROTO_UAS 0x62
|
||||
|
||||
// Request Codes
|
||||
#define MASS_REQ_ADSC 0x00
|
||||
#define MASS_REQ_GET 0xFC
|
||||
#define MASS_REQ_PUT 0xFD
|
||||
#define MASS_REQ_GET_MAX_LUN 0xFE
|
||||
#define MASS_REQ_BOMSR 0xFF // Bulk-Only Mass Storage Reset
|
||||
#define MASS_REQ_ADSC 0x00
|
||||
#define MASS_REQ_GET 0xFC
|
||||
#define MASS_REQ_PUT 0xFD
|
||||
#define MASS_REQ_GET_MAX_LUN 0xFE
|
||||
#define MASS_REQ_BOMSR 0xFF // Bulk-Only Mass Storage Reset
|
||||
|
||||
#define MASS_CBW_SIGNATURE 0x43425355
|
||||
#define MASS_CSW_SIGNATURE 0x53425355
|
||||
#define MASS_CBW_SIGNATURE 0x43425355
|
||||
#define MASS_CSW_SIGNATURE 0x53425355
|
||||
|
||||
#define MASS_CMD_DIR_OUT (0 << 7)
|
||||
#define MASS_CMD_DIR_IN (1 << 7)
|
||||
#define MASS_CMD_DIR_OUT (0 << 7)
|
||||
#define MASS_CMD_DIR_IN (1 << 7)
|
||||
|
||||
#define SCSI_CMD_INQUIRY 0x12
|
||||
#define SCSI_CMD_REPORT_LUNS 0xA0
|
||||
#define SCSI_CMD_REQUEST_SENSE 0x03
|
||||
#define SCSI_CMD_FORMAT_UNIT 0x04
|
||||
#define SCSI_CMD_READ_6 0x08
|
||||
#define SCSI_CMD_READ_10 0x28
|
||||
#define SCSI_CMD_READ_CAPACITY_10 0x25
|
||||
#define SCSI_CMD_TEST_UNIT_READY 0x00
|
||||
#define SCSI_CMD_WRITE_6 0x0A
|
||||
#define SCSI_CMD_WRITE_10 0x2A
|
||||
#define SCSI_CMD_MODE_SENSE_6 0x1A
|
||||
#define SCSI_CMD_MODE_SENSE_10 0x5A
|
||||
#define SCSI_CMD_INQUIRY 0x12
|
||||
#define SCSI_CMD_REPORT_LUNS 0xA0
|
||||
#define SCSI_CMD_REQUEST_SENSE 0x03
|
||||
#define SCSI_CMD_FORMAT_UNIT 0x04
|
||||
#define SCSI_CMD_READ_6 0x08
|
||||
#define SCSI_CMD_READ_10 0x28
|
||||
#define SCSI_CMD_READ_CAPACITY_10 0x25
|
||||
#define SCSI_CMD_TEST_UNIT_READY 0x00
|
||||
#define SCSI_CMD_WRITE_6 0x0A
|
||||
#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 MASS_ERR_SUCCESS 0x00
|
||||
#define MASS_ERR_PHASE_ERROR 0x01
|
||||
#define MASS_ERR_DEVICE_DISCONNECTED 0x11
|
||||
#define MASS_ERR_UNABLE_TO_RECOVER 0x12 // Reset recovery error
|
||||
#define MASS_ERR_GENERAL_USB_ERROR 0xFF
|
||||
#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 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
|
||||
#define SCSI_ASC_MEDIUM_NOT_PRESENT 0x3A
|
||||
#define SCSI_ASC_LBA_OUT_OF_RANGE 0x21
|
||||
|
||||
|
||||
struct Capacity
|
||||
{
|
||||
uint8_t data[8];
|
||||
//uint32_t dwBlockAddress;
|
||||
//uint32_t dwBlockLength;
|
||||
};
|
||||
#define MASS_ERR_SUCCESS 0x00
|
||||
#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
|
||||
|
||||
struct InquiryResponse
|
||||
{
|
||||
uint8_t DeviceType : 5;
|
||||
uint8_t PeripheralQualifier : 3;
|
||||
#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
|
||||
|
||||
unsigned Reserved : 7;
|
||||
unsigned Removable : 1;
|
||||
struct Capacity {
|
||||
uint8_t data[8];
|
||||
//uint32_t dwBlockAddress;
|
||||
//uint32_t dwBlockLength;
|
||||
} __attribute__((packed));
|
||||
|
||||
uint8_t Version;
|
||||
struct InquiryResponse {
|
||||
uint8_t DeviceType : 5;
|
||||
uint8_t PeripheralQualifier : 3;
|
||||
|
||||
unsigned ResponseDataFormat : 4;
|
||||
unsigned Reserved2 : 1;
|
||||
unsigned NormACA : 1;
|
||||
unsigned TrmTsk : 1;
|
||||
unsigned AERC : 1;
|
||||
unsigned Reserved : 7;
|
||||
unsigned Removable : 1;
|
||||
|
||||
uint8_t AdditionalLength;
|
||||
uint8_t Reserved3[2];
|
||||
uint8_t Version;
|
||||
|
||||
unsigned SoftReset : 1;
|
||||
unsigned CmdQue : 1;
|
||||
unsigned Reserved4 : 1;
|
||||
unsigned Linked : 1;
|
||||
unsigned Sync : 1;
|
||||
unsigned WideBus16Bit : 1;
|
||||
unsigned WideBus32Bit : 1;
|
||||
unsigned RelAddr : 1;
|
||||
unsigned ResponseDataFormat : 4;
|
||||
unsigned Reserved2 : 1;
|
||||
unsigned NormACA : 1;
|
||||
unsigned TrmTsk : 1;
|
||||
unsigned AERC : 1;
|
||||
|
||||
uint8_t VendorID[8];
|
||||
uint8_t ProductID[16];
|
||||
uint8_t RevisionID[4];
|
||||
};
|
||||
uint8_t AdditionalLength;
|
||||
uint8_t Reserved3[2];
|
||||
|
||||
struct CommandBlockWrapper
|
||||
{
|
||||
uint32_t dCBWSignature;
|
||||
uint32_t dCBWTag;
|
||||
uint32_t dCBWDataTransferLength;
|
||||
uint8_t bmCBWFlags;
|
||||
unsigned SoftReset : 1;
|
||||
unsigned CmdQue : 1;
|
||||
unsigned Reserved4 : 1;
|
||||
unsigned Linked : 1;
|
||||
unsigned Sync : 1;
|
||||
unsigned WideBus16Bit : 1;
|
||||
unsigned WideBus32Bit : 1;
|
||||
unsigned RelAddr : 1;
|
||||
|
||||
struct
|
||||
{
|
||||
uint8_t bmCBWLUN : 4;
|
||||
uint8_t bmReserved1 : 4;
|
||||
};
|
||||
struct
|
||||
{
|
||||
uint8_t bmCBWCBLength : 4;
|
||||
uint8_t bmReserved2 : 4;
|
||||
};
|
||||
uint8_t VendorID[8];
|
||||
uint8_t ProductID[16];
|
||||
uint8_t RevisionID[4];
|
||||
} __attribute__((packed));
|
||||
|
||||
uint8_t CBWCB[16];
|
||||
} ;
|
||||
struct CommandBlockWrapperBase {
|
||||
uint32_t dCBWSignature;
|
||||
uint32_t dCBWTag;
|
||||
uint32_t dCBWDataTransferLength;
|
||||
uint8_t bmCBWFlags;
|
||||
} __attribute__((packed));
|
||||
|
||||
struct CommandStatusWrapper
|
||||
{
|
||||
uint32_t dCSWSignature;
|
||||
uint32_t dCSWTag;
|
||||
uint32_t dCSWDataResidue;
|
||||
uint8_t bCSWStatus;
|
||||
};
|
||||
struct CommandBlockWrapper : public CommandBlockWrapperBase {
|
||||
|
||||
struct RequestSenseResponce
|
||||
{
|
||||
uint8_t bResponseCode;
|
||||
uint8_t bSegmentNumber;
|
||||
struct {
|
||||
uint8_t bmCBWLUN : 4;
|
||||
uint8_t bmReserved1 : 4;
|
||||
};
|
||||
|
||||
uint8_t bmSenseKey : 4;
|
||||
uint8_t bmReserved : 1;
|
||||
uint8_t bmILI : 1;
|
||||
uint8_t bmEOM : 1;
|
||||
uint8_t bmFileMark : 1;
|
||||
struct {
|
||||
uint8_t bmCBWCBLength : 4;
|
||||
uint8_t bmReserved2 : 4;
|
||||
};
|
||||
|
||||
uint8_t Information[4];
|
||||
uint8_t bAdditionalLength;
|
||||
uint8_t CmdSpecificInformation[4];
|
||||
uint8_t bAdditionalSenseCode;
|
||||
uint8_t bAdditionalSenseQualifier;
|
||||
uint8_t bFieldReplaceableUnitCode;
|
||||
uint8_t SenseKeySpecific[3];
|
||||
};
|
||||
uint8_t CBWCB[16];
|
||||
} __attribute__((packed));
|
||||
|
||||
//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;
|
||||
//};
|
||||
struct CommandStatusWrapper {
|
||||
uint32_t dCSWSignature;
|
||||
uint32_t dCSWTag;
|
||||
uint32_t dCSWDataResidue;
|
||||
uint8_t bCSWStatus;
|
||||
} __attribute__((packed));
|
||||
|
||||
struct RequestSenseResponce {
|
||||
uint8_t bResponseCode;
|
||||
uint8_t bSegmentNumber;
|
||||
|
||||
uint8_t bmSenseKey : 4;
|
||||
uint8_t bmReserved : 1;
|
||||
uint8_t bmILI : 1;
|
||||
uint8_t bmEOM : 1;
|
||||
uint8_t bmFileMark : 1;
|
||||
|
||||
uint8_t Information[4];
|
||||
uint8_t bAdditionalLength;
|
||||
uint8_t CmdSpecificInformation[4];
|
||||
uint8_t bAdditionalSenseCode;
|
||||
uint8_t bAdditionalSenseQualifier;
|
||||
uint8_t bFieldReplaceableUnitCode;
|
||||
uint8_t SenseKeySpecific[3];
|
||||
} __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
|
||||
static const uint8_t epInterruptInIndex; // InterruptIN endpoint index
|
||||
static const uint8_t epDataInIndex; // DataIn endpoint index
|
||||
static const uint8_t epDataOutIndex; // DataOUT endpoint index
|
||||
static const uint8_t epInterruptInIndex; // InterruptIN endpoint index
|
||||
|
||||
USB *pUsb;
|
||||
uint8_t bAddress;
|
||||
uint8_t bConfNum; // configuration number
|
||||
uint8_t bIface; // interface value
|
||||
uint8_t bNumEP; // total number of EP in the configuration
|
||||
uint32_t qNextPollTime; // next poll time
|
||||
bool bPollEnable; // poll enable flag
|
||||
USB *pUsb;
|
||||
uint8_t bAddress;
|
||||
uint8_t bConfNum; // configuration number
|
||||
uint8_t bIface; // interface value
|
||||
uint8_t bNumEP; // total number of EP in the configuration
|
||||
uint32_t qNextPollTime; // next poll time
|
||||
bool bPollEnable; // poll enable flag
|
||||
|
||||
EpInfo epInfo[MASS_MAX_ENDPOINTS];
|
||||
EpInfo epInfo[MASS_MAX_ENDPOINTS];
|
||||
|
||||
uint32_t dCBWTag; // Tag
|
||||
uint32_t dCBWDataTransferLength; // Data Transfer Length
|
||||
uint8_t bMaxLUN; // Max LUN
|
||||
uint8_t bLastUsbError; // Last USB error
|
||||
uint32_t dCBWTag; // Tag
|
||||
uint32_t dCBWDataTransferLength; // Data Transfer Length
|
||||
uint8_t bLastUsbError; // Last USB error
|
||||
uint8_t bMaxLUN; // Max LUN
|
||||
uint8_t bTheLUN; // Active LUN
|
||||
|
||||
protected:
|
||||
//union TransFlags
|
||||
//{
|
||||
// uint8_t nValue;
|
||||
void PrintEndpointDescriptor(const USB_ENDPOINT_DESCRIPTOR* ep_ptr);
|
||||
|
||||
// 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 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 ClearEpHalt(uint8_t index);
|
||||
uint8_t Transaction(CommandBlockWrapper *cbw, uint16_t bsize, void *buf, uint8_t flags);
|
||||
uint8_t HandleUsbError(uint8_t error, uint8_t index);
|
||||
uint8_t HandleSCSIError(uint8_t status);
|
||||
|
||||
public:
|
||||
BulkOnly(USB *p);
|
||||
uint8_t GetLastUsbError() { return bLastUsbError; };
|
||||
BulkOnly(USB *p);
|
||||
|
||||
uint8_t Reset();
|
||||
uint8_t GetMaxLUN(uint8_t *max_lun);
|
||||
uint8_t GetLastUsbError() {
|
||||
return bLastUsbError;
|
||||
};
|
||||
|
||||
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 GetbMaxLUN() {
|
||||
return bMaxLUN; // Max LUN
|
||||
}
|
||||
|
||||
// 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; };
|
||||
uint8_t GetbTheLUN() {
|
||||
return bTheLUN; // Active LUN
|
||||
}
|
||||
|
||||
// UsbConfigXtracter implementation
|
||||
virtual void EndpointXtract(uint8_t conf, uint8_t iface, uint8_t alt, uint8_t proto, const USB_ENDPOINT_DESCRIPTOR *ep);
|
||||
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 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;
|
||||
};
|
||||
|
||||
// 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__
|
|
@ -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_
|
||||
|
|
254
max_LCD.cpp
254
max_LCD.cpp
|
@ -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"
|
||||
|
||||
|
@ -47,204 +47,210 @@ e-mail : support@circuitsathome.com
|
|||
sendbyte(a); \
|
||||
}
|
||||
|
||||
static byte lcdPins; //copy of LCD pins
|
||||
static byte lcdPins; //copy of LCD pins
|
||||
|
||||
Max_LCD::Max_LCD(USB *pusb) : pUsb(pusb)
|
||||
{
|
||||
lcdPins = 0;
|
||||
Max_LCD::Max_LCD(USB *pusb) : pUsb(pusb) {
|
||||
lcdPins = 0;
|
||||
}
|
||||
|
||||
void Max_LCD::init() {
|
||||
_displayfunction = LCD_4BITMODE | LCD_1LINE | LCD_5x8DOTS;
|
||||
|
||||
void Max_LCD::init()
|
||||
{
|
||||
_displayfunction = LCD_4BITMODE | LCD_1LINE | LCD_5x8DOTS;
|
||||
// MAX3421E::gpioWr(0x55);
|
||||
|
||||
// MAX3421E::gpioWr(0x55);
|
||||
|
||||
begin(16, 1);
|
||||
begin(16, 1);
|
||||
}
|
||||
|
||||
void Max_LCD::begin(uint8_t cols, uint8_t lines, uint8_t dotsize) {
|
||||
if (lines > 1) {
|
||||
_displayfunction |= LCD_2LINE;
|
||||
}
|
||||
_numlines = lines;
|
||||
_currline = 0;
|
||||
if (lines > 1) {
|
||||
_displayfunction |= LCD_2LINE;
|
||||
}
|
||||
_numlines = lines;
|
||||
_currline = 0;
|
||||
|
||||
// for some 1 line displays you can select a 10 pixel high font
|
||||
if ((dotsize != 0) && (lines == 1)) {
|
||||
_displayfunction |= LCD_5x10DOTS;
|
||||
}
|
||||
// for some 1 line displays you can select a 10 pixel high font
|
||||
if ((dotsize != 0) && (lines == 1)) {
|
||||
_displayfunction |= LCD_5x10DOTS;
|
||||
}
|
||||
|
||||
// SEE PAGE 45/46 FOR INITIALIZATION SPECIFICATION!
|
||||
// according to datasheet, we need at least 40ms after power rises above 2.7V
|
||||
// before sending commands. Arduino can turn on way befer 4.5V so we'll wait 50
|
||||
delayMicroseconds(50000);
|
||||
lcdPins = 0x30;
|
||||
SET_E;
|
||||
SENDlcdPins();
|
||||
CLR_E;
|
||||
SENDlcdPins();
|
||||
delayMicroseconds(10000); // wait min 4.1ms
|
||||
//second try
|
||||
SET_E;
|
||||
SENDlcdPins();
|
||||
CLR_E;
|
||||
SENDlcdPins();
|
||||
delayMicroseconds(10000); // wait min 4.1ms
|
||||
// third go!
|
||||
SET_E;
|
||||
SENDlcdPins();
|
||||
CLR_E;
|
||||
SENDlcdPins();
|
||||
delayMicroseconds(10000);
|
||||
// finally, set to 4-bit interface
|
||||
lcdPins = 0x20;
|
||||
//SET_RS;
|
||||
SET_E;
|
||||
SENDlcdPins();
|
||||
//CLR_RS;
|
||||
CLR_E;
|
||||
SENDlcdPins();
|
||||
delayMicroseconds(10000);
|
||||
// finally, set # lines, font size, etc.
|
||||
command(LCD_FUNCTIONSET | _displayfunction);
|
||||
// SEE PAGE 45/46 FOR INITIALIZATION SPECIFICATION!
|
||||
// according to datasheet, we need at least 40ms after power rises above 2.7V
|
||||
// before sending commands. Arduino can turn on way befer 4.5V so we'll wait 50
|
||||
delayMicroseconds(50000);
|
||||
lcdPins = 0x30;
|
||||
SET_E;
|
||||
SENDlcdPins();
|
||||
CLR_E;
|
||||
SENDlcdPins();
|
||||
delayMicroseconds(10000); // wait min 4.1ms
|
||||
//second try
|
||||
SET_E;
|
||||
SENDlcdPins();
|
||||
CLR_E;
|
||||
SENDlcdPins();
|
||||
delayMicroseconds(10000); // wait min 4.1ms
|
||||
// third go!
|
||||
SET_E;
|
||||
SENDlcdPins();
|
||||
CLR_E;
|
||||
SENDlcdPins();
|
||||
delayMicroseconds(10000);
|
||||
// finally, set to 4-bit interface
|
||||
lcdPins = 0x20;
|
||||
//SET_RS;
|
||||
SET_E;
|
||||
SENDlcdPins();
|
||||
//CLR_RS;
|
||||
CLR_E;
|
||||
SENDlcdPins();
|
||||
delayMicroseconds(10000);
|
||||
// finally, set # lines, font size, etc.
|
||||
command(LCD_FUNCTIONSET | _displayfunction);
|
||||
|
||||
// turn the display on with no cursor or blinking default
|
||||
_displaycontrol = LCD_DISPLAYON | LCD_CURSOROFF | LCD_BLINKOFF;
|
||||
display();
|
||||
// turn the display on with no cursor or blinking default
|
||||
_displaycontrol = LCD_DISPLAYON | LCD_CURSOROFF | LCD_BLINKOFF;
|
||||
display();
|
||||
|
||||
// clear it off
|
||||
clear();
|
||||
// clear it off
|
||||
clear();
|
||||
|
||||
// Initialize to default text direction (for romance languages)
|
||||
_displaymode = LCD_ENTRYLEFT | LCD_ENTRYSHIFTDECREMENT;
|
||||
// set the entry mode
|
||||
command(LCD_ENTRYMODESET | _displaymode);
|
||||
// Initialize to default text direction (for romance languages)
|
||||
_displaymode = LCD_ENTRYLEFT | LCD_ENTRYSHIFTDECREMENT;
|
||||
// set the entry mode
|
||||
command(LCD_ENTRYMODESET | _displaymode);
|
||||
}
|
||||
|
||||
/********** high level commands, for the user! */
|
||||
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::clear() {
|
||||
command(LCD_CLEARDISPLAY); // clear display, set cursor position to zero
|
||||
delayMicroseconds(2000); // this command takes a long time!
|
||||
}
|
||||
|
||||
void Max_LCD::home()
|
||||
{
|
||||
command(LCD_RETURNHOME); // set cursor position to zero
|
||||
delayMicroseconds(2000); // this command takes a long time!
|
||||
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]));
|
||||
command(LCD_SETDDRAMADDR | (col + row_offsets[row]));
|
||||
}
|
||||
|
||||
// Turn the display on/off (quickly)
|
||||
|
||||
void Max_LCD::noDisplay() {
|
||||
_displaycontrol &= ~LCD_DISPLAYON;
|
||||
command(LCD_DISPLAYCONTROL | _displaycontrol);
|
||||
_displaycontrol &= ~LCD_DISPLAYON;
|
||||
command(LCD_DISPLAYCONTROL | _displaycontrol);
|
||||
}
|
||||
|
||||
void Max_LCD::display() {
|
||||
_displaycontrol |= LCD_DISPLAYON;
|
||||
command(LCD_DISPLAYCONTROL | _displaycontrol);
|
||||
_displaycontrol |= LCD_DISPLAYON;
|
||||
command(LCD_DISPLAYCONTROL | _displaycontrol);
|
||||
}
|
||||
|
||||
// Turns the underline cursor on/off
|
||||
|
||||
void Max_LCD::noCursor() {
|
||||
_displaycontrol &= ~LCD_CURSORON;
|
||||
command(LCD_DISPLAYCONTROL | _displaycontrol);
|
||||
_displaycontrol &= ~LCD_CURSORON;
|
||||
command(LCD_DISPLAYCONTROL | _displaycontrol);
|
||||
}
|
||||
|
||||
void Max_LCD::cursor() {
|
||||
_displaycontrol |= LCD_CURSORON;
|
||||
command(LCD_DISPLAYCONTROL | _displaycontrol);
|
||||
_displaycontrol |= LCD_CURSORON;
|
||||
command(LCD_DISPLAYCONTROL | _displaycontrol);
|
||||
}
|
||||
|
||||
|
||||
// Turn on and off the blinking cursor
|
||||
|
||||
void Max_LCD::noBlink() {
|
||||
_displaycontrol &= ~LCD_BLINKON;
|
||||
command(LCD_DISPLAYCONTROL | _displaycontrol);
|
||||
_displaycontrol &= ~LCD_BLINKON;
|
||||
command(LCD_DISPLAYCONTROL | _displaycontrol);
|
||||
}
|
||||
|
||||
void Max_LCD::blink() {
|
||||
_displaycontrol |= LCD_BLINKON;
|
||||
command(LCD_DISPLAYCONTROL | _displaycontrol);
|
||||
_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);
|
||||
command(LCD_CURSORSHIFT | LCD_DISPLAYMOVE | LCD_MOVELEFT);
|
||||
}
|
||||
|
||||
void Max_LCD::scrollDisplayRight(void) {
|
||||
command(LCD_CURSORSHIFT | LCD_DISPLAYMOVE | LCD_MOVERIGHT);
|
||||
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);
|
||||
_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);
|
||||
_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);
|
||||
_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);
|
||||
_displaymode &= ~LCD_ENTRYSHIFTINCREMENT;
|
||||
command(LCD_ENTRYMODESET | _displaymode);
|
||||
}
|
||||
|
||||
// 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++) {
|
||||
write(charmap[i]);
|
||||
}
|
||||
location &= 0x7; // we only have 8 locations 0-7
|
||||
command(LCD_SETCGRAMADDR | (location << 3));
|
||||
for (int i = 0; i < 8; i++) {
|
||||
write(charmap[i]);
|
||||
}
|
||||
}
|
||||
|
||||
/*********** mid level commands, for sending data/cmds */
|
||||
|
||||
inline void Max_LCD::command(uint8_t value) {
|
||||
LCD_sendcmd(value);
|
||||
delayMicroseconds(100);
|
||||
LCD_sendcmd(value);
|
||||
delayMicroseconds(100);
|
||||
}
|
||||
|
||||
inline void Max_LCD::write(uint8_t value) {
|
||||
LCD_sendchar(value);
|
||||
LCD_sendchar(value);
|
||||
}
|
||||
|
||||
void Max_LCD::sendbyte( uint8_t val )
|
||||
{
|
||||
lcdPins &= 0x0f; //prepare place for the upper nibble
|
||||
lcdPins |= ( val & 0xf0 ); //copy upper nibble to LCD variable
|
||||
SET_E; //send
|
||||
SENDlcdPins();
|
||||
delayMicroseconds(2);
|
||||
CLR_E;
|
||||
delayMicroseconds(2);
|
||||
SENDlcdPins();
|
||||
lcdPins &= 0x0f; //prepare place for the lower nibble
|
||||
lcdPins |= ( val << 4 ) & 0xf0; //copy lower nibble to LCD variable
|
||||
SET_E; //send
|
||||
SENDlcdPins();
|
||||
CLR_E;
|
||||
SENDlcdPins();
|
||||
delayMicroseconds(100);
|
||||
void Max_LCD::sendbyte(uint8_t val) {
|
||||
lcdPins &= 0x0f; //prepare place for the upper nibble
|
||||
lcdPins |= (val & 0xf0); //copy upper nibble to LCD variable
|
||||
SET_E; //send
|
||||
SENDlcdPins();
|
||||
delayMicroseconds(2);
|
||||
CLR_E;
|
||||
delayMicroseconds(2);
|
||||
SENDlcdPins();
|
||||
lcdPins &= 0x0f; //prepare place for the lower nibble
|
||||
lcdPins |= (val << 4) & 0xf0; //copy lower nibble to LCD variable
|
||||
SET_E; //send
|
||||
SENDlcdPins();
|
||||
CLR_E;
|
||||
SENDlcdPins();
|
||||
delayMicroseconds(100);
|
||||
}
|
||||
|
|
58
max_LCD.h
58
max_LCD.h
|
@ -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]
|
||||
//
|
||||
|
@ -65,38 +65,38 @@ e-mail : support@circuitsathome.com
|
|||
|
||||
class Max_LCD //: public Print
|
||||
{
|
||||
USB *pUsb;
|
||||
USB *pUsb;
|
||||
|
||||
public:
|
||||
Max_LCD(USB *pusb);
|
||||
void init();
|
||||
void begin(uint8_t cols, uint8_t rows, uint8_t charsize = LCD_5x8DOTS);
|
||||
void clear();
|
||||
void home();
|
||||
void noDisplay();
|
||||
void display();
|
||||
void noBlink();
|
||||
void blink();
|
||||
void noCursor();
|
||||
void cursor();
|
||||
void scrollDisplayLeft();
|
||||
void scrollDisplayRight();
|
||||
void leftToRight();
|
||||
void rightToLeft();
|
||||
void autoscroll();
|
||||
void noAutoscroll();
|
||||
void createChar(uint8_t, uint8_t[]);
|
||||
void setCursor(uint8_t, uint8_t);
|
||||
virtual void write(uint8_t);
|
||||
void command(uint8_t);
|
||||
Max_LCD(USB *pusb);
|
||||
void init();
|
||||
void begin(uint8_t cols, uint8_t rows, uint8_t charsize = LCD_5x8DOTS);
|
||||
void clear();
|
||||
void home();
|
||||
void noDisplay();
|
||||
void display();
|
||||
void noBlink();
|
||||
void blink();
|
||||
void noCursor();
|
||||
void cursor();
|
||||
void scrollDisplayLeft();
|
||||
void scrollDisplayRight();
|
||||
void leftToRight();
|
||||
void rightToLeft();
|
||||
void autoscroll();
|
||||
void noAutoscroll();
|
||||
void createChar(uint8_t, uint8_t[]);
|
||||
void setCursor(uint8_t, uint8_t);
|
||||
virtual void write(uint8_t);
|
||||
void command(uint8_t);
|
||||
|
||||
private:
|
||||
void sendbyte( uint8_t val );
|
||||
uint8_t _displayfunction; //tokill
|
||||
uint8_t _displaycontrol;
|
||||
uint8_t _displaymode;
|
||||
uint8_t _initialized;
|
||||
uint8_t _numlines,_currline;
|
||||
void sendbyte(uint8_t val);
|
||||
uint8_t _displayfunction; //tokill
|
||||
uint8_t _displaycontrol;
|
||||
uint8_t _displaymode;
|
||||
uint8_t _initialized;
|
||||
uint8_t _numlines, _currline;
|
||||
};
|
||||
|
||||
#endif
|
36
message.cpp
36
message.cpp
|
@ -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);
|
||||
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);
|
||||
}
|
||||
|
|
18
message.h
18
message.h
|
@ -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);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -13,60 +13,55 @@ 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"));
|
||||
return false;
|
||||
}
|
||||
for (; countDown && (*pcntdn); countDown--, (*pcntdn)--, (*pp)++)
|
||||
pBuf[valueSize-countDown] = (**pp);
|
||||
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);
|
||||
|
||||
if (countDown)
|
||||
return false;
|
||||
if (countDown)
|
||||
return false;
|
||||
|
||||
countDown = valueSize;
|
||||
return true;
|
||||
countDown = valueSize;
|
||||
return true;
|
||||
}
|
||||
|
||||
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);
|
||||
nStage = 1;
|
||||
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);
|
||||
nStage = 1;
|
||||
|
||||
case 1:
|
||||
if (!theParser.Parse(pp, pcntdn))
|
||||
return false;
|
||||
case 1:
|
||||
if (!theParser.Parse(pp, pcntdn))
|
||||
return false;
|
||||
|
||||
arLen = 0;
|
||||
arLen = (pBuf->valueSize >= 4) ? *((uint32_t*)pBuf->pValue) : (uint32_t)(*((uint16_t*)pBuf->pValue));
|
||||
arLenCntdn = arLen;
|
||||
nStage = 2;
|
||||
arLen = 0;
|
||||
arLen = (pBuf->valueSize >= 4) ? *((uint32_t*)pBuf->pValue) : (uint32_t)(*((uint16_t*)pBuf->pValue));
|
||||
arLenCntdn = arLen;
|
||||
nStage = 2;
|
||||
|
||||
case 2:
|
||||
pBuf->valueSize = valSize;
|
||||
theParser.Initialize(pBuf);
|
||||
nStage = 3;
|
||||
case 2:
|
||||
pBuf->valueSize = valSize;
|
||||
theParser.Initialize(pBuf);
|
||||
nStage = 3;
|
||||
|
||||
case 3:
|
||||
for (; arLenCntdn; arLenCntdn--)
|
||||
{
|
||||
if (!theParser.Parse(pp, pcntdn))
|
||||
return false;
|
||||
case 3:
|
||||
for (; arLenCntdn; arLenCntdn--) {
|
||||
if (!theParser.Parse(pp, pcntdn))
|
||||
return false;
|
||||
|
||||
if (pf)
|
||||
pf(pBuf, (arLen - arLenCntdn), me);
|
||||
}
|
||||
if (pf)
|
||||
pf(pBuf, (arLen - arLenCntdn), me);
|
||||
}
|
||||
|
||||
nStage = 0;
|
||||
}
|
||||
return true;
|
||||
nStage = 0;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
|
172
parsetools.h
172
parsetools.h
|
@ -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,123 +29,121 @@ e-mail : support@circuitsathome.com
|
|||
#include <WProgram.h>
|
||||
#endif
|
||||
|
||||
struct MultiValueBuffer
|
||||
{
|
||||
uint8_t valueSize;
|
||||
void *pValue;
|
||||
};
|
||||
struct MultiValueBuffer {
|
||||
uint8_t valueSize;
|
||||
void *pValue;
|
||||
} __attribute__((packed));
|
||||
|
||||
class MultiByteValueParser
|
||||
{
|
||||
uint8_t * pBuf;
|
||||
uint8_t countDown;
|
||||
uint8_t valueSize;
|
||||
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;
|
||||
countDown = valueSize = pbuf->valueSize;
|
||||
};
|
||||
const uint8_t* GetBuffer() {
|
||||
return pBuf;
|
||||
};
|
||||
|
||||
bool Parse(uint8_t **pp, uint16_t *pcntdn);
|
||||
void Initialize(MultiValueBuffer * const pbuf) {
|
||||
pBuf = (uint8_t*) pbuf->pValue;
|
||||
countDown = valueSize = pbuf->valueSize;
|
||||
};
|
||||
|
||||
bool Parse(uint8_t **pp, uint16_t *pcntdn);
|
||||
};
|
||||
|
||||
class ByteSkipper
|
||||
{
|
||||
uint8_t *pBuf;
|
||||
uint8_t nStage;
|
||||
uint16_t countDown;
|
||||
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;
|
||||
countDown = 0;
|
||||
};
|
||||
ByteSkipper() : pBuf(NULL), nStage(0), countDown(0) {
|
||||
};
|
||||
|
||||
bool Skip(uint8_t **pp, uint16_t *pcntdn, uint16_t bytes_to_skip)
|
||||
{
|
||||
switch (nStage)
|
||||
{
|
||||
case 0:
|
||||
countDown = bytes_to_skip;
|
||||
nStage ++;
|
||||
case 1:
|
||||
for (; countDown && (*pcntdn); countDown--, (*pp)++, (*pcntdn)--);
|
||||
void Initialize(MultiValueBuffer *pbuf) {
|
||||
pBuf = (uint8_t*) pbuf->pValue;
|
||||
countDown = 0;
|
||||
};
|
||||
|
||||
if (!countDown)
|
||||
nStage = 0;
|
||||
};
|
||||
return (!countDown);
|
||||
};
|
||||
bool Skip(uint8_t **pp, uint16_t *pcntdn, uint16_t bytes_to_skip) {
|
||||
switch(nStage) {
|
||||
case 0:
|
||||
countDown = bytes_to_skip;
|
||||
nStage++;
|
||||
case 1:
|
||||
for(; countDown && (*pcntdn); countDown--, (*pp)++, (*pcntdn)--);
|
||||
|
||||
if(!countDown)
|
||||
nStage = 0;
|
||||
};
|
||||
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;
|
||||
uint8_t enStage;
|
||||
uint8_t nStage;
|
||||
uint8_t enStage;
|
||||
|
||||
uint32_t arLen;
|
||||
uint32_t arLenCntdn;
|
||||
uint32_t arLen;
|
||||
uint32_t arLenCntdn;
|
||||
|
||||
uint8_t lenSize; // size of the array length field in bytes
|
||||
uint8_t valSize; // size of the array element in bytes
|
||||
uint8_t lenSize; // size of the array length field in bytes
|
||||
uint8_t valSize; // size of the array element in bytes
|
||||
|
||||
MultiValueBuffer *pBuf;
|
||||
MultiValueBuffer *pBuf;
|
||||
|
||||
// The only parser for both size and array element parsing
|
||||
MultiByteValueParser theParser;
|
||||
// The only parser for both size and array element parsing
|
||||
MultiByteValueParser theParser;
|
||||
|
||||
uint8_t /*ParseMode*/ prsMode;
|
||||
uint8_t /*ParseMode*/ prsMode;
|
||||
|
||||
public:
|
||||
PTPListParser() :
|
||||
pBuf(NULL),
|
||||
nStage(0),
|
||||
enStage(0),
|
||||
arLenCntdn(0),
|
||||
arLen(0),
|
||||
lenSize(0),
|
||||
valSize(0),
|
||||
prsMode(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;
|
||||
PTPListParser() :
|
||||
nStage(0),
|
||||
enStage(0),
|
||||
arLen(0),
|
||||
arLenCntdn(0),
|
||||
lenSize(0),
|
||||
valSize(0),
|
||||
pBuf(NULL),
|
||||
prsMode(modeArray) {
|
||||
};
|
||||
|
||||
if (prsMode == modeRange)
|
||||
{
|
||||
arLenCntdn = arLen = 3;
|
||||
nStage = 2;
|
||||
}
|
||||
else
|
||||
{
|
||||
arLenCntdn = arLen = 0;
|
||||
nStage = 0;
|
||||
}
|
||||
enStage = 0;
|
||||
theParser.Initialize(p);
|
||||
};
|
||||
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;
|
||||
|
||||
bool Parse(uint8_t **pp, uint16_t *pcntdn, PTP_ARRAY_EL_FUNC pf, const void *me = NULL);
|
||||
if(prsMode == modeRange) {
|
||||
arLenCntdn = arLen = 3;
|
||||
nStage = 2;
|
||||
} else {
|
||||
arLenCntdn = arLen = 0;
|
||||
nStage = 0;
|
||||
}
|
||||
enStage = 0;
|
||||
theParser.Initialize(p);
|
||||
};
|
||||
|
||||
bool Parse(uint8_t **pp, uint16_t *pcntdn, PTP_ARRAY_EL_FUNC pf, const void *me = NULL);
|
||||
};
|
||||
|
||||
#endif // __PARSETOOLS_H__
|
67
printhex.h
67
printhex.h
|
@ -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));
|
||||
|
||||
while (mask > 1)
|
||||
{
|
||||
if (val < mask)
|
||||
prn->print("0");
|
||||
|
||||
mask >>= 4;
|
||||
}
|
||||
prn->print((T)val, HEX);
|
||||
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);
|
||||
}
|
||||
|
||||
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");
|
||||
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);
|
||||
}
|
||||
|
||||
#endif // __PRINTHEX_H__
|
122
usb_ch9.h
122
usb_ch9.h
|
@ -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_
|
||||
|
@ -94,77 +94,71 @@ e-mail : support@circuitsathome.com
|
|||
|
||||
/* Device descriptor structure */
|
||||
typedef struct {
|
||||
uint8_t bLength; // Length of this descriptor.
|
||||
uint8_t bDescriptorType; // DEVICE descriptor type (USB_DESCRIPTOR_DEVICE).
|
||||
uint16_t bcdUSB; // USB Spec Release Number (BCD).
|
||||
uint8_t bDeviceClass; // Class code (assigned by the USB-IF). 0xFF-Vendor specific.
|
||||
uint8_t bDeviceSubClass; // Subclass code (assigned by the USB-IF).
|
||||
uint8_t bDeviceProtocol; // Protocol code (assigned by the USB-IF). 0xFF-Vendor specific.
|
||||
uint8_t bMaxPacketSize0; // Maximum packet size for endpoint 0.
|
||||
uint16_t idVendor; // Vendor ID (assigned by the USB-IF).
|
||||
uint16_t idProduct; // Product ID (assigned by the manufacturer).
|
||||
uint16_t bcdDevice; // Device release number (BCD).
|
||||
uint8_t iManufacturer; // Index of String Descriptor describing the manufacturer.
|
||||
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;
|
||||
uint8_t bLength; // Length of this descriptor.
|
||||
uint8_t bDescriptorType; // DEVICE descriptor type (USB_DESCRIPTOR_DEVICE).
|
||||
uint16_t bcdUSB; // USB Spec Release Number (BCD).
|
||||
uint8_t bDeviceClass; // Class code (assigned by the USB-IF). 0xFF-Vendor specific.
|
||||
uint8_t bDeviceSubClass; // Subclass code (assigned by the USB-IF).
|
||||
uint8_t bDeviceProtocol; // Protocol code (assigned by the USB-IF). 0xFF-Vendor specific.
|
||||
uint8_t bMaxPacketSize0; // Maximum packet size for endpoint 0.
|
||||
uint16_t idVendor; // Vendor ID (assigned by the USB-IF).
|
||||
uint16_t idProduct; // Product ID (assigned by the manufacturer).
|
||||
uint16_t bcdDevice; // Device release number (BCD).
|
||||
uint8_t iManufacturer; // Index of String Descriptor describing the manufacturer.
|
||||
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.
|
||||
} __attribute__((packed)) USB_DEVICE_DESCRIPTOR;
|
||||
|
||||
/* Configuration descriptor structure */
|
||||
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.
|
||||
uint8_t bNumInterfaces; // Number of interfaces in this configuration.
|
||||
uint8_t bConfigurationValue; // Value of this configuration (1 based).
|
||||
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;
|
||||
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.
|
||||
uint8_t bNumInterfaces; // Number of interfaces in this configuration.
|
||||
uint8_t bConfigurationValue; // Value of this configuration (1 based).
|
||||
uint8_t iConfiguration; // Index of String Descriptor describing the configuration.
|
||||
uint8_t bmAttributes; // Configuration characteristics.
|
||||
uint8_t bMaxPower; // Maximum power consumed by this configuration.
|
||||
} __attribute__((packed)) USB_CONFIGURATION_DESCRIPTOR;
|
||||
|
||||
/* Interface descriptor structure */
|
||||
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).
|
||||
uint8_t bAlternateSetting; // Value of this alternate interface setting.
|
||||
uint8_t bNumEndpoints; // Number of endpoints in this interface.
|
||||
uint8_t bInterfaceClass; // Class code (assigned by the USB-IF). 0xFF-Vendor specific.
|
||||
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;
|
||||
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).
|
||||
uint8_t bAlternateSetting; // Value of this alternate interface setting.
|
||||
uint8_t bNumEndpoints; // Number of endpoints in this interface.
|
||||
uint8_t bInterfaceClass; // Class code (assigned by the USB-IF). 0xFF-Vendor specific.
|
||||
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.
|
||||
} __attribute__((packed)) USB_INTERFACE_DESCRIPTOR;
|
||||
|
||||
/* Endpoint descriptor structure */
|
||||
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;
|
||||
|
||||
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.
|
||||
} __attribute__((packed)) USB_ENDPOINT_DESCRIPTOR;
|
||||
|
||||
/* HID descriptor */
|
||||
typedef struct
|
||||
{
|
||||
uint8_t bLength;
|
||||
uint8_t bDescriptorType;
|
||||
uint16_t bcdHID; // HID class specification release
|
||||
uint8_t bCountryCode;
|
||||
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;
|
||||
typedef struct {
|
||||
uint8_t bLength;
|
||||
uint8_t bDescriptorType;
|
||||
uint16_t bcdHID; // HID class specification release
|
||||
uint8_t bCountryCode;
|
||||
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
|
||||
} __attribute__((packed)) USB_HID_DESCRIPTOR;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
uint8_t bDescrType; // Type of class descriptor
|
||||
uint16_t wDescriptorLength; // Total size of the Report descriptor
|
||||
} HID_CLASS_DESCRIPTOR_LEN_AND_TYPE;
|
||||
typedef struct {
|
||||
uint8_t bDescrType; // Type of class descriptor
|
||||
uint16_t wDescriptorLength; // Total size of the Report descriptor
|
||||
} __attribute__((packed)) HID_CLASS_DESCRIPTOR_LEN_AND_TYPE;
|
||||
|
||||
#endif // _ch9_h_
|
||||
|
|
392
usbhost.h
392
usbhost.h
|
@ -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,24 +22,23 @@ 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:
|
||||
static void init() {
|
||||
uint8_t tmp;
|
||||
CLK::SetDirWrite();
|
||||
MOSI::SetDirWrite();
|
||||
MISO::SetDirRead();
|
||||
SPI_SS::SetDirWrite();
|
||||
/* mode 00 (CPOL=0, CPHA=0) master, fclk/2. Mode 11 (CPOL=11, CPHA=11) is also supported by MAX3421E */
|
||||
SPCR = 0x50;
|
||||
SPSR = 0x01;
|
||||
/**/
|
||||
tmp = SPSR;
|
||||
tmp = SPDR;
|
||||
}
|
||||
template< typename CLK, typename MOSI, typename MISO, typename SPI_SS > class SPi {
|
||||
public:
|
||||
|
||||
static void init() {
|
||||
//uint8_t tmp;
|
||||
CLK::SetDirWrite();
|
||||
MOSI::SetDirWrite();
|
||||
MISO::SetDirRead();
|
||||
SPI_SS::SetDirWrite();
|
||||
/* mode 00 (CPOL=0, CPHA=0) master, fclk/2. Mode 11 (CPOL=11, CPHA=11) is also supported by MAX3421E */
|
||||
SPCR = 0x50;
|
||||
SPSR = 0x01;
|
||||
/**/
|
||||
//tmp = SPSR;
|
||||
//tmp = SPDR;
|
||||
}
|
||||
};
|
||||
|
||||
/* SPI pin definitions. see avrpins.h */
|
||||
|
@ -53,143 +52,138 @@ typedef SPi< Pb5, Pb3, Pb4, Pb2 > spi;
|
|||
typedef SPi< Pb7, Pb5, Pb6, Pb4 > spi;
|
||||
#endif
|
||||
|
||||
template< typename SS, typename INTR > class MAX3421e /* : public spi */
|
||||
{
|
||||
static uint8_t vbusState;
|
||||
template< typename SS, typename INTR > class MAX3421e /* : public spi */ {
|
||||
static uint8_t vbusState;
|
||||
|
||||
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 );
|
||||
uint8_t gpioRd();
|
||||
uint16_t reset();
|
||||
int8_t Init();
|
||||
uint8_t getVbusState( void ) { return vbusState; };
|
||||
void busprobe();
|
||||
uint8_t GpxHandler();
|
||||
uint8_t IntHandler();
|
||||
uint8_t Task();
|
||||
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);
|
||||
uint8_t gpioRd();
|
||||
uint16_t reset();
|
||||
int8_t Init();
|
||||
|
||||
uint8_t getVbusState(void) {
|
||||
return vbusState;
|
||||
};
|
||||
void busprobe();
|
||||
uint8_t GpxHandler();
|
||||
uint8_t IntHandler();
|
||||
uint8_t Task();
|
||||
};
|
||||
|
||||
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()
|
||||
{
|
||||
/* 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< SS, INTR >::MAX3421e() {
|
||||
/* pin and peripheral setup */
|
||||
SS::SetDirWrite();
|
||||
SS::Set();
|
||||
spi::init();
|
||||
INTR::SetDirRead();
|
||||
|
||||
/* MAX3421E - full-duplex SPI, level interrupt */
|
||||
regWr( rPINCTL,( bmFDUPSPI + bmINTLEVEL ));
|
||||
/* MAX3421E - full-duplex SPI, level interrupt */
|
||||
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 )
|
||||
{
|
||||
SS::Clear();
|
||||
SPDR = ( reg | 0x02 );
|
||||
while(!( SPSR & ( 1 << SPIF )));
|
||||
SPDR = data;
|
||||
while(!( SPSR & ( 1 << SPIF )));
|
||||
SS::Set();
|
||||
return;
|
||||
void MAX3421e< SS, INTR >::regWr(uint8_t reg, uint8_t data) {
|
||||
SS::Clear();
|
||||
SPDR = (reg | 0x02);
|
||||
while(!(SPSR & (1 << SPIF)));
|
||||
SPDR = data;
|
||||
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 )
|
||||
{
|
||||
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
|
||||
data_p++; // advance data pointer
|
||||
}
|
||||
while(!( SPSR & ( 1 << SPIF )));
|
||||
SS::Set();
|
||||
return( 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
|
||||
data_p++; // advance data pointer
|
||||
}
|
||||
while(!(SPSR & (1 << SPIF)));
|
||||
SS::Set();
|
||||
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 );
|
||||
data >>= 4;
|
||||
regWr( rIOPINS2, data );
|
||||
return;
|
||||
void MAX3421e< SS, INTR >::gpioWr(uint8_t data) {
|
||||
regWr(rIOPINS1, data);
|
||||
data >>= 4;
|
||||
regWr(rIOPINS2, data);
|
||||
return;
|
||||
}
|
||||
|
||||
/* single host register read */
|
||||
template< typename SS, typename INTR >
|
||||
uint8_t MAX3421e< SS, INTR >::regRd( uint8_t reg )
|
||||
{
|
||||
SS::Clear();
|
||||
SPDR = reg;
|
||||
while(!( SPSR & ( 1 << SPIF )));
|
||||
SPDR = 0; //send empty byte
|
||||
while(!( SPSR & ( 1 << SPIF )));
|
||||
SS::Set();
|
||||
return( SPDR );
|
||||
uint8_t MAX3421e< SS, INTR >::regRd(uint8_t reg) {
|
||||
SS::Clear();
|
||||
SPDR = reg;
|
||||
while(!(SPSR & (1 << SPIF)));
|
||||
SPDR = 0; //send empty byte
|
||||
while(!(SPSR & (1 << SPIF)));
|
||||
SS::Set();
|
||||
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 )
|
||||
{
|
||||
SS::Clear();
|
||||
SPDR = reg;
|
||||
while(!( SPSR & ( 1 << SPIF ))); //wait
|
||||
while( nbytes ) {
|
||||
SPDR = 0; //send empty byte
|
||||
nbytes--;
|
||||
while(!( SPSR & ( 1 << SPIF )));
|
||||
*data_p = SPDR;
|
||||
data_p++;
|
||||
}
|
||||
SS::Set();
|
||||
return( 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) {
|
||||
SPDR = 0; //send empty byte
|
||||
nbytes--;
|
||||
while(!(SPSR & (1 << SPIF)));
|
||||
*data_p = SPDR;
|
||||
data_p++;
|
||||
}
|
||||
SS::Set();
|
||||
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 gpin = 0;
|
||||
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 );
|
||||
uint8_t MAX3421e< SS, INTR >::gpioRd() {
|
||||
uint8_t gpin = 0;
|
||||
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);
|
||||
}
|
||||
|
||||
/* 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 i = 0;
|
||||
regWr( rUSBCTL, bmCHIPRES );
|
||||
regWr( rUSBCTL, 0x00 );
|
||||
while( ++i ) {
|
||||
if(( regRd( rUSBIRQ ) & bmOSCOKIRQ )) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
return( i );
|
||||
uint16_t MAX3421e< SS, INTR >::reset() {
|
||||
uint16_t i = 0;
|
||||
regWr(rUSBCTL, bmCHIPRES);
|
||||
regWr(rUSBCTL, 0x00);
|
||||
while(++i) {
|
||||
if((regRd(rUSBIRQ) & bmOSCOKIRQ)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
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 );
|
||||
}
|
||||
regWr( rMODE, bmDPPULLDN|bmDMPULLDN|bmHOST ); // set pull-downs, Host
|
||||
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( 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
|
||||
/* check if device is connected */
|
||||
regWr(rHCTL, bmSAMPLEBUS); // sample USB bus
|
||||
while(!(regRd(rHCTL) & bmSAMPLEBUS)); //wait for sample operation to finish
|
||||
|
||||
busprobe(); //check if anything is connected
|
||||
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()
|
||||
{
|
||||
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
|
||||
vbusState = FSHOST;
|
||||
}
|
||||
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
|
||||
vbusState = LSHOST;
|
||||
}
|
||||
else {
|
||||
regWr( rMODE, MODE_FS_HOST ); //start full-speed host
|
||||
vbusState = FSHOST;
|
||||
}
|
||||
break;
|
||||
case( bmSE1 ): //illegal state
|
||||
vbusState = SE1;
|
||||
break;
|
||||
case( bmSE0 ): //disconnected state
|
||||
regWr( rMODE, bmDPPULLDN|bmDMPULLDN|bmHOST|bmSEPIRQ);
|
||||
vbusState = SE0;
|
||||
break;
|
||||
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
|
||||
vbusState = FSHOST;
|
||||
} 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
|
||||
vbusState = LSHOST;
|
||||
} else {
|
||||
regWr(rMODE, MODE_FS_HOST); //start full-speed host
|
||||
vbusState = FSHOST;
|
||||
}
|
||||
break;
|
||||
case( bmSE1): //illegal state
|
||||
vbusState = SE1;
|
||||
break;
|
||||
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 rcode = 0;
|
||||
uint8_t pinvalue;
|
||||
//Serial.print("Vbus state: ");
|
||||
//Serial.println( vbusState, HEX );
|
||||
pinvalue = INTR::IsSet(); //Read();
|
||||
//pinvalue = digitalRead( MAX_INT );
|
||||
if( pinvalue == 0 ) {
|
||||
rcode = IntHandler();
|
||||
}
|
||||
// pinvalue = digitalRead( MAX_GPX );
|
||||
// if( pinvalue == LOW ) {
|
||||
// GpxHandler();
|
||||
// }
|
||||
// usbSM(); //USB state machine
|
||||
return( rcode );
|
||||
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) {
|
||||
rcode = IntHandler();
|
||||
}
|
||||
// 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 HIRQ;
|
||||
uint8_t HIRQ_sendback = 0x00;
|
||||
HIRQ = regRd( rHIRQ ); //determine interrupt source
|
||||
//if( HIRQ & bmFRAMEIRQ ) { //->1ms SOF interrupt handler
|
||||
// HIRQ_sendback |= bmFRAMEIRQ;
|
||||
//}//end FRAMEIRQ handling
|
||||
if( HIRQ & bmCONDETIRQ ) {
|
||||
busprobe();
|
||||
HIRQ_sendback |= bmCONDETIRQ;
|
||||
}
|
||||
/* End HIRQ interrupts handling, clear serviced IRQs */
|
||||
regWr( rHIRQ, HIRQ_sendback );
|
||||
return( HIRQ_sendback );
|
||||
uint8_t MAX3421e< SS, INTR >::IntHandler() {
|
||||
uint8_t HIRQ;
|
||||
uint8_t HIRQ_sendback = 0x00;
|
||||
HIRQ = regRd(rHIRQ); //determine interrupt source
|
||||
//if( HIRQ & bmFRAMEIRQ ) { //->1ms SOF interrupt handler
|
||||
// HIRQ_sendback |= bmFRAMEIRQ;
|
||||
//}//end FRAMEIRQ handling
|
||||
if(HIRQ & bmCONDETIRQ) {
|
||||
busprobe();
|
||||
HIRQ_sendback |= bmCONDETIRQ;
|
||||
}
|
||||
/* End HIRQ interrupts handling, clear serviced IRQs */
|
||||
regWr(rHIRQ, HIRQ_sendback);
|
||||
return( HIRQ_sendback);
|
||||
}
|
||||
//template< typename SS, typename INTR >
|
||||
//uint8_t MAX3421e< SS, INTR >::GpxHandler()
|
||||
|
|
568
usbhub.cpp
568
usbhub.cpp
|
@ -13,402 +13,382 @@ 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)
|
||||
{
|
||||
epInfo[0].epAddr = 0;
|
||||
epInfo[0].maxPktSize = 8;
|
||||
epInfo[0].epAttribs = 0;
|
||||
epInfo[0].bmNakPower = USB_NAK_MAX_POWER;
|
||||
pUsb(p),
|
||||
bAddress(0),
|
||||
bNbrPorts(0),
|
||||
bInitState(0),
|
||||
qNextPollTime(0),
|
||||
bPollEnable(false) {
|
||||
epInfo[0].epAddr = 0;
|
||||
epInfo[0].maxPktSize = 8;
|
||||
epInfo[0].epAttribs = 0;
|
||||
epInfo[0].bmNakPower = USB_NAK_MAX_POWER;
|
||||
|
||||
epInfo[1].epAddr = 1;
|
||||
epInfo[1].maxPktSize = 8; //kludge
|
||||
epInfo[1].epAttribs = 0;
|
||||
epInfo[1].bmNakPower = USB_NAK_NOWAIT;
|
||||
epInfo[1].epAddr = 1;
|
||||
epInfo[1].maxPktSize = 8; //kludge
|
||||
epInfo[1].epAttribs = 0;
|
||||
epInfo[1].bmNakPower = USB_NAK_NOWAIT;
|
||||
|
||||
if (pUsb)
|
||||
pUsb->RegisterDeviceClass(this);
|
||||
if (pUsb)
|
||||
pUsb->RegisterDeviceClass(this);
|
||||
}
|
||||
|
||||
uint8_t USBHub::Init(uint8_t parent, uint8_t port, bool lowspeed)
|
||||
{
|
||||
uint8_t buf[32];
|
||||
uint8_t rcode;
|
||||
UsbDevice *p = NULL;
|
||||
EpInfo *oldep_ptr = NULL;
|
||||
uint8_t len = 0;
|
||||
uint16_t cd_len = 0;
|
||||
uint8_t USBHub::Init(uint8_t parent, uint8_t port, bool lowspeed) {
|
||||
uint8_t buf[32];
|
||||
uint8_t rcode;
|
||||
UsbDevice *p = NULL;
|
||||
EpInfo *oldep_ptr = NULL;
|
||||
uint8_t len = 0;
|
||||
uint16_t cd_len = 0;
|
||||
|
||||
//USBTRACE("\r\nHub Init Start");
|
||||
//USBTRACE("\r\nHub Init Start");
|
||||
|
||||
AddressPool &addrPool = pUsb->GetAddressPool();
|
||||
AddressPool &addrPool = pUsb->GetAddressPool();
|
||||
|
||||
switch (bInitState)
|
||||
{
|
||||
case 0:
|
||||
if (bAddress)
|
||||
return USB_ERROR_CLASS_INSTANCE_ALREADY_IN_USE;
|
||||
switch (bInitState) {
|
||||
case 0:
|
||||
if (bAddress)
|
||||
return USB_ERROR_CLASS_INSTANCE_ALREADY_IN_USE;
|
||||
|
||||
// Get pointer to pseudo device with address 0 assigned
|
||||
p = addrPool.GetUsbDevicePtr(0);
|
||||
// Get pointer to pseudo device with address 0 assigned
|
||||
p = addrPool.GetUsbDevicePtr(0);
|
||||
|
||||
if (!p)
|
||||
return USB_ERROR_ADDRESS_NOT_FOUND_IN_POOL;
|
||||
if (!p)
|
||||
return USB_ERROR_ADDRESS_NOT_FOUND_IN_POOL;
|
||||
|
||||
if (!p->epinfo)
|
||||
return USB_ERROR_EPINFO_IS_NULL;
|
||||
if (!p->epinfo)
|
||||
return USB_ERROR_EPINFO_IS_NULL;
|
||||
|
||||
// Save old pointer to EP_RECORD of address 0
|
||||
oldep_ptr = p->epinfo;
|
||||
// Save old pointer to EP_RECORD of address 0
|
||||
oldep_ptr = p->epinfo;
|
||||
|
||||
// Temporary assign new pointer to epInfo to p->epinfo in order to avoid toggle inconsistence
|
||||
p->epinfo = epInfo;
|
||||
// Temporary assign new pointer to epInfo to p->epinfo in order to avoid toggle inconsistence
|
||||
p->epinfo = epInfo;
|
||||
|
||||
p->lowspeed = lowspeed;
|
||||
p->lowspeed = lowspeed;
|
||||
|
||||
// Get device descriptor
|
||||
rcode = pUsb->getDevDescr( 0, 0, 8, (uint8_t*)buf );
|
||||
// Get device descriptor
|
||||
rcode = pUsb->getDevDescr(0, 0, 8, (uint8_t*)buf);
|
||||
|
||||
p->lowspeed = false;
|
||||
p->lowspeed = false;
|
||||
|
||||
if (!rcode)
|
||||
len = (buf[0] > 32) ? 32 : buf[0];
|
||||
if (!rcode)
|
||||
len = (buf[0] > 32) ? 32 : buf[0];
|
||||
|
||||
if( rcode )
|
||||
{
|
||||
// Restore p->epinfo
|
||||
p->epinfo = oldep_ptr;
|
||||
return rcode;
|
||||
}
|
||||
if (rcode) {
|
||||
// Restore p->epinfo
|
||||
p->epinfo = oldep_ptr;
|
||||
return rcode;
|
||||
}
|
||||
|
||||
// Extract device class from device descriptor
|
||||
// If device class is not a hub return
|
||||
if (((USB_DEVICE_DESCRIPTOR*)buf)->bDeviceClass != 0x09)
|
||||
return USB_DEV_CONFIG_ERROR_DEVICE_NOT_SUPPORTED;
|
||||
// Extract device class from device descriptor
|
||||
// If device class is not a hub return
|
||||
if (((USB_DEVICE_DESCRIPTOR*)buf)->bDeviceClass != 0x09)
|
||||
return USB_DEV_CONFIG_ERROR_DEVICE_NOT_SUPPORTED;
|
||||
|
||||
// Allocate new address according to device class
|
||||
bAddress = addrPool.AllocAddress(parent, (((USB_DEVICE_DESCRIPTOR*)buf)->bDeviceClass == 0x09) ? true : false, port);
|
||||
// Allocate new address according to device class
|
||||
bAddress = addrPool.AllocAddress(parent, (((USB_DEVICE_DESCRIPTOR*)buf)->bDeviceClass == 0x09) ? true : false, port);
|
||||
|
||||
if (!bAddress)
|
||||
return USB_ERROR_OUT_OF_ADDRESS_SPACE_IN_POOL;
|
||||
if (!bAddress)
|
||||
return USB_ERROR_OUT_OF_ADDRESS_SPACE_IN_POOL;
|
||||
|
||||
// Extract Max Packet Size from the device descriptor
|
||||
epInfo[0].maxPktSize = ((USB_DEVICE_DESCRIPTOR*)buf)->bMaxPacketSize0;
|
||||
// Extract Max Packet Size from the device descriptor
|
||||
epInfo[0].maxPktSize = ((USB_DEVICE_DESCRIPTOR*)buf)->bMaxPacketSize0;
|
||||
|
||||
// Assign new address to the device
|
||||
rcode = pUsb->setAddr( 0, 0, bAddress );
|
||||
// Assign new address to the device
|
||||
rcode = pUsb->setAddr(0, 0, bAddress);
|
||||
|
||||
if (rcode)
|
||||
{
|
||||
// Restore p->epinfo
|
||||
p->epinfo = oldep_ptr;
|
||||
addrPool.FreeAddress(bAddress);
|
||||
bAddress = 0;
|
||||
return rcode;
|
||||
}
|
||||
if (rcode) {
|
||||
// Restore p->epinfo
|
||||
p->epinfo = oldep_ptr;
|
||||
addrPool.FreeAddress(bAddress);
|
||||
bAddress = 0;
|
||||
return rcode;
|
||||
}
|
||||
|
||||
//USBTRACE2("\r\nHub address: ", bAddress );
|
||||
//USBTRACE2("\r\nHub address: ", bAddress );
|
||||
|
||||
// Restore p->epinfo
|
||||
p->epinfo = oldep_ptr;
|
||||
// Restore p->epinfo
|
||||
p->epinfo = oldep_ptr;
|
||||
|
||||
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;
|
||||
if (rcode)
|
||||
goto FailGetDevDescr;
|
||||
|
||||
// Assign epInfo to epinfo pointer
|
||||
rcode = pUsb->setEpInfoEntry(bAddress, 2, epInfo);
|
||||
// Assign epInfo to epinfo pointer
|
||||
rcode = pUsb->setEpInfoEntry(bAddress, 2, epInfo);
|
||||
|
||||
if (rcode)
|
||||
goto FailSetDevTblEntry;
|
||||
if (rcode)
|
||||
goto FailSetDevTblEntry;
|
||||
|
||||
bInitState = 1;
|
||||
bInitState = 1;
|
||||
|
||||
case 1:
|
||||
// Get hub descriptor
|
||||
rcode = GetHubDescriptor(0, 8, buf);
|
||||
case 1:
|
||||
// Get hub descriptor
|
||||
rcode = GetHubDescriptor(0, 8, buf);
|
||||
|
||||
if (rcode)
|
||||
goto FailGetHubDescr;
|
||||
if (rcode)
|
||||
goto FailGetHubDescr;
|
||||
|
||||
// Save number of ports for future use
|
||||
bNbrPorts = ((HubDescriptor*)buf)->bNbrPorts;
|
||||
// Save number of ports for future use
|
||||
bNbrPorts = ((HubDescriptor*)buf)->bNbrPorts;
|
||||
|
||||
bInitState = 2;
|
||||
bInitState = 2;
|
||||
|
||||
case 2:
|
||||
// Read configuration Descriptor in Order To Obtain Proper Configuration Value
|
||||
rcode = pUsb->getConfDescr(bAddress, 0, 8, 0, buf);
|
||||
case 2:
|
||||
// Read configuration Descriptor in Order To Obtain Proper Configuration Value
|
||||
rcode = pUsb->getConfDescr(bAddress, 0, 8, 0, buf);
|
||||
|
||||
if (!rcode)
|
||||
{
|
||||
cd_len = ((USB_CONFIGURATION_DESCRIPTOR*)buf)->wTotalLength;
|
||||
rcode = pUsb->getConfDescr(bAddress, 0, cd_len, 0, buf);
|
||||
}
|
||||
if (rcode)
|
||||
goto FailGetConfDescr;
|
||||
if (!rcode) {
|
||||
cd_len = ((USB_CONFIGURATION_DESCRIPTOR*)buf)->wTotalLength;
|
||||
rcode = pUsb->getConfDescr(bAddress, 0, cd_len, 0, buf);
|
||||
}
|
||||
if (rcode)
|
||||
goto FailGetConfDescr;
|
||||
|
||||
// The following code is of no practical use in real life applications.
|
||||
// It only intended for the usb protocol sniffer to properly parse hub-class requests.
|
||||
{
|
||||
uint8_t buf2[24];
|
||||
// The following code is of no practical use in real life applications.
|
||||
// It only intended for the usb protocol sniffer to properly parse hub-class requests.
|
||||
{
|
||||
uint8_t buf2[24];
|
||||
|
||||
rcode = pUsb->getConfDescr(bAddress, 0, buf[0], 0, buf2);
|
||||
rcode = pUsb->getConfDescr(bAddress, 0, buf[0], 0, buf2);
|
||||
|
||||
if (rcode)
|
||||
goto FailGetConfDescr;
|
||||
}
|
||||
if (rcode)
|
||||
goto FailGetConfDescr;
|
||||
}
|
||||
|
||||
// Set Configuration Value
|
||||
rcode = pUsb->setConf(bAddress, 0, buf[5]);
|
||||
// Set Configuration Value
|
||||
rcode = pUsb->setConf(bAddress, 0, buf[5]);
|
||||
|
||||
if (rcode)
|
||||
goto FailSetConfDescr;
|
||||
if (rcode)
|
||||
goto FailSetConfDescr;
|
||||
|
||||
bInitState = 3;
|
||||
bInitState = 3;
|
||||
|
||||
case 3:
|
||||
// Power on all ports
|
||||
for (uint8_t j=1; j<=bNbrPorts; j++)
|
||||
SetPortFeature(HUB_FEATURE_PORT_POWER, j, 0); //HubPortPowerOn(j);
|
||||
case 3:
|
||||
// Power on all ports
|
||||
for (uint8_t j = 1; j <= bNbrPorts; j++)
|
||||
SetPortFeature(HUB_FEATURE_PORT_POWER, j, 0); //HubPortPowerOn(j);
|
||||
|
||||
pUsb->SetHubPreMask();
|
||||
bPollEnable = true;
|
||||
bInitState = 0;
|
||||
}
|
||||
bInitState = 0;
|
||||
return 0;
|
||||
pUsb->SetHubPreMask();
|
||||
bPollEnable = true;
|
||||
bInitState = 0;
|
||||
}
|
||||
bInitState = 0;
|
||||
return 0;
|
||||
|
||||
FailGetDevDescr:
|
||||
goto Fail;
|
||||
goto Fail;
|
||||
|
||||
FailSetDevTblEntry:
|
||||
goto Fail;
|
||||
goto Fail;
|
||||
|
||||
FailGetHubDescr:
|
||||
goto Fail;
|
||||
goto Fail;
|
||||
|
||||
FailGetConfDescr:
|
||||
goto Fail;
|
||||
goto Fail;
|
||||
|
||||
FailSetConfDescr:
|
||||
goto Fail;
|
||||
|
||||
FailGetPortStatus:
|
||||
goto Fail;
|
||||
goto Fail;
|
||||
|
||||
Fail:
|
||||
return rcode;
|
||||
return rcode;
|
||||
}
|
||||
|
||||
uint8_t USBHub::Release()
|
||||
{
|
||||
pUsb->GetAddressPool().FreeAddress(bAddress);
|
||||
uint8_t USBHub::Release() {
|
||||
pUsb->GetAddressPool().FreeAddress(bAddress);
|
||||
|
||||
if (bAddress == 0x41)
|
||||
pUsb->SetHubPreMask();
|
||||
if (bAddress == 0x41)
|
||||
pUsb->SetHubPreMask();
|
||||
|
||||
bAddress = 0;
|
||||
bNbrPorts = 0;
|
||||
qNextPollTime = 0;
|
||||
bPollEnable = false;
|
||||
return 0;
|
||||
bAddress = 0;
|
||||
bNbrPorts = 0;
|
||||
qNextPollTime = 0;
|
||||
bPollEnable = false;
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint8_t USBHub::Poll()
|
||||
{
|
||||
uint8_t rcode = 0;
|
||||
uint8_t USBHub::Poll() {
|
||||
uint8_t rcode = 0;
|
||||
|
||||
if (!bPollEnable)
|
||||
return 0;
|
||||
if (!bPollEnable)
|
||||
return 0;
|
||||
|
||||
if (qNextPollTime <= millis())
|
||||
{
|
||||
rcode = CheckHubStatus();
|
||||
qNextPollTime = millis() + 100;
|
||||
}
|
||||
return rcode;
|
||||
if (qNextPollTime <= millis()) {
|
||||
rcode = CheckHubStatus();
|
||||
qNextPollTime = millis() + 100;
|
||||
}
|
||||
return rcode;
|
||||
}
|
||||
|
||||
uint8_t USBHub::CheckHubStatus()
|
||||
{
|
||||
uint8_t rcode;
|
||||
uint8_t buf[8];
|
||||
uint16_t read = 1;
|
||||
uint8_t USBHub::CheckHubStatus() {
|
||||
uint8_t rcode;
|
||||
uint8_t buf[8];
|
||||
uint16_t read = 1;
|
||||
|
||||
rcode = pUsb->inTransfer(bAddress, 1, &read, buf);
|
||||
rcode = pUsb->inTransfer(bAddress, 1, &read, buf);
|
||||
|
||||
if (rcode)
|
||||
return rcode;
|
||||
if (rcode)
|
||||
return rcode;
|
||||
|
||||
if (buf[0] & 0x01) // Hub Status Change
|
||||
{
|
||||
//pUsb->PrintHubStatus(addr);
|
||||
//rcode = GetHubStatus(1, 0, 1, 4, buf);
|
||||
//if (rcode)
|
||||
//{
|
||||
// Serial.print("GetHubStatus Error");
|
||||
// Serial.println(rcode, HEX);
|
||||
// return rcode;
|
||||
//}
|
||||
}
|
||||
for (uint8_t port=1,mask=0x02; port<8; mask<<=1, port++)
|
||||
{
|
||||
if (buf[0] & mask)
|
||||
{
|
||||
HubEvent evt;
|
||||
evt.bmEvent = 0;
|
||||
if (buf[0] & 0x01) // Hub Status Change
|
||||
{
|
||||
//pUsb->PrintHubStatus(addr);
|
||||
//rcode = GetHubStatus(1, 0, 1, 4, buf);
|
||||
//if (rcode)
|
||||
//{
|
||||
// Serial.print("GetHubStatus Error");
|
||||
// Serial.println(rcode, HEX);
|
||||
// return rcode;
|
||||
//}
|
||||
}
|
||||
for (uint8_t port = 1, mask = 0x02; port < 8; mask <<= 1, port++) {
|
||||
if (buf[0] & mask) {
|
||||
HubEvent evt;
|
||||
evt.bmEvent = 0;
|
||||
|
||||
rcode = GetPortStatus(port, 4, evt.evtBuff);
|
||||
rcode = GetPortStatus(port, 4, evt.evtBuff);
|
||||
|
||||
if (rcode)
|
||||
continue;
|
||||
if (rcode)
|
||||
continue;
|
||||
|
||||
rcode = PortStatusChange(port, evt);
|
||||
rcode = PortStatusChange(port, evt);
|
||||
|
||||
if (rcode == HUB_ERROR_PORT_HAS_BEEN_RESET)
|
||||
return 0;
|
||||
if (rcode == HUB_ERROR_PORT_HAS_BEEN_RESET)
|
||||
return 0;
|
||||
|
||||
if (rcode)
|
||||
return rcode;
|
||||
}
|
||||
} // for
|
||||
if (rcode)
|
||||
return rcode;
|
||||
}
|
||||
} // for
|
||||
|
||||
for (uint8_t port=1; port<=bNbrPorts; port++)
|
||||
{
|
||||
HubEvent evt;
|
||||
evt.bmEvent = 0;
|
||||
for (uint8_t port = 1; port <= bNbrPorts; port++) {
|
||||
HubEvent evt;
|
||||
evt.bmEvent = 0;
|
||||
|
||||
rcode = GetPortStatus(port, 4, evt.evtBuff);
|
||||
rcode = GetPortStatus(port, 4, evt.evtBuff);
|
||||
|
||||
if (rcode)
|
||||
continue;
|
||||
if (rcode)
|
||||
continue;
|
||||
|
||||
if ((evt.bmStatus & bmHUB_PORT_STATE_CHECK_DISABLED) != bmHUB_PORT_STATE_DISABLED)
|
||||
continue;
|
||||
if ((evt.bmStatus & bmHUB_PORT_STATE_CHECK_DISABLED) != bmHUB_PORT_STATE_DISABLED)
|
||||
continue;
|
||||
|
||||
// Emulate connection event for the port
|
||||
evt.bmChange |= bmHUB_PORT_STATUS_C_PORT_CONNECTION;
|
||||
// Emulate connection event for the port
|
||||
evt.bmChange |= bmHUB_PORT_STATUS_C_PORT_CONNECTION;
|
||||
|
||||
rcode = PortStatusChange(port, evt);
|
||||
rcode = PortStatusChange(port, evt);
|
||||
|
||||
if (rcode == HUB_ERROR_PORT_HAS_BEEN_RESET)
|
||||
return 0;
|
||||
if (rcode == HUB_ERROR_PORT_HAS_BEEN_RESET)
|
||||
return 0;
|
||||
|
||||
if (rcode)
|
||||
return rcode;
|
||||
} // for
|
||||
return 0;
|
||||
if (rcode)
|
||||
return rcode;
|
||||
} // for
|
||||
return 0;
|
||||
}
|
||||
|
||||
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:
|
||||
if (bResetInitiated)
|
||||
return 0;
|
||||
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:
|
||||
if (bResetInitiated)
|
||||
return 0;
|
||||
|
||||
ClearPortFeature(HUB_FEATURE_C_PORT_ENABLE, port, 0);
|
||||
ClearPortFeature(HUB_FEATURE_C_PORT_CONNECTION, port, 0);
|
||||
SetPortFeature(HUB_FEATURE_PORT_RESET, port, 0);
|
||||
bResetInitiated = true;
|
||||
return HUB_ERROR_PORT_HAS_BEEN_RESET;
|
||||
ClearPortFeature(HUB_FEATURE_C_PORT_ENABLE, port, 0);
|
||||
ClearPortFeature(HUB_FEATURE_C_PORT_CONNECTION, port, 0);
|
||||
SetPortFeature(HUB_FEATURE_PORT_RESET, port, 0);
|
||||
bResetInitiated = true;
|
||||
return HUB_ERROR_PORT_HAS_BEEN_RESET;
|
||||
|
||||
// Device disconnected event
|
||||
case bmHUB_PORT_EVENT_DISCONNECT:
|
||||
ClearPortFeature(HUB_FEATURE_C_PORT_ENABLE, port, 0);
|
||||
ClearPortFeature(HUB_FEATURE_C_PORT_CONNECTION, port, 0);
|
||||
bResetInitiated = false;
|
||||
// Device disconnected event
|
||||
case bmHUB_PORT_EVENT_DISCONNECT:
|
||||
ClearPortFeature(HUB_FEATURE_C_PORT_ENABLE, port, 0);
|
||||
ClearPortFeature(HUB_FEATURE_C_PORT_CONNECTION, port, 0);
|
||||
bResetInitiated = false;
|
||||
|
||||
UsbDeviceAddress a;
|
||||
a.bmHub = 0;
|
||||
a.bmParent = bAddress;
|
||||
a.bmAddress = port;
|
||||
pUsb->ReleaseDevice(a.devAddress);
|
||||
return 0;
|
||||
UsbDeviceAddress a;
|
||||
a.bmHub = 0;
|
||||
a.bmParent = bAddress;
|
||||
a.bmAddress = port;
|
||||
pUsb->ReleaseDevice(a.devAddress);
|
||||
return 0;
|
||||
|
||||
// Reset complete event
|
||||
case bmHUB_PORT_EVENT_RESET_COMPLETE:
|
||||
case bmHUB_PORT_EVENT_LS_RESET_COMPLETE:
|
||||
ClearPortFeature(HUB_FEATURE_C_PORT_RESET, port, 0);
|
||||
ClearPortFeature(HUB_FEATURE_C_PORT_CONNECTION, port, 0);
|
||||
// Reset complete event
|
||||
case bmHUB_PORT_EVENT_RESET_COMPLETE:
|
||||
case bmHUB_PORT_EVENT_LS_RESET_COMPLETE:
|
||||
ClearPortFeature(HUB_FEATURE_C_PORT_RESET, port, 0);
|
||||
ClearPortFeature(HUB_FEATURE_C_PORT_CONNECTION, port, 0);
|
||||
|
||||
delay(20);
|
||||
delay(20);
|
||||
|
||||
a.devAddress = bAddress;
|
||||
a.devAddress = bAddress;
|
||||
|
||||
pUsb->Configuring(a.bmAddress, port, (evt.bmStatus & bmHUB_PORT_STATUS_PORT_LOW_SPEED) );
|
||||
bResetInitiated = false;
|
||||
break;
|
||||
pUsb->Configuring(a.bmAddress, port, (evt.bmStatus & bmHUB_PORT_STATUS_PORT_LOW_SPEED));
|
||||
bResetInitiated = false;
|
||||
break;
|
||||
|
||||
} // switch (evt.bmEvent)
|
||||
return 0;
|
||||
} // switch (evt.bmEvent)
|
||||
return 0;
|
||||
}
|
||||
|
||||
void PrintHubPortStatus(USBHub *hubptr, uint8_t addr, uint8_t port, bool print_changes)
|
||||
{
|
||||
uint8_t rcode = 0;
|
||||
HubEvent evt;
|
||||
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);
|
||||
rcode = hubptr->GetPortStatus(port, 4, evt.evtBuff);
|
||||
|
||||
if (rcode)
|
||||
{
|
||||
Serial.println("ERROR!");
|
||||
return;
|
||||
}
|
||||
Serial.print("\r\nPort ");
|
||||
Serial.println(port, DEC);
|
||||
if (rcode) {
|
||||
Serial.println("ERROR!");
|
||||
return;
|
||||
}
|
||||
Serial.print("\r\nPort ");
|
||||
Serial.println(port, DEC);
|
||||
|
||||
Serial.println("Status");
|
||||
Serial.print("CONNECTION:\t");
|
||||
Serial.println((evt.bmStatus & bmHUB_PORT_STATUS_PORT_CONNECTION) > 0, DEC);
|
||||
Serial.print("ENABLE:\t\t");
|
||||
Serial.println((evt.bmStatus & bmHUB_PORT_STATUS_PORT_ENABLE) > 0, DEC);
|
||||
Serial.print("SUSPEND:\t");
|
||||
Serial.println((evt.bmStatus & bmHUB_PORT_STATUS_PORT_SUSPEND) > 0, DEC);
|
||||
Serial.print("OVER_CURRENT:\t");
|
||||
Serial.println((evt.bmStatus & bmHUB_PORT_STATUS_PORT_OVER_CURRENT) > 0, DEC);
|
||||
Serial.print("RESET:\t\t");
|
||||
Serial.println((evt.bmStatus & bmHUB_PORT_STATUS_PORT_RESET) > 0, DEC);
|
||||
Serial.print("POWER:\t\t");
|
||||
Serial.println((evt.bmStatus & bmHUB_PORT_STATUS_PORT_POWER) > 0, DEC);
|
||||
Serial.print("LOW_SPEED:\t");
|
||||
Serial.println((evt.bmStatus & bmHUB_PORT_STATUS_PORT_LOW_SPEED) > 0, DEC);
|
||||
Serial.print("HIGH_SPEED:\t");
|
||||
Serial.println((evt.bmStatus & bmHUB_PORT_STATUS_PORT_HIGH_SPEED) > 0, DEC);
|
||||
Serial.print("TEST:\t\t");
|
||||
Serial.println((evt.bmStatus & bmHUB_PORT_STATUS_PORT_TEST) > 0, DEC);
|
||||
Serial.print("INDICATOR:\t");
|
||||
Serial.println((evt.bmStatus & bmHUB_PORT_STATUS_PORT_INDICATOR) > 0, DEC);
|
||||
Serial.println("Status");
|
||||
Serial.print("CONNECTION:\t");
|
||||
Serial.println((evt.bmStatus & bmHUB_PORT_STATUS_PORT_CONNECTION) > 0, DEC);
|
||||
Serial.print("ENABLE:\t\t");
|
||||
Serial.println((evt.bmStatus & bmHUB_PORT_STATUS_PORT_ENABLE) > 0, DEC);
|
||||
Serial.print("SUSPEND:\t");
|
||||
Serial.println((evt.bmStatus & bmHUB_PORT_STATUS_PORT_SUSPEND) > 0, DEC);
|
||||
Serial.print("OVER_CURRENT:\t");
|
||||
Serial.println((evt.bmStatus & bmHUB_PORT_STATUS_PORT_OVER_CURRENT) > 0, DEC);
|
||||
Serial.print("RESET:\t\t");
|
||||
Serial.println((evt.bmStatus & bmHUB_PORT_STATUS_PORT_RESET) > 0, DEC);
|
||||
Serial.print("POWER:\t\t");
|
||||
Serial.println((evt.bmStatus & bmHUB_PORT_STATUS_PORT_POWER) > 0, DEC);
|
||||
Serial.print("LOW_SPEED:\t");
|
||||
Serial.println((evt.bmStatus & bmHUB_PORT_STATUS_PORT_LOW_SPEED) > 0, DEC);
|
||||
Serial.print("HIGH_SPEED:\t");
|
||||
Serial.println((evt.bmStatus & bmHUB_PORT_STATUS_PORT_HIGH_SPEED) > 0, DEC);
|
||||
Serial.print("TEST:\t\t");
|
||||
Serial.println((evt.bmStatus & bmHUB_PORT_STATUS_PORT_TEST) > 0, DEC);
|
||||
Serial.print("INDICATOR:\t");
|
||||
Serial.println((evt.bmStatus & bmHUB_PORT_STATUS_PORT_INDICATOR) > 0, DEC);
|
||||
|
||||
if (!print_changes)
|
||||
return;
|
||||
if (!print_changes)
|
||||
return;
|
||||
|
||||
Serial.println("\nChange");
|
||||
Serial.print("CONNECTION:\t");
|
||||
Serial.println((evt.bmChange & bmHUB_PORT_STATUS_C_PORT_CONNECTION) > 0, DEC);
|
||||
Serial.print("ENABLE:\t\t");
|
||||
Serial.println((evt.bmChange & bmHUB_PORT_STATUS_C_PORT_ENABLE) > 0, DEC);
|
||||
Serial.print("SUSPEND:\t");
|
||||
Serial.println((evt.bmChange & bmHUB_PORT_STATUS_C_PORT_SUSPEND) > 0, DEC);
|
||||
Serial.print("OVER_CURRENT:\t");
|
||||
Serial.println((evt.bmChange & bmHUB_PORT_STATUS_C_PORT_OVER_CURRENT) > 0, DEC);
|
||||
Serial.print("RESET:\t\t");
|
||||
Serial.println((evt.bmChange & bmHUB_PORT_STATUS_C_PORT_RESET) > 0, DEC);
|
||||
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");
|
||||
Serial.println((evt.bmChange & bmHUB_PORT_STATUS_C_PORT_ENABLE) > 0, DEC);
|
||||
Serial.print("SUSPEND:\t");
|
||||
Serial.println((evt.bmChange & bmHUB_PORT_STATUS_C_PORT_SUSPEND) > 0, DEC);
|
||||
Serial.print("OVER_CURRENT:\t");
|
||||
Serial.println((evt.bmChange & bmHUB_PORT_STATUS_C_PORT_OVER_CURRENT) > 0, DEC);
|
||||
Serial.print("RESET:\t\t");
|
||||
Serial.println((evt.bmChange & bmHUB_PORT_STATUS_C_PORT_RESET) > 0, DEC);
|
||||
}
|
||||
|
|
162
usbhub.h
162
usbhub.h
|
@ -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,116 +143,115 @@ 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
|
||||
{
|
||||
uint8_t bDescLength; // descriptor length
|
||||
uint8_t bDescriptorType; // descriptor type
|
||||
uint8_t bNbrPorts; // number of ports a hub equiped with
|
||||
struct HubDescriptor {
|
||||
uint8_t bDescLength; // descriptor length
|
||||
uint8_t bDescriptorType; // descriptor type
|
||||
uint8_t bNbrPorts; // number of ports a hub equiped with
|
||||
|
||||
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;
|
||||
};
|
||||
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;
|
||||
};
|
||||
uint8_t bPwrOn2PwrGood;
|
||||
uint8_t bHubContrCurrent;
|
||||
} __attribute__((packed));
|
||||
|
||||
struct HubEvent
|
||||
{
|
||||
union
|
||||
{
|
||||
struct
|
||||
{
|
||||
uint16_t bmStatus; // port status bits
|
||||
uint16_t bmChange; // port status change bits
|
||||
};
|
||||
uint32_t bmEvent;
|
||||
uint8_t evtBuff[4];
|
||||
};
|
||||
};
|
||||
struct HubEvent {
|
||||
|
||||
class USBHub : USBDeviceConfig
|
||||
{
|
||||
static bool bResetInitiated; // True when reset is triggered
|
||||
union {
|
||||
|
||||
USB *pUsb; // USB class instance pointer
|
||||
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));
|
||||
|
||||
EpInfo epInfo[2]; // interrupt endpoint info structure
|
||||
class USBHub : USBDeviceConfig {
|
||||
static bool bResetInitiated; // True when reset is triggered
|
||||
|
||||
uint8_t bAddress; // address
|
||||
uint8_t bNbrPorts; // number of ports
|
||||
uint8_t bInitState; // initialization state variable
|
||||
uint32_t qNextPollTime; // next poll time
|
||||
bool bPollEnable; // poll enable flag
|
||||
USB *pUsb; // USB class instance pointer
|
||||
|
||||
uint8_t CheckHubStatus();
|
||||
uint8_t PortStatusChange(uint8_t port, HubEvent &evt);
|
||||
EpInfo epInfo[2]; // interrupt endpoint info structure
|
||||
|
||||
uint8_t bAddress; // address
|
||||
uint8_t bNbrPorts; // number of ports
|
||||
uint8_t bInitState; // initialization state variable
|
||||
uint32_t qNextPollTime; // next poll time
|
||||
bool bPollEnable; // poll enable flag
|
||||
|
||||
uint8_t CheckHubStatus();
|
||||
uint8_t PortStatusChange(uint8_t port, HubEvent &evt);
|
||||
|
||||
public:
|
||||
USBHub(USB *p);
|
||||
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();
|
||||
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 Init(uint8_t parent, uint8_t port, bool lowspeed);
|
||||
virtual uint8_t Release();
|
||||
virtual uint8_t Poll();
|
||||
|
||||
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);
|
||||
|
|
54
xboxEnums.h
54
xboxEnums.h
|
@ -22,43 +22,43 @@
|
|||
|
||||
/** Enum used to set special LED modes supported by the Xbox controller. */
|
||||
enum LEDMode {
|
||||
ROTATING = 0x0A,
|
||||
FASTBLINK = 0x0B,
|
||||
SLOWBLINK = 0x0C,
|
||||
ALTERNATING = 0x0D,
|
||||
ROTATING = 0x0A,
|
||||
FASTBLINK = 0x0B,
|
||||
SLOWBLINK = 0x0C,
|
||||
ALTERNATING = 0x0D,
|
||||
};
|
||||
|
||||
/** Used to set the LEDs on the controllers */
|
||||
const uint8_t XBOXLEDS[] PROGMEM = {
|
||||
0x02, // LED1
|
||||
0x03, // LED2
|
||||
0x04, // LED3
|
||||
0x05, // LED4
|
||||
0x01 // ALL - Used to blink all LEDs
|
||||
};
|
||||
0x02, // LED1
|
||||
0x03, // LED2
|
||||
0x04, // LED3
|
||||
0x05, // LED4
|
||||
0x01 // ALL - Used to blink all LEDs
|
||||
};
|
||||
/** Buttons on the controllers */
|
||||
const uint16_t XBOXBUTTONS[] PROGMEM = {
|
||||
0x0100, // UP
|
||||
0x0800, // RIGHT
|
||||
0x0200, // DOWN
|
||||
0x0400, // LEFT
|
||||
0x0100, // UP
|
||||
0x0800, // RIGHT
|
||||
0x0200, // DOWN
|
||||
0x0400, // LEFT
|
||||
|
||||
0x2000, // BACK
|
||||
0x1000, // START
|
||||
0x4000, // L3
|
||||
0x8000, // R3
|
||||
0x2000, // BACK
|
||||
0x1000, // START
|
||||
0x4000, // L3
|
||||
0x8000, // R3
|
||||
|
||||
0,0, // Skip L2 and R2 as these are analog buttons
|
||||
0x0001, // L1
|
||||
0x0002, // R1
|
||||
0, 0, // Skip L2 and R2 as these are analog buttons
|
||||
0x0001, // L1
|
||||
0x0002, // R1
|
||||
|
||||
0x0020, // B
|
||||
0x0010, // A
|
||||
0x0040, // X
|
||||
0x0080, // Y
|
||||
0x0020, // B
|
||||
0x0010, // A
|
||||
0x0040, // X
|
||||
0x0080, // Y
|
||||
|
||||
0x0004, // XBOX
|
||||
0x0008 // SYNC
|
||||
0x0004, // XBOX
|
||||
0x0008 // SYNC
|
||||
};
|
||||
|
||||
#endif
|
Loading…
Reference in a new issue