Issue with writing USB Mass Storage "PluggableUSB.h" Module

Hi, I have a Micro with the AtMega32U4 chip on it which does USB. I'm trying to make a simple USB Mass Storage. It can return nothing but random data at this stage - I'm just trying to get the device to be detected by my Mac/PC/etc.

I've read lots about LUAF and found lots of examples on the web but I'm trying to write it as a library for the Arduino. The HID, and MIDI examples are useful but have only got me so far. This wiki page is useful too but it doesn't cover the detail needed for a USB noob like myself.

From my research so far my understanding is I have a device class descriptor (provided by PluggableUSB), an interface descriptor (provided by subclass), 2 endpoint descriptors for bulk in and bulk out (provided in interface descriptor). There is also a Control Endpoint by default provided by PluggableUSB for responding to commands (I assume this is where I listen out for the SCSI commands?)

Here is my code so far

// MassStorage.h

#ifndef MSTORAGE_h
#define MSTORAGE_h

#include <stdint.h>
#include <Arduino.h>
#include "PluggableUSB.h"

#if !defined(USBCON)
#error MassStorage can only be used with an USB MCU.
#endif

#define USB_MASS_STORAGE_SUBCLASS 0x06
#define USB_MASS_STORAGE_PROTOCOL 0x50

typedef struct 
{
  InterfaceDescriptor id;
  EndpointDescriptor  in;
  EndpointDescriptor  out;
} MSDDescriptor;

class MassStorage_ : public PluggableUSBModule
{
private:
  uint8_t epType[2];

public:
  MassStorage_(void);
  void start(void);

protected:
  // Implementation of the PluggableUSBModule
  int getInterface(uint8_t* interfaceCount);
  int getDescriptor(USBSetup& setup);
  bool setup(USBSetup& setup);
  uint8_t getShortName(char* name);
};
extern MassStorage_ MassStorage;

#endif
// MassStorage.cpp
#include "MassStorage.h"

#define BULK_ENDPOINT_OUT	pluggedEndpoint
#define BULK_ENDPOINT_IN	((uint8_t)(pluggedEndpoint+1))

MassStorage_ MassStorage;

int MassStorage_::getInterface(uint8_t* interfaceCount)
{
	*interfaceCount += 1; // uses 1
	MSDDescriptor msdInterface = {
		D_INTERFACE(pluggedInterface, 2, USB_DEVICE_CLASS_STORAGE, USB_MASS_STORAGE_SUBCLASS, USB_MASS_STORAGE_PROTOCOL),
		D_ENDPOINT(USB_ENDPOINT_IN(BULK_ENDPOINT_IN), USB_ENDPOINT_TYPE_BULK, USB_EP_SIZE, 0x00),
		D_ENDPOINT(USB_ENDPOINT_OUT(BULK_ENDPOINT_OUT), USB_ENDPOINT_TYPE_BULK, USB_EP_SIZE, 0x00)
	};
	return USB_SendControl(0, &msdInterface, sizeof(msdInterface));
}

int MassStorage_::getDescriptor(USBSetup& setup)
{
 	return 0;
}

uint8_t MassStorage_::getShortName(char *name)
{
	name[0] = 'M';
	name[1] = 'S';
	name[2] = 'D';
	return 3;
}

bool MassStorage_::setup(USBSetup& setup)
{
	uint8_t request = setup.bRequest;
	uint8_t requestType = setup.bmRequestType;

	if (requestType == REQUEST_DEVICETOHOST_CLASS_INTERFACE) {
		if (request == 0xFF) { // Storage reset
			return true;
		} else if (request == 0xFE) { // Return Max Lun
			uint8_t maxLun = 1;
			USB_SendControl(0, &maxLun, sizeof(maxLun));
			return true;
		} 
	}

	return false;
}


void MassStorage_::start(void)
{

}

MassStorage_::MassStorage_(void) : PluggableUSBModule(2, 2, epType)
{
	epType[0] = EP_TYPE_BULK_IN;	// ENDPOINT_IN
	epType[1] = EP_TYPE_BULK_OUT;	// ENDPOINT_OUT

	PluggableUSB().plug(this);
}
// Arduino Sketch
#include "MassStorage.h"

void setup() {
  MassStorage.start();
}

void loop() {
}

How my understanding of how it works is that the PluggableUSB class takes care of most stuff (device descriptor etc) and you just need to override key methods such as getInterface().

Now I believe the interface descriptor is being sent correctly and it tries to reset the USB Device because I see this in my Console logs for the laptop

default	11:23:46.587681 +0000	kernel	USB device 2341803714100002 - fConsecutiveResetCount = 1.
default	11:23:46.988379 +0000	kernel	USB device 2341803714100002 - will be reset!
default	11:23:47.227445 +0000	kernel	USBMSC Identifier (non-unique): 0x2341 0x8037 0x100
default	11:23:47.248156 +0000	kernel	USB device 2341803714100002 - fConsecutiveResetCount = 2.
default	11:23:48.549563 +0000	kernel	USB device 2341803714100002 - will be reset!
default	11:23:48.786988 +0000	kernel	USBMSC Identifier (non-unique): 0x2341 0x8037 0x100
default	11:23:48.804627 +0000	kernel	USB device 2341803714100002 - fConsecutiveResetCount = 3.
default	11:23:50.106117 +0000	kernel	USB device 2341803714100002 - will be reset!
default	11:23:50.341132 +0000	kernel	USBMSC Identifier (non-unique): 0x2341 0x8037 0x100
default	11:23:51.919567 +0000	kernel	USB device 2341803714100002 - fConsecutiveResetCount = 5.
default	11:23:52.920026 +0000	kernel	USB device 2341803714100002 - 

...

fConsecutiveResetCount > kIOUSBMassStorageMaxConsecutiveResets ( 5 ).
default	11:23:52.920059 +0000	kernel	USB device 2341803714100002 - fIOUSBMassStorageDriverNub->terminate().
default	11:23:52.920432 +0000	kernel	USB device 2341803714100002 - fConsecutiveResetCount = 6.
default	11:23:52.920735 +0000	kernel	IOUSBMassStorageInterfaceNub: bad busy count (0,-1)

Backtrace 0xffffff8000a255a4 0xffffff7f83029e04 0xffffff8000a5582e 0xffffff8000a28839 0xffffff8000a33227 0xffffff800035b0ce 0x0

It does seem something to do with MassStorage is being detected! I believe I'm meant to intercept the "Reset" Config packet and return an acknowledgment packet, which I do by returning true in bool MassStorage_::setup(USBSetup& setup) (assuming this is how you ack from the examples).

I'm also meant to handle the SCSI commands but I don't understand how or where I listen out for them and how I return data to them?

If anyone has any guidance or more experience to point me in the right direction I'd be very grateful. I'm quite out of my comfort zone and I feel that it's something that if the right person just saw it they'd be able to tell me what I'm doing wrong in 5 minutes vs the hours and hours I've spend trying to get this far!