Skip to content

Commit 7842191

Browse files
committed
Implement usb drive volume
1 parent 9476941 commit 7842191

File tree

8 files changed

+356
-5
lines changed

8 files changed

+356
-5
lines changed

src/Config/Pins.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -213,6 +213,10 @@
213213
# define HAS_SBC_INTERFACE 0
214214
#endif
215215

216+
#ifndef SUPPORT_USB_DRIVE
217+
# define SUPPORT_USB_DRIVE 0
218+
#endif
219+
216220
#ifndef HAS_MASS_STORAGE
217221
# define HAS_MASS_STORAGE 1
218222
#endif

src/Config/Pins_Duet3_MB6HC.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,10 +28,12 @@ constexpr uint32_t IAP_IMAGE_START = 0x20458000; // last 32kb of RAM
2828
# define HAS_SBC_INTERFACE 0
2929
# define HAS_MASS_STORAGE 0
3030
# define HAS_HIGH_SPEED_SD 0
31+
# define SUPPORT_USB_DRIVE 0
3132
#else
3233
# define HAS_SBC_INTERFACE 1
3334
# define HAS_MASS_STORAGE 1
3435
# define HAS_HIGH_SPEED_SD 1
36+
# define SUPPORT_USB_DRIVE 1
3537
#endif
3638

3739
#define HAS_CPU_TEMP_SENSOR 1
@@ -198,6 +200,11 @@ constexpr Pin SdSpiCSPins[1] = { PortDPin(22) }; // this one is allocated
198200
constexpr uint32_t ExpectedSdCardSpeed = 25000000;
199201
constexpr IRQn SdhcIRQn = HSMCI_IRQn;
200202

203+
#if SUPPORT_USB_DRIVE
204+
// USB Drives
205+
constexpr size_t NumUsbDrives = 2;
206+
#endif
207+
201208
// DotStar LED control
202209
#define LEDSTRIP_USES_USART 0
203210

src/Hardware/SAME70/same70q20b_flash.ld

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -52,8 +52,8 @@ SEARCH_DIR(.)
5252
MEMORY
5353
{
5454
rom (rx) : ORIGIN = 0x00400000, LENGTH = 0x00100000
55-
ram_not_cached (rw) : ORIGIN = 0x20400000, LENGTH = 0x00018400 /* we currently allocate 97kb of non-cached RAM */
56-
ram (rwx) : ORIGIN = 0x20418400, LENGTH = 0x00047C00 /* that leaves 287Kb of cached RAM */
55+
ram_not_cached (rw) : ORIGIN = 0x20400000, LENGTH = 0x00018800 /* we currently allocate 97kb of non-cached RAM */
56+
ram (rwx) : ORIGIN = 0x20418800, LENGTH = 0x00047800 /* that leaves 287Kb of cached RAM */
5757
}
5858

5959
/* Section Definitions */

src/Libraries/Fatfs/ffconf.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -166,7 +166,7 @@
166166
/ Drive/Volume Configurations
167167
/---------------------------------------------------------------------------*/
168168

169-
#define FF_VOLUMES 2
169+
#define FF_VOLUMES 4
170170
/* Number of volumes (logical drives) to be used. (1-10) */
171171

172172

src/Storage/MassStorage.cpp

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,13 @@ static_assert(FF_MAX_LFN >= MaxFilenameLength, "FF_MAX_LFN too small");
2323

2424
#include "SdCardVolume.h"
2525

