fixing conflict

This commit is contained in:
Oleg Mazurov 2012-07-26 16:59:41 -06:00
commit 1c5553e7bf
6 changed files with 2807 additions and 152 deletions

1539
RFCOMM.cpp Normal file

File diff suppressed because it is too large Load diff

332
RFCOMM.h Normal file
View 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

View 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);
}

View file

@ -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
View 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
View 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__