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
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