26+
#if SUPPORT_USB_DRIVE
27+
#include "UsbVolume.h"
28+
static_assert(FF_VOLUMES >= NumSdCards + NumUsbDrives);
29+
#else
2630
static_assert(FF_VOLUMES >= NumSdCards);
31+
#endif
32+
2733
// A note on using mutexes:
2834
// Each storage volume has its own mutex. There is also one for the file table, and one for the find first/find next buffer.
2935
// The FatFS subsystem locks and releases the appropriate volume mutex when it is called.
@@ -41,7 +47,16 @@ alignas(4) static __nocache char writeBufferStorage[NumFileWriteBuffers][FileWri
4147
# endif
4248

4349
static SdCardVolume sdVolumes[NumSdCards] = { SdCardVolume("SDO", 0), SdCardVolume("SD1", 1) };
44-
static StorageVolume* storageVolumes[] = { &sdVolumes[0], &sdVolumes[1] };
50+
#if SUPPORT_USB_DRIVE
51+
static UsbVolume usbVolumes[NumUsbDrives] = { UsbVolume("USB0", 2), UsbVolume("USB1", 3) };
52+
#endif
53+
54+
static StorageVolume* storageVolumes[] = { &sdVolumes[0], &sdVolumes[1],
55+
#if SUPPORT_USB_DRIVE
56+
&usbVolumes[0], &usbVolumes[1]
57+
#endif
58+
};
59+
4560
static DIR findDir;
4661
#endif
4762

@@ -1019,7 +1034,7 @@ void MassStorage::RecordSimulationTime(const char *printingFilePath, uint32_t si
10191034
// Get information about the volume and interface speed on the specified slot
10201035
MassStorage::InfoResult MassStorage::GetVolumeInfo(size_t slot, SdCardReturnedInfo& returnedInfo) noexcept
10211036
{
1022-
if (slot >= GetNumVolumes() && storageVolumes[slot]->IsUseable())
1037+
if (slot >= GetNumVolumes() || !(storageVolumes[slot]->IsUseable()))
10231038
{
10241039
return InfoResult::badSlot;
10251040
}

src/Storage/MassStorage.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,8 +63,11 @@ namespace MassStorage
6363
return 1;
6464
#else
6565
return NumSdCards
66+
#if SUPPORT_USB_DRIVE
67+
+ NumUsbDrives
6668
#endif
6769
;
70+
#endif
6871
}
6972
#endif
7073

src/Storage/UsbVolume.cpp

Lines changed: 251 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,251 @@
1+
2+
#include <cstdint>
3+
4+
#include <Platform/Platform.h>
5+
#include <Platform/RepRap.h>
6+
7+
#include <TinyUsbInterface.h>
8+
9+
#if SUPPORT_USB_DRIVE
10+
11+
static_assert(CORE_USES_TINYUSB && CFG_TUH_ENABLED, "USB drive support needs tinyUSB host stack"); // implementation only on tinyUSB with host support
12+
#if CORE_USES_TINYUSB && CFG_TUH_ENABLED
13+
14+
#include <tusb.h>
15+
#include <class/msc/msc_host.h>
16+
17+
#include "UsbVolume.h"
18+
19+
static bool disk_io_complete(uint8_t address, tuh_msc_complete_data_t const *cb_data)
20+
{
21+
(void) address;
22+
BinarySemaphore *ioDone = reinterpret_cast<BinarySemaphore*>(cb_data->user_arg);
23+
ioDone->Give();
24+
return true;
25+
}
26+
27+
void UsbVolume::Init() noexcept
28+
{
29+
StorageVolume::Init();
30+
address = 0;
31+
32+
for (size_t i = 0; i < NumUsbDrives; i++)
33+
{
34+
if (usbDrives[i] == nullptr)
35+
{
36+
usbDrives[i] = this;
37+
break;
38+
}
39+
}
40+
}
41+
42+
void UsbVolume::Spin() noexcept
43+
{
44+
if (state == State::removed)
45+
{
46+
InternalUnmount();
47+
address = 0;
48+
state = State::free;
49+
}
50+
}
51+
52+
bool UsbVolume::IsUseable(const StringRef& reply) const noexcept
53+
{
54+
if (!CoreUsbIsHostMode())
55+
{
56+
if (&reply != &StorageVolume::noReply)
57+
{
58+
reply.copy("USB not configured as host");
59+
}
60+
return false;
61+
}
62+
return true;
63+
}
64+
65+
GCodeResult UsbVolume::Mount(const StringRef &reply, bool reportSuccess) noexcept
66+
{
67+
if (!IsDetected())
68+
{
69+
reply.copy("No USB storage detected");
70+
return GCodeResult::error;
71+
}
72+
73+
if (IsMounted())
74+
{
75+
if (MassStorage::AnyFileOpen(&fileSystem))
76+
{
77+
// Don't re-mount the card if any files are open on it
78+
reply.printf("%s has open file(s)", id);
79+
return GCodeResult::error;
80+
}
81+
(void)InternalUnmount();
82+
}
83+
84+
// Mount the file systems
85+
const FRESULT res = f_mount(&fileSystem, path, 1);
86+
if (res == FR_NO_FILESYSTEM)
87+
{
88+
reply.printf("Cannot mount %s: no FAT filesystem found on card (EXFAT is not supported)", id);
89+
return GCodeResult::error;
90+
}
91+
if (res != FR_OK)
92+
{
93+
reply.printf("Cannot mount %s: code %d", id, res);
94+
return GCodeResult::error;
95+
}
96+
state = State::mounted;
97+
98+
reprap.VolumesUpdated();
99+
if (reportSuccess)
100+
{
101+
float capacity = GetCapacity() / 1000000.0f; // get capacity and convert from Kib to Mbytes
102+
const char* capUnits = capacity >= 1000.0 ? "Gb" : "Mb";
103+
reply.printf("%s mounted, capacity %.2f%s", id, static_cast<double>(capacity >= 1000.0 ? capacity / 1000 : capacity), capUnits);
104+
}
105+
IncrementSeqNum();
106+
107+
return GCodeResult::ok;
108+
}
109+
110+
uint64_t UsbVolume::GetCapacity() const noexcept
111+
{
112+
// Get capacity of device
113+
uint64_t const block_count = tuh_msc_get_block_count(address, lun);
114+
uint64_t const block_size = tuh_msc_get_block_size(address, lun);
115+
return block_count * block_size;
116+
}
117+
118+
uint32_t UsbVolume::GetInterfaceSpeed() const noexcept
119+
{
120+
tusb_speed_t speed = tuh_speed_get(address);
121+
return (speed == TUSB_SPEED_HIGH ? 480000000 : 12000000) / 8;
122+
}
123+
124+
DRESULT UsbVolume::DiskInitialize() noexcept
125+
{
126+
return RES_OK; // nothing to do
127+
}
128+
129+
DRESULT UsbVolume::DiskStatus() noexcept
130+
{
131+
return static_cast<DRESULT>(tuh_msc_mounted(address) ? 0 : STA_NODISK);
132+
}
133+
134+
DRESULT UsbVolume::DiskRead(BYTE *buff, LBA_t sector, UINT count) noexcept
135+
{
136+
tuh_msc_read10(address, lun, buff, sector, (uint16_t)count, disk_io_complete, reinterpret_cast<uintptr_t>(&ioDone));
137+
ioDone.Take();
138+
return RES_OK;
139+
}
140+
141+
DRESULT UsbVolume::DiskWrite(BYTE const *buff, LBA_t sector, UINT count) noexcept
142+
{
143+
tuh_msc_write10(address, lun, buff, sector, (uint16_t)count, disk_io_complete, reinterpret_cast<uintptr_t>(&ioDone));
144+
ioDone.Take();
145+
return RES_OK;
146+
}
147+
148+
DRESULT UsbVolume::DiskIoctl(BYTE cmd, void *buff) noexcept
149+
{
150+
switch (cmd)
151+
{
152+
case CTRL_SYNC:
153+
// nothing to do since we do blocking
154+
return RES_OK;
155+
156+
case GET_SECTOR_COUNT:
157+
*((DWORD *)buff) = (WORD)tuh_msc_get_block_count(address, lun);
158+
return RES_OK;
159+
160+
case GET_SECTOR_SIZE:
161+
*((WORD *)buff) = (WORD)tuh_msc_get_block_size(address, lun);
162+
return RES_OK;
163+
164+
case GET_BLOCK_SIZE:
165+
*((DWORD *)buff) = 1; // erase block size in units of sector size
166+
return RES_OK;
167+
168+
default:
169+
return RES_PARERR;
170+
}
171+
172+
return RES_OK;
173+
}
174+
175+
void UsbVolume::DeviceUnmount() noexcept
176+
{
177+
switch (state)
178+
{
179+
case State::removed:
180+
state = State::free;
181+
break;
182+
case State::mounted:
183+
state = State::inserted;
184+
default:
185+
break;
186+
}
187+
}
188+
189+
bool UsbVolume::Accept(uint8_t address)
190+
{
191+
if (state == State::free)
192+
{
193+
state = State::inserted;
194+
this->address = address;
195+
return true;
196+
}
197+
return false;
198+
}
199+
200+
void UsbVolume::Free()
201+
{
202+
switch (state)
203+
{
204+
case State::inserted:
205+
state = State::free; // immediately set free
206+
address = 0;
207+
break;
208+
case State::mounted:
209+
state = State::removed; // perform actual freeing in spin function
210+
default:
211+
break;
212+
}
213+
}
214+
215+
/*static*/ void UsbVolume::VolumeInserted(uint8_t address)
216+
{
217+
for (UsbVolume *drive : usbDrives)
218+
{
219+
// Check if there are free ones that can accept
220+
if (drive->Accept(address))
221+
{
222+
break;
223+
}
224+
}
225+
}
226+
227+
/*static*/ void UsbVolume::VolumeRemoved(uint8_t address)
228+
{
229+
for (UsbVolume *drive : usbDrives)
230+
{
231+
if (drive->address == address)
232+
{
233+
drive->Free();
234+
}
235+
}
236+
}
237+
238+
extern "C" void tuh_msc_mount_cb(uint8_t address)
239+
{
240+
UsbVolume::VolumeInserted(address);
241+
}
242+
243+
extern "C" void tuh_msc_umount_cb(uint8_t address)
244+
{
245+
UsbVolume::VolumeRemoved(address);
246+
}
247+
248+
/*static*/ UsbVolume *UsbVolume::usbDrives[NumUsbDrives];
249+
250+
#endif // CORE_USES_TINYUSB && CFG_TUH_ENABLED
251+
#endif // SUPPORT_USB_DRIVE

0 commit comments

Comments
 (0)