mirror of
https://github.com/felis/USB_Host_Shield_2.0.git
synced 2024-03-22 11:31:26 +01:00
fixing conflict
This commit is contained in:
commit
1c5553e7bf
6 changed files with 2807 additions and 152 deletions
1539
RFCOMM.cpp
Normal file
1539
RFCOMM.cpp
Normal file
File diff suppressed because it is too large
Load diff
332
RFCOMM.h
Normal file
332
RFCOMM.h
Normal file
|
@ -0,0 +1,332 @@
|
||||||
|
/* Copyright (C) 2012 Kristian Lauszus, TKJ Electronics. All rights reserved.
|
||||||
|
|
||||||
|
This software may be distributed and modified under the terms of the GNU
|
||||||
|
General Public License version 2 (GPL2) as published by the Free Software
|
||||||
|
Foundation and appearing in the file GPL2.TXT included in the packaging of
|
||||||
|
this file. Please note that GPL2 Section 2[b] requires that all works based
|
||||||
|
on this software must also be made publicly available under the terms of
|
||||||
|
the GPL2 ("Copyleft").
|
||||||
|
|
||||||
|
Contact information
|
||||||
|
-------------------
|
||||||
|
|
||||||
|
Kristian Lauszus, TKJ Electronics
|
||||||
|
Web : http://www.tkjelectronics.com
|
||||||
|
e-mail : kristianl@tkjelectronics.com
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _rfcomm_h_
|
||||||
|
#define _rfcomm_h_
|
||||||
|
|
||||||
|
#if defined(ARDUINO) && ARDUINO >= 100
|
||||||
|
#include "Arduino.h"
|
||||||
|
#else
|
||||||
|
#include "WProgram.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "Usb.h"
|
||||||
|
#include "confdescparser.h"
|
||||||
|
|
||||||
|
/* CSR Bluetooth data taken from descriptors */
|
||||||
|
#define BULK_MAXPKTSIZE 64 // max size for ACL data
|
||||||
|
|
||||||
|
// used in control endpoint header for HCI Commands
|
||||||
|
#define bmREQ_HCI_OUT USB_SETUP_HOST_TO_DEVICE|USB_SETUP_TYPE_CLASS|USB_SETUP_RECIPIENT_DEVICE
|
||||||
|
|
||||||
|
/* Bluetooth HCI states for hci_task() */
|
||||||
|
#define HCI_INIT_STATE 0
|
||||||
|
#define HCI_RESET_STATE 1
|
||||||
|
#define HCI_BDADDR_STATE 2
|
||||||
|
#define HCI_SET_NAME_STATE 3
|
||||||
|
#define HCI_SCANNING_STATE 4
|
||||||
|
#define HCI_CONNECT_IN_STATE 5
|
||||||
|
#define HCI_REMOTE_NAME_STATE 6
|
||||||
|
#define HCI_CONNECTED_STATE 7
|
||||||
|
#define HCI_DISABLE_SCAN 8
|
||||||
|
#define HCI_DONE_STATE 9
|
||||||
|
#define HCI_DISCONNECT_STATE 10
|
||||||
|
|
||||||
|
/* HCI event flags*/
|
||||||
|
#define HCI_FLAG_CMD_COMPLETE 0x01
|
||||||
|
#define HCI_FLAG_CONN_COMPLETE 0x02
|
||||||
|
#define HCI_FLAG_DISCONN_COMPLETE 0x04
|
||||||
|
#define HCI_FLAG_REMOTE_NAME_COMPLETE 0x08
|
||||||
|
#define HCI_FLAG_INCOMING_REQUEST 0x10
|
||||||
|
#define HCI_FLAG_READ_BDADDR 0x20
|
||||||
|
|
||||||
|
/*Macros for HCI event flag tests */
|
||||||
|
#define hci_cmd_complete (hci_event_flag & HCI_FLAG_CMD_COMPLETE)
|
||||||
|
#define hci_connect_complete (hci_event_flag & HCI_FLAG_CONN_COMPLETE)
|
||||||
|
#define hci_disconnect_complete (hci_event_flag & HCI_FLAG_DISCONN_COMPLETE)
|
||||||
|
#define hci_remote_name_complete (hci_event_flag & HCI_FLAG_REMOTE_NAME_COMPLETE)
|
||||||
|
#define hci_incoming_connect_request (hci_event_flag & HCI_FLAG_INCOMING_REQUEST)
|
||||||
|
#define hci_read_bdaddr_complete (hci_event_flag & HCI_FLAG_READ_BDADDR)
|
||||||
|
|
||||||
|
/* HCI Events managed */
|
||||||
|
#define EV_COMMAND_COMPLETE 0x0E
|
||||||
|
#define EV_COMMAND_STATUS 0x0F
|
||||||
|
#define EV_CONNECT_COMPLETE 0x03
|
||||||
|
#define EV_DISCONNECT_COMPLETE 0x05
|
||||||
|
#define EV_NUM_COMPLETE_PKT 0x13
|
||||||
|
#define EV_INQUIRY_COMPLETE 0x01
|
||||||
|
#define EV_INQUIRY_RESULT 0x02
|
||||||
|
#define EV_REMOTE_NAME_COMPLETE 0x07
|
||||||
|
#define EV_INCOMING_CONNECT 0x04
|
||||||
|
#define EV_ROLE_CHANGED 0x12
|
||||||
|
#define EV_PAGE_SCAN_REP_MODE 0x20
|
||||||
|
#define EV_DATA_BUFFER_OVERFLOW 0x1A
|
||||||
|
#define EV_LOOPBACK_COMMAND 0x19
|
||||||
|
#define EV_CHANGE_CONNECTION_LINK 0x09
|
||||||
|
#define EV_AUTHENTICATION_COMPLETE 0x06
|
||||||
|
#define EV_MAX_SLOTS_CHANGE 0x1B
|
||||||
|
#define EV_PIN_CODE_REQUEST 0x16
|
||||||
|
#define EV_LINK_KEY_REQUEST 0x17
|
||||||
|
#define EV_QOS_SETUP_COMPLETE 0x0D
|
||||||
|
#define EV_LINK_KEY_NOTIFICATION 0x18
|
||||||
|
#define EV_ENCRYPTION_CHANGE 0x08
|
||||||
|
#define EV_READ_REMOTE_VERSION_INFORMATION_COMPLETE 0x0C
|
||||||
|
|
||||||
|
/* Bluetooth L2CAP states for SDP_task() and RFCOMM_task() */
|
||||||
|
#define L2CAP_SDP_WAIT 0
|
||||||
|
#define L2CAP_SDP_SETUP 1
|
||||||
|
#define L2CAP_SDP_REQUEST 2
|
||||||
|
#define L2CAP_SDP_SUCCESS 3
|
||||||
|
#define L2CAP_SDP_DONE 4
|
||||||
|
#define L2CAP_RFCOMM_WAIT 5
|
||||||
|
#define L2CAP_RFCOMM_SETUP 6
|
||||||
|
#define L2CAP_RFCOMM_REQUEST 7
|
||||||
|
#define L2CAP_RFCOMM_SUCCESS 8
|
||||||
|
#define L2CAP_RFCOMM_DONE 9
|
||||||
|
#define L2CAP_DISCONNECT_RESPONSE 10
|
||||||
|
|
||||||
|
/* L2CAP event flags */
|
||||||
|
#define L2CAP_FLAG_CONNECTION_SDP_REQUEST 0x001
|
||||||
|
#define L2CAP_FLAG_CONNECTION_RFCOMM_REQUEST 0x002
|
||||||
|
#define L2CAP_FLAG_CONFIG_SDP_REQUEST 0x004
|
||||||
|
#define L2CAP_FLAG_CONFIG_RFCOMM_REQUEST 0x008
|
||||||
|
#define L2CAP_FLAG_CONFIG_SDP_SUCCESS 0x010
|
||||||
|
#define L2CAP_FLAG_CONFIG_RFCOMM_SUCCESS 0x020
|
||||||
|
#define L2CAP_FLAG_DISCONNECT_SDP_REQUEST 0x040
|
||||||
|
#define L2CAP_FLAG_DISCONNECT_RFCOMM_REQUEST 0x080
|
||||||
|
#define L2CAP_FLAG_DISCONNECT_RESPONSE 0x100
|
||||||
|
|
||||||
|
/* Macros for L2CAP event flag tests */
|
||||||
|
#define l2cap_connection_request_sdp_flag (l2cap_event_flag & L2CAP_FLAG_CONNECTION_SDP_REQUEST)
|
||||||
|
#define l2cap_connection_request_rfcomm_flag (l2cap_event_flag & L2CAP_FLAG_CONNECTION_RFCOMM_REQUEST)
|
||||||
|
#define l2cap_config_request_sdp_flag (l2cap_event_flag & L2CAP_FLAG_CONFIG_SDP_REQUEST)
|
||||||
|
#define l2cap_config_request_rfcomm_flag (l2cap_event_flag & L2CAP_FLAG_CONFIG_RFCOMM_REQUEST)
|
||||||
|
#define l2cap_config_success_sdp_flag (l2cap_event_flag & L2CAP_FLAG_CONFIG_SDP_SUCCESS)
|
||||||
|
#define l2cap_config_success_rfcomm_flag (l2cap_event_flag & L2CAP_FLAG_CONFIG_RFCOMM_SUCCESS)
|
||||||
|
#define l2cap_disconnect_request_sdp_flag (l2cap_event_flag & L2CAP_FLAG_DISCONNECT_SDP_REQUEST)
|
||||||
|
#define l2cap_disconnect_request_rfcomm_flag (l2cap_event_flag & L2CAP_FLAG_DISCONNECT_RFCOMM_REQUEST)
|
||||||
|
#define l2cap_disconnect_response_flag (l2cap_event_flag & L2CAP_FLAG_DISCONNECT_RESPONSE)
|
||||||
|
|
||||||
|
/* L2CAP signaling commands */
|
||||||
|
#define L2CAP_CMD_COMMAND_REJECT 0x01
|
||||||
|
#define L2CAP_CMD_CONNECTION_REQUEST 0x02
|
||||||
|
#define L2CAP_CMD_CONNECTION_RESPONSE 0x03
|
||||||
|
#define L2CAP_CMD_CONFIG_REQUEST 0x04
|
||||||
|
#define L2CAP_CMD_CONFIG_RESPONSE 0x05
|
||||||
|
#define L2CAP_CMD_DISCONNECT_REQUEST 0x06
|
||||||
|
#define L2CAP_CMD_DISCONNECT_RESPONSE 0x07
|
||||||
|
#define L2CAP_CMD_INFORMATION_REQUEST 0x0A
|
||||||
|
#define L2CAP_CMD_INFORMATION_RESPONSE 0x0B
|
||||||
|
|
||||||
|
/* Bluetooth L2CAP PSM */
|
||||||
|
#define SDP_PSM 0x01 // Service Discovery Protocol PSM Value
|
||||||
|
#define RFCOMM_PSM 0x03 // RFCOMM PSM Value
|
||||||
|
|
||||||
|
// Used For Connection Response - Remember to Include High Byte
|
||||||
|
#define PENDING 0x01
|
||||||
|
#define SUCCESSFUL 0x00
|
||||||
|
|
||||||
|
// Used to determine if it is a Bluetooth dongle
|
||||||
|
#define WI_SUBCLASS_RF 0x01 // RF Controller
|
||||||
|
#define WI_PROTOCOL_BT 0x01 // Bluetooth Programming Interface
|
||||||
|
|
||||||
|
#define BTD_MAX_ENDPOINTS 4
|
||||||
|
|
||||||
|
/* Used for SDP */
|
||||||
|
#define SDP_SERVICE_SEARCH_ATTRIBUTE_REQUEST_PDU 0x06 // See the RFCOMM specs
|
||||||
|
#define SDP_SERVICE_SEARCH_ATTRIBUTE_RESPONSE_PDU 0x07 // See the RFCOMM specs
|
||||||
|
#define SERIALPORT_UUID 0x1101 // See http://www.bluetooth.org/Technical/AssignedNumbers/service_discovery.htm
|
||||||
|
#define L2CAP_UUID 0x0100
|
||||||
|
|
||||||
|
/* Used for RFCOMM */
|
||||||
|
#define RFCOMM_SABM 0x2F
|
||||||
|
#define RFCOMM_UA 0x63
|
||||||
|
#define RFCOMM_UIH 0xEF
|
||||||
|
//#define RFCOMM_DM 0x0F
|
||||||
|
#define RFCOMM_DISC 0x43
|
||||||
|
|
||||||
|
#define extendAddress 0x01 // Allways 1
|
||||||
|
|
||||||
|
// Multiplexer message types
|
||||||
|
#define BT_RFCOMM_PN_CMD 0x83
|
||||||
|
#define BT_RFCOMM_PN_RSP 0x81
|
||||||
|
#define BT_RFCOMM_MSC_CMD 0xE3
|
||||||
|
#define BT_RFCOMM_MSC_RSP 0xE1
|
||||||
|
#define BT_RFCOMM_RPN_CMD 0x93
|
||||||
|
#define BT_RFCOMM_RPN_RSP 0x91
|
||||||
|
/*
|
||||||
|
#define BT_RFCOMM_TEST_CMD 0x23
|
||||||
|
#define BT_RFCOMM_TEST_RSP 0x21
|
||||||
|
#define BT_RFCOMM_FCON_CMD 0xA3
|
||||||
|
#define BT_RFCOMM_FCON_RSP 0xA1
|
||||||
|
#define BT_RFCOMM_FCOFF_CMD 0x63
|
||||||
|
#define BT_RFCOMM_FCOFF_RSP 0x61
|
||||||
|
#define BT_RFCOMM_RLS_CMD 0x53
|
||||||
|
#define BT_RFCOMM_RLS_RSP 0x51
|
||||||
|
#define BT_RFCOMM_NSC_RSP 0x11
|
||||||
|
*/
|
||||||
|
|
||||||
|
class RFCOMM : public USBDeviceConfig, public UsbConfigXtracter {
|
||||||
|
public:
|
||||||
|
RFCOMM(USB *p, const char* name = "Arduino", const char* pin = "1234");
|
||||||
|
|
||||||
|
// 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 bPollEnable; };
|
||||||
|
|
||||||
|
// UsbConfigXtracter implementation
|
||||||
|
virtual void EndpointXtract(uint8_t conf, uint8_t iface, uint8_t alt, uint8_t proto, const USB_ENDPOINT_DESCRIPTOR *ep);
|
||||||
|
|
||||||
|
bool isWatingForConnection() { return watingForConnection; }; // Use this to indicate when it is ready for a incoming connection
|
||||||
|
|
||||||
|
void disconnect(); // Used this void to disconnect the virtual serial port
|
||||||
|
bool connected;// Variable used to indicate if the connection is established
|
||||||
|
|
||||||
|
/* Serial commands currently supported */
|
||||||
|
void print(const char* data); // Used to send strings
|
||||||
|
void print(uint8_t data); // Used to send single bytes
|
||||||
|
void println(const char* data); // Include newline and carriage return
|
||||||
|
void println(uint8_t data); // Include newline and carriage return
|
||||||
|
uint8_t available() { return rfcommAvailable; }; // Get the bytes waiting to be read
|
||||||
|
uint8_t read(); // Used to read the buffer
|
||||||
|
|
||||||
|
protected:
|
||||||
|
/* mandatory members */
|
||||||
|
USB *pUsb;
|
||||||
|
uint8_t bAddress; // device address
|
||||||
|
EpInfo epInfo[BTD_MAX_ENDPOINTS]; //endpoint info structure
|
||||||
|
|
||||||
|
uint8_t bConfNum; // configuration number
|
||||||
|
uint8_t bNumEP; // total number of endpoints in the configuration
|
||||||
|
uint32_t qNextPollTime; // next poll time
|
||||||
|
|
||||||
|
#define BTD_CONTROL_PIPE 0 // Bluetooth dongles control endpoint
|
||||||
|
static const uint8_t BTD_EVENT_PIPE; // HCI event endpoint index
|
||||||
|
static const uint8_t BTD_DATAIN_PIPE; // ACL In endpoint index
|
||||||
|
static const uint8_t BTD_DATAOUT_PIPE; // ACL Out endpoint index
|
||||||
|
|
||||||
|
void PrintEndpointDescriptor(const USB_ENDPOINT_DESCRIPTOR* ep_ptr);
|
||||||
|
|
||||||
|
private:
|
||||||
|
const char* btdName;
|
||||||
|
const char* btdPin;
|
||||||
|
|
||||||
|
bool bPollEnable;
|
||||||
|
uint8_t pollInterval;
|
||||||
|
bool watingForConnection;
|
||||||
|
|
||||||
|
/* Set true when a channel is created */
|
||||||
|
bool SDPConnected;
|
||||||
|
bool RFCOMMConnected;
|
||||||
|
|
||||||
|
/*variables filled from HCI event management */
|
||||||
|
uint16_t hci_handle;
|
||||||
|
uint8_t my_bdaddr[6]; // The bluetooth dongles Bluetooth address
|
||||||
|
uint8_t disc_bdaddr[6]; // the bluetooth address is always 6 bytes
|
||||||
|
uint8_t remote_name[30]; // first 30 chars of remote name
|
||||||
|
|
||||||
|
/* 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
|
||||||
|
|
||||||
|
/* variables used by high level L2CAP task */
|
||||||
|
uint8_t l2cap_sdp_state;
|
||||||
|
uint8_t l2cap_rfcomm_state;
|
||||||
|
uint16_t l2cap_event_flag;// l2cap flags of received bluetooth events
|
||||||
|
|
||||||
|
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 rfcommbuf[BULK_MAXPKTSIZE]; // Buffer for RFCOMM Data
|
||||||
|
|
||||||
|
/* L2CAP Channels */
|
||||||
|
uint8_t sdp_scid[2]; // L2CAP source CID for HID_Control
|
||||||
|
uint8_t sdp_dcid[2]; // 0x0050
|
||||||
|
uint8_t rfcomm_scid[2]; // L2CAP source CID for HID_Interrupt
|
||||||
|
uint8_t rfcomm_dcid[2]; // 0x0051
|
||||||
|
uint8_t identifier; // Identifier for command
|
||||||
|
|
||||||
|
/* RFCOMM Variables */
|
||||||
|
uint8_t rfcommChannel;
|
||||||
|
uint8_t rfcommChannelPermanent;
|
||||||
|
uint8_t rfcommDirection;
|
||||||
|
uint8_t rfcommCommandResponse;
|
||||||
|
uint8_t rfcommChannelType;
|
||||||
|
uint8_t rfcommPfBit;
|
||||||
|
|
||||||
|
unsigned long timer;
|
||||||
|
bool waitForLastCommand;
|
||||||
|
bool creditSent;
|
||||||
|
|
||||||
|
uint8_t rfcommDataBuffer[256]; // Create a 256 sized buffer for incoming data
|
||||||
|
uint8_t rfcommAvailable;
|
||||||
|
|
||||||
|
bool firstMessage; // Used to see if it's the first SDP request received
|
||||||
|
|
||||||
|
/* State machines */
|
||||||
|
void HCI_event_task(); //poll the HCI event pipe
|
||||||
|
void HCI_task(); // HCI state machine
|
||||||
|
void ACL_event_task(); // start polling the ACL input pipe too, though discard data until connected
|
||||||
|
void SDP_task(); // SDP state machine
|
||||||
|
void RFCOMM_task(); // RFCOMM state machine
|
||||||
|
|
||||||
|
void readReport(); // read incoming data
|
||||||
|
void printReport(); // print incoming date - Uncomment "#define PRINTREPORT" to print incoming data debugging
|
||||||
|
|
||||||
|
/* HCI Commands */
|
||||||
|
void HCI_Command(uint8_t* data, uint16_t nbytes);
|
||||||
|
void hci_reset();
|
||||||
|
void hci_write_scan_enable();
|
||||||
|
void hci_write_scan_disable();
|
||||||
|
void hci_read_bdaddr();
|
||||||
|
void hci_accept_connection();
|
||||||
|
void hci_remote_name();
|
||||||
|
void hci_set_local_name(const char* name);
|
||||||
|
void hci_pin_code_request_reply(const char* key);
|
||||||
|
void hci_link_key_request_negative_reply();
|
||||||
|
void hci_disconnect();
|
||||||
|
|
||||||
|
/* L2CAP Commands */
|
||||||
|
void L2CAP_Command(uint8_t* data, uint16_t nbytes, uint8_t channelLow = 0x01, uint8_t channelHigh = 0x00); // Standard L2CAP header: Channel ID (0x01) for ACL-U
|
||||||
|
void l2cap_connection_response(uint8_t rxid, uint8_t* dcid, uint8_t* scid, uint8_t result);
|
||||||
|
void l2cap_config_request(uint8_t rxid, uint8_t* dcid);
|
||||||
|
void l2cap_config_response(uint8_t rxid, uint8_t* scid);
|
||||||
|
void l2cap_disconnection_request(uint8_t rxid, uint8_t* dcid, uint8_t* scid);
|
||||||
|
void l2cap_disconnection_response(uint8_t rxid, uint8_t* dcid, uint8_t* scid);
|
||||||
|
void l2cap_information_response(uint8_t rxid, uint8_t infoTypeLow, uint8_t infoTypeHigh);
|
||||||
|
|
||||||
|
/* SDP Commands */
|
||||||
|
void SDP_Command(uint8_t* data, uint16_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, uint16_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
|
38
examples/RFCOMM/RFCOMM.ino
Normal file
38
examples/RFCOMM/RFCOMM.ino
Normal file
|
@ -0,0 +1,38 @@
|
||||||
|
/*
|
||||||
|
Example sketch for the RFCOMM Bluetooth library - developed by Kristian Lauszus
|
||||||
|
For more information visit my blog: http://blog.tkjelectronics.dk/ or
|
||||||
|
send me an e-mail: kristianl@tkjelectronics.com
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <RFCOMM.h>
|
||||||
|
USB Usb;
|
||||||
|
/* You can create the instance of the class in two ways */
|
||||||
|
RFCOMM SerialBT(&Usb); // This will set the name to the defaults: "Arduino" and the pin to "1234"
|
||||||
|
//RFCOMM SerialBT(&Usb, "Lauszus' Arduino","0000"); // You can also set the name and pin like so
|
||||||
|
|
||||||
|
boolean firstMessage = true;
|
||||||
|
|
||||||
|
void setup() {
|
||||||
|
Serial.begin(115200);
|
||||||
|
if (Usb.Init() == -1) {
|
||||||
|
Serial.print(F("\r\nOSC did not start"));
|
||||||
|
while(1); //halt
|
||||||
|
}
|
||||||
|
Serial.print(F("\r\nRFCOMM Bluetooth Library Started"));
|
||||||
|
}
|
||||||
|
void loop() {
|
||||||
|
Usb.Task();
|
||||||
|
if(SerialBT.connected) {
|
||||||
|
if(firstMessage) {
|
||||||
|
firstMessage = false;
|
||||||
|
SerialBT.println("Hello from Arduino"); // Send welcome message
|
||||||
|
}
|
||||||
|
if(Serial.available())
|
||||||
|
SerialBT.print(Serial.read());
|
||||||
|
if(SerialBT.available())
|
||||||
|
Serial.write(SerialBT.read());
|
||||||
|
}
|
||||||
|
else
|
||||||
|
firstMessage = true;
|
||||||
|
delay(5);
|
||||||
|
}
|
152
keywords.txt
152
keywords.txt
|
@ -1,152 +0,0 @@
|
||||||
################################################
|
|
||||||
# Syntax Coloring Map For PS3 Bluetooth Library
|
|
||||||
################################################
|
|
||||||
|
|
||||||
################################################
|
|
||||||
# Datatypes (KEYWORD1)
|
|
||||||
################################################
|
|
||||||
|
|
||||||
PS3BT KEYWORD1
|
|
||||||
|
|
||||||
################################################
|
|
||||||
# Methods and Functions (KEYWORD2)
|
|
||||||
################################################
|
|
||||||
setBdaddr KEYWORD2
|
|
||||||
setMoveBdaddr KEYWORD2
|
|
||||||
|
|
||||||
getButton KEYWORD2
|
|
||||||
getAnalogButton KEYWORD2
|
|
||||||
getAnalogHat KEYWORD2
|
|
||||||
getSensor KEYWORD2
|
|
||||||
getAngle KEYWORD2
|
|
||||||
getStatus KEYWORD2
|
|
||||||
getStatusString KEYWORD2
|
|
||||||
disconnect KEYWORD2
|
|
||||||
|
|
||||||
setAllOff KEYWORD2
|
|
||||||
setRumbleOff KEYWORD2
|
|
||||||
setRumbleOn KEYWORD2
|
|
||||||
setLedOff KEYWORD2
|
|
||||||
setLedOn KEYWORD2
|
|
||||||
moveSetBulb KEYWORD2
|
|
||||||
moveSetRumble KEYWORD2
|
|
||||||
|
|
||||||
PS3BTConnected KEYWORD2
|
|
||||||
PS3MoveBTConnected KEYWORD2
|
|
||||||
PS3NavigationBTConnected KEYWORD2
|
|
||||||
buttonChanged KEYWORD2
|
|
||||||
buttonPressed KEYWORD2
|
|
||||||
buttonReleased KEYWORD2
|
|
||||||
|
|
||||||
isWatingForConnection KEYWORD2
|
|
||||||
|
|
||||||
################################################
|
|
||||||
# Constants and enums (LITERAL1)
|
|
||||||
################################################
|
|
||||||
LED1 LITERAL1
|
|
||||||
LED2 LITERAL1
|
|
||||||
LED3 LITERAL1
|
|
||||||
LED4 LITERAL1
|
|
||||||
LED5 LITERAL1
|
|
||||||
LED6 LITERAL1
|
|
||||||
LED7 LITERAL1
|
|
||||||
LED8 LITERAL1
|
|
||||||
LED9 LITERAL1
|
|
||||||
LED10 LITERAL1
|
|
||||||
|
|
||||||
Red LITERAL1
|
|
||||||
Green LITERAL1
|
|
||||||
Blue LITERAL1
|
|
||||||
Yellow LITERAL1
|
|
||||||
Lightblue LITERAL1
|
|
||||||
Purble LITERAL1
|
|
||||||
White LITERAL1
|
|
||||||
Off LITERAL1
|
|
||||||
|
|
||||||
SELECT LITERAL1
|
|
||||||
L3 LITERAL1
|
|
||||||
R3 LITERAL1
|
|
||||||
START LITERAL1
|
|
||||||
UP LITERAL1
|
|
||||||
RIGHT LITERAL1
|
|
||||||
DOWN LITERAL1
|
|
||||||
LEFT LITERAL1
|
|
||||||
L2 LITERAL1
|
|
||||||
R2 LITERAL1
|
|
||||||
L1 LITERAL1
|
|
||||||
R1 LITERAL1
|
|
||||||
TRIANGLE LITERAL1
|
|
||||||
CIRCLE LITERAL1
|
|
||||||
CROSS LITERAL1
|
|
||||||
SQUARE LITERAL1
|
|
||||||
PS LITERAL1
|
|
||||||
SELECT_MOVE LITERAL1
|
|
||||||
START_MOVE LITERAL1
|
|
||||||
TRIANGLE_MOVE LITERAL1
|
|
||||||
CIRCLE_MOVE LITERAL1
|
|
||||||
CROSS_MOVE LITERAL1
|
|
||||||
SQUARE_MOVE LITERAL1
|
|
||||||
PS_MOVE LITERAL1
|
|
||||||
MOVE_MOVE LITERAL1
|
|
||||||
T_MOVE LITERAL1
|
|
||||||
|
|
||||||
UP_ANALOG LITERAL1
|
|
||||||
RIGHT_ANALOG LITERAL1
|
|
||||||
DOWN_ANALOG LITERAL1
|
|
||||||
LEFT_ANALOG LITERAL1
|
|
||||||
L2_ANALOG LITERAL1
|
|
||||||
R2_ANALOG LITERAL1
|
|
||||||
L1_ANALOG LITERAL1
|
|
||||||
R1_ANALOG LITERAL1
|
|
||||||
TRIANGLE_ANALOG LITERAL1
|
|
||||||
CIRCLE_ANALOG LITERAL1
|
|
||||||
CROSS_ANALOG LITERAL1
|
|
||||||
SQUARE_ANALOG LITERAL1
|
|
||||||
T_MOVE_ANALOG LITERAL1
|
|
||||||
|
|
||||||
LeftHatX LITERAL1
|
|
||||||
LeftHatY LITERAL1
|
|
||||||
RightHatX LITERAL1
|
|
||||||
RightHatY LITERAL1
|
|
||||||
|
|
||||||
aX LITERAL1
|
|
||||||
aY LITERAL1
|
|
||||||
aZ LITERAL1
|
|
||||||
gZ LITERAL1
|
|
||||||
aXmove LITERAL1
|
|
||||||
aYmove LITERAL1
|
|
||||||
aZmove LITERAL1
|
|
||||||
gXmove LITERAL1
|
|
||||||
gYmove LITERAL1
|
|
||||||
gZmove LITERAL1
|
|
||||||
tempMove LITERAL1
|
|
||||||
mXmove LITERAL1
|
|
||||||
mZmove LITERAL1
|
|
||||||
mYmove LITERAL1
|
|
||||||
|
|
||||||
Pitch LITERAL1
|
|
||||||
Roll LITERAL1
|
|
||||||
|
|
||||||
Plugged LITERAL1
|
|
||||||
Unplugged LITERAL1
|
|
||||||
Charging LITERAL1
|
|
||||||
NotCharging LITERAL1
|
|
||||||
Shutdown LITERAL1
|
|
||||||
Dying LITERAL1
|
|
||||||
Low LITERAL1
|
|
||||||
High LITERAL1
|
|
||||||
Full LITERAL1
|
|
||||||
MoveCharging LITERAL1
|
|
||||||
MoveNotCharging LITERAL1
|
|
||||||
MoveShutdown LITERAL1
|
|
||||||
MoveDying LITERAL1
|
|
||||||
MoveLow LITERAL1
|
|
||||||
MoveHigh LITERAL1
|
|
||||||
MoveFull LITERAL1
|
|
||||||
CableRumble LITERAL1
|
|
||||||
Cable LITERAL1
|
|
||||||
BluetoothRumble LITERAL1
|
|
||||||
Bluetooth LITERAL1
|
|
||||||
|
|
||||||
RumbleHigh LITERAL1
|
|
||||||
RumbleLow LITERAL1
|
|
646
masstorage.cpp
Normal file
646
masstorage.cpp
Normal file
|
@ -0,0 +1,646 @@
|
||||||
|
#include "masstorage.h"
|
||||||
|
|
||||||
|
|
||||||
|
//bool BulkReadParser::IsValidCSW(uint8_t size, uint8_t *pcsw)
|
||||||
|
//{
|
||||||
|
// if (size != 0x0d)
|
||||||
|
// {
|
||||||
|
// Notify(PSTR("CSW:Size error"));
|
||||||
|
// return false;
|
||||||
|
// }
|
||||||
|
// if (*((uint32_t*)pcsw) != MASS_CSW_SIGNATURE)
|
||||||
|
// {
|
||||||
|
// Notify(PSTR("CSW:Sig error"));
|
||||||
|
// return false;
|
||||||
|
// }
|
||||||
|
// //if (size != 0x0d || *((uint32_t*)pcsw) != MASS_CSW_SIGNATURE ||
|
||||||
|
// // ((CommandStatusWrapper*)pcsw)->dCSWTag != dCBWTag)
|
||||||
|
// // return false;
|
||||||
|
// return true;
|
||||||
|
//}
|
||||||
|
|
||||||
|
//bool BulkReadParser::IsMeaningfulCSW(uint8_t size, uint8_t *pcsw)
|
||||||
|
//{
|
||||||
|
// if (((CommandStatusWrapper*)pcsw)->bCSWStatus < 2 &&
|
||||||
|
// ((CommandStatusWrapper*)pcsw)->dCSWDataResidue <= dCBWDataTransferLength )
|
||||||
|
// return true;
|
||||||
|
// if ( ((CommandStatusWrapper*)pcsw)->bCSWStatus == 2 )
|
||||||
|
// return true;
|
||||||
|
// return false;
|
||||||
|
//}
|
||||||
|
|
||||||
|
//void BulkReadParser::Parse(const uint16_t len, const uint8_t *pbuf, const uint16_t &offset)
|
||||||
|
//{
|
||||||
|
// if (offset == 0 && len > sizeof(CommandStatusWrapper))
|
||||||
|
// if (IsValidCSW(sizeof(CommandStatusWrapper), pbuf) && IsMeaningfulCSW(sizeof(CommandStatusWrapper), pbuf))
|
||||||
|
// {
|
||||||
|
// CommandStatusWrapper *pCSW = (CommandStatusWrapper*)pbuf;
|
||||||
|
//
|
||||||
|
// Serial.println("Sig:");
|
||||||
|
// PrintHex<uint32_t>(pCSW->dCSWSignature);
|
||||||
|
// Serial.println("Tag:");
|
||||||
|
// PrintHex<uint32_t>(pCSW->dCSWTag);
|
||||||
|
// Serial.println("Res:");
|
||||||
|
// PrintHex<uint32_t>(pCSW->dCSWDataResidue);
|
||||||
|
// Serial.println("Ret:");
|
||||||
|
// PrintHex<uint8_t>(pCSW->bCSWStatus);
|
||||||
|
// }
|
||||||
|
//}
|
||||||
|
|
||||||
|
const uint8_t BulkOnly::epDataInIndex = 1;
|
||||||
|
const uint8_t BulkOnly::epDataOutIndex = 2;
|
||||||
|
const uint8_t BulkOnly::epInterruptInIndex = 3;
|
||||||
|
|
||||||
|
BulkOnly::BulkOnly(USB *p /*, CDCAsyncOper *pasync*/) :
|
||||||
|
pUsb(p),
|
||||||
|
//pAsync(pasync),
|
||||||
|
bAddress(0),
|
||||||
|
qNextPollTime(0),
|
||||||
|
bPollEnable(false),
|
||||||
|
bIface(0),
|
||||||
|
bNumEP(1)
|
||||||
|
{
|
||||||
|
for(uint8_t i=0; i<MASS_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);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t BulkOnly::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
|
||||||
|
|
||||||
|
AddressPool &addrPool = pUsb->GetAddressPool();
|
||||||
|
|
||||||
|
USBTRACE("MS Init\r\n");
|
||||||
|
|
||||||
|
if (bAddress)
|
||||||
|
return USB_ERROR_CLASS_INSTANCE_ALREADY_IN_USE;
|
||||||
|
|
||||||
|
// Get pointer to pseudo device with address 0 assigned
|
||||||
|
p = addrPool.GetUsbDevicePtr(0);
|
||||||
|
|
||||||
|
if (!p)
|
||||||
|
return USB_ERROR_ADDRESS_NOT_FOUND_IN_POOL;
|
||||||
|
|
||||||
|
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;
|
||||||
|
|
||||||
|
// 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, constBufSize, (uint8_t*)buf );
|
||||||
|
|
||||||
|
// Restore p->epinfo
|
||||||
|
p->epinfo = oldep_ptr;
|
||||||
|
|
||||||
|
if( rcode )
|
||||||
|
goto FailGetDevDescr;
|
||||||
|
|
||||||
|
// 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 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 );
|
||||||
|
|
||||||
|
if (rcode)
|
||||||
|
{
|
||||||
|
p->lowspeed = false;
|
||||||
|
addrPool.FreeAddress(bAddress);
|
||||||
|
bAddress = 0;
|
||||||
|
USBTRACE2("setAddr:",rcode);
|
||||||
|
return rcode;
|
||||||
|
}
|
||||||
|
|
||||||
|
USBTRACE2("Addr:", bAddress);
|
||||||
|
|
||||||
|
p->lowspeed = false;
|
||||||
|
|
||||||
|
p = addrPool.GetUsbDevicePtr(bAddress);
|
||||||
|
|
||||||
|
if (!p)
|
||||||
|
return USB_ERROR_ADDRESS_NOT_FOUND_IN_POOL;
|
||||||
|
|
||||||
|
p->lowspeed = lowspeed;
|
||||||
|
|
||||||
|
num_of_conf = ((USB_DEVICE_DESCRIPTOR*)buf)->bNumConfigurations;
|
||||||
|
|
||||||
|
// Assign epInfo to epinfo pointer
|
||||||
|
rcode = pUsb->setEpInfoEntry(bAddress, 1, epInfo);
|
||||||
|
|
||||||
|
if (rcode)
|
||||||
|
goto FailSetDevTblEntry;
|
||||||
|
|
||||||
|
USBTRACE2("NC:", num_of_conf);
|
||||||
|
|
||||||
|
for (uint8_t i=0; i<num_of_conf; i++)
|
||||||
|
{
|
||||||
|
HexDumper<USBReadParser, uint16_t, uint16_t> HexDump;
|
||||||
|
ConfigDescParser< USB_CLASS_MASS_STORAGE,
|
||||||
|
MASS_SUBCLASS_SCSI,
|
||||||
|
MASS_PROTO_BBB,
|
||||||
|
CP_MASK_COMPARE_CLASS |
|
||||||
|
CP_MASK_COMPARE_SUBCLASS |
|
||||||
|
CP_MASK_COMPARE_PROTOCOL> BulkOnlyParser(this);
|
||||||
|
|
||||||
|
rcode = pUsb->getConfDescr(bAddress, 0, i, &HexDump);
|
||||||
|
rcode = pUsb->getConfDescr(bAddress, 0, i, &BulkOnlyParser);
|
||||||
|
|
||||||
|
|
||||||
|
if (bNumEP > 1)
|
||||||
|
break;
|
||||||
|
} // for
|
||||||
|
|
||||||
|
if (bNumEP < 3)
|
||||||
|
return USB_DEV_CONFIG_ERROR_DEVICE_NOT_SUPPORTED;
|
||||||
|
|
||||||
|
// Assign epInfo to epinfo pointer
|
||||||
|
rcode = pUsb->setEpInfoEntry(bAddress, bNumEP, epInfo);
|
||||||
|
|
||||||
|
USBTRACE2("Conf:", bConfNum);
|
||||||
|
|
||||||
|
// Set Configuration Value
|
||||||
|
rcode = pUsb->setConf(bAddress, 0, bConfNum);
|
||||||
|
|
||||||
|
if (rcode)
|
||||||
|
goto FailSetConf;
|
||||||
|
|
||||||
|
delay(5000);
|
||||||
|
|
||||||
|
//rcode = pAsync->OnInit(this);
|
||||||
|
|
||||||
|
//if (rcode)
|
||||||
|
// goto FailOnInit;
|
||||||
|
|
||||||
|
rcode = GetMaxLUN(&bMaxLUN);
|
||||||
|
|
||||||
|
if (rcode)
|
||||||
|
goto FailGetMaxLUN;
|
||||||
|
|
||||||
|
delay(10);
|
||||||
|
|
||||||
|
{
|
||||||
|
InquiryResponse response;
|
||||||
|
rcode = Inquiry(bMaxLUN, sizeof(InquiryResponse), (uint8_t*)&response);
|
||||||
|
|
||||||
|
if (rcode)
|
||||||
|
goto FailInquiry;
|
||||||
|
|
||||||
|
//if (response.DeviceType != 0)
|
||||||
|
// goto FailInvalidDevice;
|
||||||
|
}
|
||||||
|
|
||||||
|
delay(10);
|
||||||
|
|
||||||
|
USBTRACE("MS configured\r\n");
|
||||||
|
|
||||||
|
bPollEnable = true;
|
||||||
|
|
||||||
|
//USBTRACE("Poll enabled\r\n");
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
FailGetDevDescr:
|
||||||
|
USBTRACE("getDevDescr:");
|
||||||
|
goto Fail;
|
||||||
|
|
||||||
|
FailSetDevTblEntry:
|
||||||
|
USBTRACE("setDevTblEn:");
|
||||||
|
goto Fail;
|
||||||
|
|
||||||
|
FailGetConfDescr:
|
||||||
|
USBTRACE("getConf:");
|
||||||
|
goto Fail;
|
||||||
|
|
||||||
|
FailSetConf:
|
||||||
|
USBTRACE("setConf:");
|
||||||
|
goto Fail;
|
||||||
|
|
||||||
|
FailOnInit:
|
||||||
|
USBTRACE("OnInit:");
|
||||||
|
goto Fail;
|
||||||
|
|
||||||
|
FailGetMaxLUN:
|
||||||
|
USBTRACE("GetMaxLUN:");
|
||||||
|
goto Fail;
|
||||||
|
|
||||||
|
FailInquiry:
|
||||||
|
USBTRACE("Inquiry:");
|
||||||
|
goto Fail;
|
||||||
|
|
||||||
|
Fail:
|
||||||
|
Serial.println(rcode, HEX);
|
||||||
|
Release();
|
||||||
|
return rcode;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void BulkOnly::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;
|
||||||
|
|
||||||
|
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;
|
||||||
|
|
||||||
|
// 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);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t BulkOnly::Release()
|
||||||
|
{
|
||||||
|
pUsb->GetAddressPool().FreeAddress(bAddress);
|
||||||
|
|
||||||
|
bIface = 0;
|
||||||
|
bNumEP = 1;
|
||||||
|
|
||||||
|
bAddress = 0;
|
||||||
|
qNextPollTime = 0;
|
||||||
|
bPollEnable = false;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t BulkOnly::Poll()
|
||||||
|
{
|
||||||
|
uint8_t rcode = 0;
|
||||||
|
|
||||||
|
if (!bPollEnable)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
uint32_t time_now = millis();
|
||||||
|
|
||||||
|
//if (qNextPollTime <= time_now)
|
||||||
|
//{
|
||||||
|
// qNextPollTime = time_now + 100;
|
||||||
|
|
||||||
|
// uint8_t rcode;
|
||||||
|
// const uint8_t constBufSize = 16;
|
||||||
|
// uint8_t buf[constBufSize];
|
||||||
|
|
||||||
|
// 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);
|
||||||
|
|
||||||
|
// if (rcode)
|
||||||
|
// return rcode;
|
||||||
|
|
||||||
|
// for (uint8_t i=0; i<read; i++)
|
||||||
|
// {
|
||||||
|
// PrintHex<uint8_t>(buf[i]);
|
||||||
|
// Serial.print(" ");
|
||||||
|
// }
|
||||||
|
// USBTRACE("\r\n");
|
||||||
|
//}
|
||||||
|
return rcode;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool BulkOnly::IsValidCBW(uint8_t size, uint8_t *pcbw)
|
||||||
|
{
|
||||||
|
if (size != 0x1f || *((uint32_t*)pcbw) != MASS_CBW_SIGNATURE)
|
||||||
|
return false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool BulkOnly::IsMeaningfulCBW(uint8_t size, uint8_t *pcbw)
|
||||||
|
{
|
||||||
|
if (((CommandBlockWrapper*)pcbw)->bmReserved1 != 0 ||
|
||||||
|
((CommandBlockWrapper*)pcbw)->bmReserved2 != 0 ||
|
||||||
|
((CommandBlockWrapper*)pcbw)->bmCBWLUN > bMaxLUN ||
|
||||||
|
((CommandBlockWrapper*)pcbw)->bmCBWCBLength > 0x10 )
|
||||||
|
return false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t BulkOnly::Reset()
|
||||||
|
{
|
||||||
|
return( pUsb->ctrlReq( bAddress, 0, bmREQ_MASSOUT, MASS_REQ_BOMSR, 0, 0, bIface, 0, 0, NULL, NULL ));
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t BulkOnly::GetMaxLUN(uint8_t *plun)
|
||||||
|
{
|
||||||
|
uint8_t cnt = 3;
|
||||||
|
|
||||||
|
bLastUsbError = pUsb->ctrlReq( bAddress, 0, bmREQ_MASSIN, MASS_REQ_GET_MAX_LUN, 0, 0, bIface, 1, 1, plun, NULL );
|
||||||
|
|
||||||
|
delay(10);
|
||||||
|
//Serial.println(F("bLastUsbError: "));
|
||||||
|
//Serial.println(bLastUsbError);
|
||||||
|
|
||||||
|
if (bLastUsbError == hrSTALL)
|
||||||
|
{
|
||||||
|
*plun = 0;
|
||||||
|
bLastUsbError = ClearEpHalt(epDataInIndex);
|
||||||
|
return MASS_ERR_SUCCESS;
|
||||||
|
}
|
||||||
|
if (bLastUsbError == hrJERR)
|
||||||
|
return MASS_ERR_DEVICE_DISCONNECTED;
|
||||||
|
else if (bLastUsbError)
|
||||||
|
return MASS_ERR_GENERAL_USB_ERROR;
|
||||||
|
return MASS_ERR_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t BulkOnly::HandleUsbError(uint8_t index)
|
||||||
|
{
|
||||||
|
uint8_t count = 3;
|
||||||
|
|
||||||
|
while (bLastUsbError && count)
|
||||||
|
{
|
||||||
|
switch (bLastUsbError)
|
||||||
|
{
|
||||||
|
case hrSUCCESS:
|
||||||
|
return MASS_ERR_SUCCESS;
|
||||||
|
case hrJERR:
|
||||||
|
bLastUsbError = hrSUCCESS;
|
||||||
|
return MASS_ERR_DEVICE_DISCONNECTED;
|
||||||
|
case hrSTALL:
|
||||||
|
bLastUsbError = ClearEpHalt(index);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return MASS_ERR_GENERAL_USB_ERROR;
|
||||||
|
}
|
||||||
|
count --;
|
||||||
|
} // while
|
||||||
|
|
||||||
|
return MASS_ERR_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t BulkOnly::ClearEpHalt(uint8_t index)
|
||||||
|
{
|
||||||
|
return (pUsb->ctrlReq( bAddress, 0, USB_SETUP_HOST_TO_DEVICE|USB_SETUP_TYPE_STANDARD|USB_SETUP_RECIPIENT_ENDPOINT,
|
||||||
|
USB_REQUEST_CLEAR_FEATURE, USB_FEATURE_ENDPOINT_HALT, 0, epInfo[index].epAddr, 0, 0, NULL, NULL ));
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t BulkOnly::ResetRecovery()
|
||||||
|
{
|
||||||
|
bLastUsbError = Reset();
|
||||||
|
|
||||||
|
if (bLastUsbError)
|
||||||
|
return bLastUsbError;
|
||||||
|
|
||||||
|
delay(6);
|
||||||
|
|
||||||
|
bLastUsbError = ClearEpHalt(epDataInIndex);
|
||||||
|
|
||||||
|
if (bLastUsbError)
|
||||||
|
return bLastUsbError;
|
||||||
|
|
||||||
|
delay(6);
|
||||||
|
|
||||||
|
bLastUsbError = ClearEpHalt(epDataOutIndex);
|
||||||
|
|
||||||
|
delay(6);
|
||||||
|
|
||||||
|
return bLastUsbError;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t BulkOnly::Inquiry(uint8_t lun, uint16_t bsize, uint8_t *buf)
|
||||||
|
{
|
||||||
|
CommandBlockWrapper cbw;
|
||||||
|
|
||||||
|
cbw.dCBWSignature = MASS_CBW_SIGNATURE;
|
||||||
|
cbw.dCBWTag = 0xdeadbeef;
|
||||||
|
cbw.dCBWDataTransferLength = bsize;
|
||||||
|
cbw.bmCBWFlags = MASS_CMD_DIR_IN,
|
||||||
|
cbw.bmCBWLUN = lun;
|
||||||
|
cbw.bmCBWCBLength = 6;
|
||||||
|
|
||||||
|
for (uint8_t i=0; i<16; i++)
|
||||||
|
cbw.CBWCB[i] = 0;
|
||||||
|
|
||||||
|
cbw.CBWCB[0] = SCSI_CMD_INQUIRY;
|
||||||
|
cbw.CBWCB[4] = bsize;
|
||||||
|
|
||||||
|
return Transaction(&cbw, bsize, buf, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t BulkOnly::RequestSense(uint8_t lun, uint16_t size, uint8_t *buf)
|
||||||
|
{
|
||||||
|
CommandBlockWrapper cbw;
|
||||||
|
|
||||||
|
cbw.dCBWSignature = MASS_CBW_SIGNATURE;
|
||||||
|
cbw.dCBWTag = 0xdeadbeef;
|
||||||
|
cbw.dCBWDataTransferLength = size;
|
||||||
|
cbw.bmCBWFlags = MASS_CMD_DIR_IN,
|
||||||
|
cbw.bmCBWLUN = lun;
|
||||||
|
cbw.bmCBWCBLength = 6;
|
||||||
|
|
||||||
|
for (uint8_t i=0; i<16; i++)
|
||||||
|
cbw.CBWCB[i] = 0;
|
||||||
|
|
||||||
|
cbw.CBWCB[0] = SCSI_CMD_REQUEST_SENSE;
|
||||||
|
cbw.CBWCB[4] = size;
|
||||||
|
|
||||||
|
return Transaction(&cbw, size, buf, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t BulkOnly::ReadCapacity(uint8_t lun, uint16_t bsize, uint8_t *buf)
|
||||||
|
{
|
||||||
|
CommandBlockWrapper cbw;
|
||||||
|
|
||||||
|
cbw.dCBWSignature = MASS_CBW_SIGNATURE;
|
||||||
|
cbw.dCBWTag = 0xdeadbeef;
|
||||||
|
cbw.dCBWDataTransferLength = bsize;
|
||||||
|
cbw.bmCBWFlags = MASS_CMD_DIR_IN,
|
||||||
|
cbw.bmCBWLUN = lun;
|
||||||
|
cbw.bmCBWCBLength = 10;
|
||||||
|
|
||||||
|
for (uint8_t i=0; i<16; i++)
|
||||||
|
cbw.CBWCB[i] = 0;
|
||||||
|
|
||||||
|
cbw.CBWCB[0] = SCSI_CMD_READ_CAPACITY_10;
|
||||||
|
cbw.CBWCB[4] = bsize;
|
||||||
|
|
||||||
|
return Transaction(&cbw, bsize, buf, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t BulkOnly::TestUnitReady(uint8_t lun)
|
||||||
|
{
|
||||||
|
CommandBlockWrapper cbw;
|
||||||
|
|
||||||
|
cbw.dCBWSignature = MASS_CBW_SIGNATURE;
|
||||||
|
cbw.dCBWTag = 0xdeadbeef;
|
||||||
|
cbw.dCBWDataTransferLength = 0;
|
||||||
|
cbw.bmCBWFlags = MASS_CMD_DIR_OUT,
|
||||||
|
cbw.bmCBWLUN = lun;
|
||||||
|
cbw.bmCBWCBLength = 6;
|
||||||
|
|
||||||
|
for (uint8_t i=0; i<16; i++)
|
||||||
|
cbw.CBWCB[i] = 0;
|
||||||
|
|
||||||
|
cbw.CBWCB[0] = SCSI_CMD_TEST_UNIT_READY;
|
||||||
|
|
||||||
|
return Transaction(&cbw, 0, NULL, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t BulkOnly::Read(uint8_t lun, uint32_t addr, uint16_t bsize, USBReadParser *prs)
|
||||||
|
{
|
||||||
|
CommandBlockWrapper cbw;
|
||||||
|
|
||||||
|
cbw.dCBWSignature = MASS_CBW_SIGNATURE;
|
||||||
|
cbw.dCBWTag = 0xdeadbeef;
|
||||||
|
cbw.dCBWDataTransferLength = bsize;
|
||||||
|
cbw.bmCBWFlags = MASS_CMD_DIR_IN,
|
||||||
|
cbw.bmCBWLUN = lun;
|
||||||
|
cbw.bmCBWCBLength = 10;
|
||||||
|
|
||||||
|
for (uint8_t i=0; i<16; i++)
|
||||||
|
cbw.CBWCB[i] = 0;
|
||||||
|
|
||||||
|
cbw.CBWCB[0] = SCSI_CMD_READ_10;
|
||||||
|
cbw.CBWCB[8] = 1;
|
||||||
|
cbw.CBWCB[5] = (addr & 0xff);
|
||||||
|
cbw.CBWCB[4] = ((addr >> 8) & 0xff);
|
||||||
|
cbw.CBWCB[3] = ((addr >> 16) & 0xff);
|
||||||
|
cbw.CBWCB[2] = ((addr >> 24) & 0xff);
|
||||||
|
|
||||||
|
return Transaction(&cbw, bsize, prs, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t BulkOnly::Transaction(CommandBlockWrapper *cbw, uint16_t size, void *buf, uint8_t flags)
|
||||||
|
{
|
||||||
|
uint16_t read;
|
||||||
|
{
|
||||||
|
bLastUsbError = pUsb->outTransfer(bAddress, epInfo[epDataOutIndex].epAddr, sizeof(CommandBlockWrapper), (uint8_t*)cbw);
|
||||||
|
|
||||||
|
uint8_t ret = HandleUsbError(epDataOutIndex);
|
||||||
|
|
||||||
|
if (ret)
|
||||||
|
{
|
||||||
|
ErrorMessage<uint8_t>(PSTR("CBW"), ret);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (size && buf)
|
||||||
|
{
|
||||||
|
read = size;
|
||||||
|
|
||||||
|
if (cbw->bmCBWFlags & MASS_CMD_DIR_IN)
|
||||||
|
{
|
||||||
|
if ((flags & MASS_TRANS_FLG_CALLBACK) == MASS_TRANS_FLG_CALLBACK)
|
||||||
|
{
|
||||||
|
const uint8_t bufSize = 64;
|
||||||
|
uint16_t total = size;
|
||||||
|
uint16_t count = 0;
|
||||||
|
uint8_t rbuf[bufSize];
|
||||||
|
|
||||||
|
read = bufSize;
|
||||||
|
|
||||||
|
while(count < total &&
|
||||||
|
((bLastUsbError = pUsb->inTransfer(bAddress, epInfo[epDataInIndex].epAddr, &read, (uint8_t*)rbuf)) == hrSUCCESS)
|
||||||
|
)
|
||||||
|
{
|
||||||
|
((USBReadParser*)buf)->Parse(read, rbuf, count);
|
||||||
|
|
||||||
|
count += read;
|
||||||
|
read = bufSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (bLastUsbError == hrSTALL)
|
||||||
|
bLastUsbError = ClearEpHalt(epDataInIndex);
|
||||||
|
|
||||||
|
if (bLastUsbError)
|
||||||
|
{
|
||||||
|
ErrorMessage<uint8_t>(PSTR("RDR"), bLastUsbError);
|
||||||
|
return MASS_ERR_GENERAL_USB_ERROR;
|
||||||
|
}
|
||||||
|
} // if ((flags & 1) == 1)
|
||||||
|
else
|
||||||
|
bLastUsbError = pUsb->inTransfer(bAddress, epInfo[epDataInIndex].epAddr, &read, (uint8_t*)buf);
|
||||||
|
} // if (cbw->bmCBWFlags & MASS_CMD_DIR_IN)
|
||||||
|
|
||||||
|
else if (cbw->bmCBWFlags & MASS_CMD_DIR_OUT)
|
||||||
|
bLastUsbError = pUsb->outTransfer(bAddress, epInfo[epDataOutIndex].epAddr, read, (uint8_t*)buf);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t ret = HandleUsbError((cbw->bmCBWFlags & MASS_CMD_DIR_IN) ? epDataInIndex : epDataOutIndex);
|
||||||
|
|
||||||
|
if (ret)
|
||||||
|
{
|
||||||
|
ErrorMessage<uint8_t>(PSTR("RSP"), ret);
|
||||||
|
return MASS_ERR_GENERAL_USB_ERROR;
|
||||||
|
}
|
||||||
|
{
|
||||||
|
CommandStatusWrapper csw;
|
||||||
|
read = sizeof(CommandStatusWrapper);
|
||||||
|
|
||||||
|
bLastUsbError = pUsb->inTransfer(bAddress, epInfo[epDataInIndex].epAddr, &read, (uint8_t*)&csw);
|
||||||
|
|
||||||
|
uint8_t ret = HandleUsbError(epDataInIndex);
|
||||||
|
|
||||||
|
if (ret)
|
||||||
|
{
|
||||||
|
ErrorMessage<uint8_t>(PSTR("CSW"), ret);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
//if (csw.bCSWStatus == MASS_ERR_PHASE_ERROR)
|
||||||
|
// bLastUsbError = ResetRecovery();
|
||||||
|
|
||||||
|
return csw.bCSWStatus;
|
||||||
|
}
|
||||||
|
//return MASS_ERR_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
void BulkOnly::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"));
|
||||||
|
}
|
252
masstorage.h
Normal file
252
masstorage.h
Normal file
|
@ -0,0 +1,252 @@
|
||||||
|
#if !defined(__MASSTORAGE_H__)
|
||||||
|
#define __MASSTORAGE_H__
|
||||||
|
|
||||||
|
#include <inttypes.h>
|
||||||
|
#include <avr/pgmspace.h>
|
||||||
|
#include "avrpins.h"
|
||||||
|
#include "max3421e.h"
|
||||||
|
#include "usbhost.h"
|
||||||
|
#include "usb_ch9.h"
|
||||||
|
#include "Usb.h"
|
||||||
|
|
||||||
|
#if defined(ARDUINO) && ARDUINO >=100
|
||||||
|
#include "Arduino.h"
|
||||||
|
#else
|
||||||
|
#include <WProgram.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "printhex.h"
|
||||||
|
#include "hexdump.h"
|
||||||
|
#include "message.h"
|
||||||
|
|
||||||
|
#include "confdescparser.h"
|
||||||
|
|
||||||
|
#define SWAP(a, b) (((a) ^= (b)), ((b) ^= (a)), ((a) ^= (b)))
|
||||||
|
|
||||||
|
#define bmREQ_MASSOUT USB_SETUP_HOST_TO_DEVICE|USB_SETUP_TYPE_CLASS|USB_SETUP_RECIPIENT_INTERFACE
|
||||||
|
#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
|
||||||
|
|
||||||
|
// 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
|
||||||
|
|
||||||
|
// 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_CBW_SIGNATURE 0x43425355
|
||||||
|
#define MASS_CSW_SIGNATURE 0x53425355
|
||||||
|
|
||||||
|
#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 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 MASS_TRANS_FLG_CALLBACK 0x01 // Callback is involved
|
||||||
|
#define MASS_TRANS_FLG_NO_STALL_CHECK 0x02 // STALL condition is not checked
|
||||||
|
#define MASS_TRANS_FLG_NO_PHASE_CHECK 0x04 // PHASE_ERROR is not checked
|
||||||
|
|
||||||
|
|
||||||
|
struct Capacity
|
||||||
|
{
|
||||||
|
uint8_t data[8];
|
||||||
|
//uint32_t dwBlockAddress;
|
||||||
|
//uint32_t dwBlockLength;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct InquiryResponse
|
||||||
|
{
|
||||||
|
uint8_t DeviceType : 5;
|
||||||
|
uint8_t PeripheralQualifier : 3;
|
||||||
|
|
||||||
|
unsigned Reserved : 7;
|
||||||
|
unsigned Removable : 1;
|
||||||
|
|
||||||
|
uint8_t Version;
|
||||||
|
|
||||||
|
unsigned ResponseDataFormat : 4;
|
||||||
|
unsigned Reserved2 : 1;
|
||||||
|
unsigned NormACA : 1;
|
||||||
|
unsigned TrmTsk : 1;
|
||||||
|
unsigned AERC : 1;
|
||||||
|
|
||||||
|
uint8_t AdditionalLength;
|
||||||
|
uint8_t Reserved3[2];
|
||||||
|
|
||||||
|
unsigned SoftReset : 1;
|
||||||
|
unsigned CmdQue : 1;
|
||||||
|
unsigned Reserved4 : 1;
|
||||||
|
unsigned Linked : 1;
|
||||||
|
unsigned Sync : 1;
|
||||||
|
unsigned WideBus16Bit : 1;
|
||||||
|
unsigned WideBus32Bit : 1;
|
||||||
|
unsigned RelAddr : 1;
|
||||||
|
|
||||||
|
uint8_t VendorID[8];
|
||||||
|
uint8_t ProductID[16];
|
||||||
|
uint8_t RevisionID[4];
|
||||||
|
};
|
||||||
|
|
||||||
|
struct CommandBlockWrapper
|
||||||
|
{
|
||||||
|
uint32_t dCBWSignature;
|
||||||
|
uint32_t dCBWTag;
|
||||||
|
uint32_t dCBWDataTransferLength;
|
||||||
|
uint8_t bmCBWFlags;
|
||||||
|
|
||||||
|
struct
|
||||||
|
{
|
||||||
|
uint8_t bmCBWLUN : 4;
|
||||||
|
uint8_t bmReserved1 : 4;
|
||||||
|
};
|
||||||
|
struct
|
||||||
|
{
|
||||||
|
uint8_t bmCBWCBLength : 4;
|
||||||
|
uint8_t bmReserved2 : 4;
|
||||||
|
};
|
||||||
|
|
||||||
|
uint8_t CBWCB[16];
|
||||||
|
} ;
|
||||||
|
|
||||||
|
struct CommandStatusWrapper
|
||||||
|
{
|
||||||
|
uint32_t dCSWSignature;
|
||||||
|
uint32_t dCSWTag;
|
||||||
|
uint32_t dCSWDataResidue;
|
||||||
|
uint8_t bCSWStatus;
|
||||||
|
};
|
||||||
|
|
||||||
|
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];
|
||||||
|
};
|
||||||
|
|
||||||
|
//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;
|
||||||
|
//};
|
||||||
|
|
||||||
|
#define MASS_MAX_ENDPOINTS 3
|
||||||
|
|
||||||
|
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
|
||||||
|
|
||||||
|
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];
|
||||||
|
|
||||||
|
uint32_t dCBWTag; // Tag
|
||||||
|
uint32_t dCBWDataTransferLength; // Data Transfer Length
|
||||||
|
uint8_t bMaxLUN; // Max LUN
|
||||||
|
uint8_t bLastUsbError; // Last USB error
|
||||||
|
|
||||||
|
protected:
|
||||||
|
//union TransFlags
|
||||||
|
//{
|
||||||
|
// uint8_t nValue;
|
||||||
|
|
||||||
|
// struct {
|
||||||
|
// uint8_t bmCallback : 1;
|
||||||
|
// uint8_t bmCheckPhaseErr : 1;
|
||||||
|
// uint8_t bmDummy : 6;
|
||||||
|
// };
|
||||||
|
//};
|
||||||
|
void PrintEndpointDescriptor(const USB_ENDPOINT_DESCRIPTOR* ep_ptr);
|
||||||
|
|
||||||
|
bool IsValidCBW(uint8_t size, uint8_t *pcbw);
|
||||||
|
bool IsMeaningfulCBW(uint8_t size, uint8_t *pcbw);
|
||||||
|
|
||||||
|
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);
|
||||||
|
|
||||||
|
public:
|
||||||
|
BulkOnly(USB *p);
|
||||||
|
uint8_t GetLastUsbError() { return bLastUsbError; };
|
||||||
|
|
||||||
|
uint8_t Reset();
|
||||||
|
uint8_t GetMaxLUN(uint8_t *max_lun);
|
||||||
|
|
||||||
|
uint8_t ResetRecovery();
|
||||||
|
uint8_t Inquiry(uint8_t lun, uint16_t size, uint8_t *buf);
|
||||||
|
uint8_t TestUnitReady(uint8_t lun);
|
||||||
|
uint8_t ReadCapacity(uint8_t lun, uint16_t size, uint8_t *buf);
|
||||||
|
uint8_t RequestSense(uint8_t lun, uint16_t size, uint8_t *buf);
|
||||||
|
//uint8_t Read(uint8_t lun, uint32_t addr, uint16_t bsize, uint8_t *buf);
|
||||||
|
uint8_t Read(uint8_t lun, uint32_t addr, uint16_t bsize, USBReadParser *prs);
|
||||||
|
|
||||||
|
// 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);
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // __MASSTORAGE_H__
|
Loading…
Reference in a new issue