Skip to content

Commit dec52c3

Browse files
committed
Add ported USBMSD library
1 parent 24ee5a9 commit dec52c3

File tree

3 files changed

+1266
-0
lines changed

3 files changed

+1266
-0
lines changed

libraries/USBMSD/PluggableUSBMSD.h

+316
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,316 @@
1+
/*
2+
* Copyright (c) 2018-2019, Arm Limited and affiliates.
3+
* SPDX-License-Identifier: Apache-2.0
4+
*
5+
* Licensed under the Apache License, Version 2.0 (the "License");
6+
* you may not use this file except in compliance with the License.
7+
* You may obtain a copy of the License at
8+
*
9+
* http://www.apache.org/licenses/LICENSE-2.0
10+
*
11+
* Unless required by applicable law or agreed to in writing, software
12+
* distributed under the License is distributed on an "AS IS" BASIS,
13+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
* See the License for the specific language governing permissions and
15+
* limitations under the License.
16+
*/
17+
18+
#ifndef USBMSD_H
19+
#define USBMSD_H
20+
21+
/* These headers are included for child class. */
22+
#include "USBDescriptor.h"
23+
#include "USBDevice_Types.h"
24+
#include "platform/Callback.h"
25+
#include "events/PolledQueue.h"
26+
#include "events/Task.h"
27+
#include "BlockDevice.h"
28+
#include "Mutex.h"
29+
30+
#include "USBDevice.h"
31+
#include "USB/PluggableUSBDevice.h"
32+
33+
namespace arduino {
34+
35+
/**
36+
* USBMSD class: generic class in order to use all kinds of blocks storage chip
37+
*
38+
* Introduction
39+
*
40+
* USBMSD implements the MSD protocol. It permits to access a block device (flash, sdcard,...)
41+
* from a computer over USB.
42+
*
43+
* @code
44+
* #include "mbed.h"
45+
* #include "SDBlockDevice.h"
46+
* #include "USBMSD.h"
47+
*
48+
* SDBlockDevice sd(PTE3, PTE1, PTE2, PTE4);
49+
* USBMSD usb(&sd);
50+
*
51+
* int main() {
52+
*
53+
* while(true) {
54+
* usb.process();
55+
* }
56+
*
57+
* return 0;
58+
* }
59+
* @endcode
60+
*/
61+
class USBMSD: public internal::PluggableUSBModule {
62+
public:
63+
64+
/**
65+
* Constructor
66+
*
67+
* This creates a new USBMSD object with the given block device. Connect must be called
68+
* for the block device to connect.
69+
*
70+
* @param bd BlockDevice to mount as a USB drive
71+
* @param connect_blocking true to perform a blocking connect, false to start in a disconnected state
72+
* @param vendor_id Your vendor_id
73+
* @param product_id Your product_id
74+
* @param product_release Your preoduct_release
75+
*/
76+
USBMSD(mbed::BlockDevice *bd, bool connect_blocking = true, uint16_t vendor_id = 0x0703, uint16_t product_id = 0x0104, uint16_t product_release = 0x0001);
77+
78+
/**
79+
* Fully featured constructor
80+
*
81+
* Construct this object with the supplied USBPhy and parameters. The user
82+
* this object is responsible for calling connect() or init().
83+
*
84+
* @note Derived classes must use this constructor and call init() or
85+
* connect() themselves. Derived classes should also call deinit() in
86+
* their destructor. This ensures that no interrupts can occur when the
87+
* object is partially constructed or destroyed.
88+
*
89+
* @param phy USB phy to use
90+
* @param bd BlockDevice to mount as a USB drive
91+
* @param vendor_id Your vendor_id
92+
* @param product_id Your product_id
93+
* @param product_release Your preoduct_release
94+
*/
95+
USBMSD(USBPhy *phy, mbed::BlockDevice *bd, uint16_t vendor_id, uint16_t product_id, uint16_t product_release);
96+
97+
/**
98+
* Destroy this object
99+
*
100+
* Any classes which inherit from this class must call disconnect
101+
* before this destructor runs.
102+
*/
103+
virtual ~USBMSD();
104+
105+
/**
106+
* Connect the USB MSD device.
107+
*
108+
* @returns true if successful
109+
*/
110+
bool connect();
111+
112+
/**
113+
* Disconnect the USB MSD device.
114+
*/
115+
void disconnect();
116+
117+
118+
void begin();
119+
/**
120+
* Perform USB processing
121+
*/
122+
void process();
123+
124+
/**
125+
* Called when USBMSD needs to perform processing
126+
*
127+
* @param cb Callback called when USBMSD needs process() to be called
128+
*/
129+
void attach(mbed::Callback<void()> cb);
130+
131+
/**
132+
* Check if MSD device was removed/unmounted on the host side.
133+
*
134+
* @returns true if device was removed/unmounted on the host side
135+
*/
136+
bool media_removed();
137+
138+
protected:
139+
140+
/*
141+
* read one or more blocks on a storage chip
142+
*
143+
* @param data pointer where will be stored read data
144+
* @param block starting block number
145+
* @param count number of blocks to read
146+
* @returns 0 if successful
147+
*/
148+
virtual int disk_read(uint8_t *data, uint64_t block, uint8_t count);
149+
150+
/*
151+
* write one or more blocks on a storage chip
152+
*
153+
* @param data data to write
154+
* @param block starting block number
155+
* @param count number of blocks to write
156+
* @returns 0 if successful
157+
*/
158+
virtual int disk_write(const uint8_t *data, uint64_t block, uint8_t count);
159+
160+
/*
161+
* Disk initilization
162+
*/
163+
virtual int disk_initialize();
164+
165+
/*
166+
* Return the number of blocks
167+
*
168+
* @returns number of blocks
169+
*/
170+
virtual uint64_t disk_sectors();
171+
172+
/*
173+
* Return memory size
174+
*
175+
* @returns memory size
176+
*/
177+
virtual uint64_t disk_size();
178+
179+
/*
180+
* To check the status of the storage chip
181+
*
182+
* @returns status: 0: OK, 1: disk not initialized, 2: no medium in the drive, 4: write protected
183+
*/
184+
virtual int disk_status();
185+
186+
private:
187+
188+
// MSC Bulk-only Stage
189+
enum Stage {
190+
READ_CBW, // wait a CBW
191+
ERROR, // error
192+
PROCESS_CBW, // process a CBW request
193+
SEND_CSW, // send a CSW
194+
};
195+
196+
// Bulk-only CBW
197+
typedef MBED_PACKED(struct)
198+
{
199+
uint32_t Signature;
200+
uint32_t Tag;
201+
uint32_t DataLength;
202+
uint8_t Flags;
203+
uint8_t LUN;
204+
uint8_t CBLength;
205+
uint8_t CB[16];
206+
} CBW;
207+
208+
// Bulk-only CSW
209+
typedef MBED_PACKED(struct)
210+
{
211+
uint32_t Signature;
212+
uint32_t Tag;
213+
uint32_t DataResidue;
214+
uint8_t Status;
215+
} CSW;
216+
217+
// If this class has been initialized
218+
bool _initialized;
219+
220+
// If msd device has been unmounted by host
221+
volatile bool _media_removed;
222+
223+
//state of the bulk-only state machine
224+
Stage _stage;
225+
226+
// current CBW
227+
CBW _cbw;
228+
229+
// CSW which will be sent
230+
CSW _csw;
231+
232+
// addr where will be read or written data
233+
uint32_t _addr;
234+
235+
// length of a reading or writing
236+
uint32_t _length;
237+
238+
// memory OK (after a memoryVerify)
239+
bool _mem_ok;
240+
241+
// cache in RAM before writing in memory. Useful also to read a block.
242+
uint8_t *_page;
243+
244+
int _block_size;
245+
uint64_t _memory_size;
246+
uint64_t _block_count;
247+
248+
// endpoints
249+
usb_ep_t _bulk_in;
250+
usb_ep_t _bulk_out;
251+
uint8_t _bulk_in_buf[64];
252+
uint8_t _bulk_out_buf[64];
253+
bool _out_ready;
254+
bool _in_ready;
255+
uint32_t _bulk_out_size;
256+
257+
// Interrupt to thread deferral
258+
events::PolledQueue _queue;
259+
events::Task<void()> _in_task;
260+
events::Task<void()> _out_task;
261+
events::Task<void()> _reset_task;
262+
events::Task<void(const USBDevice::setup_packet_t *)> _control_task;
263+
events::Task<void()> _configure_task;
264+
265+
mbed::BlockDevice *_bd;
266+
rtos::Mutex _mutex_init;
267+
rtos::Mutex _mutex;
268+
269+
// space for config descriptor
270+
uint8_t _configuration_descriptor[32];
271+
272+
virtual const uint8_t *string_iproduct_desc();
273+
virtual const uint8_t *string_iinterface_desc();
274+
virtual const uint8_t *configuration_desc(uint8_t index);
275+
virtual void callback_set_interface(uint16_t interface, uint8_t alternate);
276+
virtual void callback_state_change(USBDevice::DeviceState new_state);
277+
virtual uint32_t callback_request(const USBDevice::setup_packet_t *setup, USBDevice::RequestResult *result, uint8_t** data);
278+
virtual bool callback_request_xfer_done(const USBDevice::setup_packet_t *setup, bool aborted);
279+
virtual bool callback_set_configuration(uint8_t configuration);
280+
virtual void init(EndpointResolver& resolver);
281+
282+
void _isr_out();
283+
void _isr_in();
284+
285+
void _out();
286+
void _in();
287+
void _reset();
288+
uint32_t _control(const USBDevice::setup_packet_t *setup, USBDevice::RequestResult *result, uint8_t** data);
289+
void _configure();
290+
291+
void _init();
292+
void _process();
293+
void _write_next(uint8_t *data, uint32_t size);
294+
void _read_next();
295+
296+
void CBWDecode(uint8_t *buf, uint16_t size);
297+
void sendCSW(void);
298+
bool inquiryRequest(void);
299+
bool write(uint8_t *buf, uint16_t size);
300+
bool readFormatCapacity();
301+
bool readCapacity(void);
302+
bool infoTransfer(void);
303+
void memoryRead(void);
304+
bool modeSense6(void);
305+
void testUnitReady(void);
306+
bool requestSense(void);
307+
void memoryVerify(uint8_t *buf, uint16_t size);
308+
void memoryWrite(uint8_t *buf, uint16_t size);
309+
void msd_reset();
310+
void fail();
311+
};
312+
}
313+
314+
extern arduino::USBMSD MassStorage;
315+
316+
#endif

libraries/USBMSD/Singleton.cpp

+29
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
#include "Arduino.h"
2+
#include "PluggableUSBMSD.h"
3+
#include "FlashIAPBlockDevice.h"
4+
#include "FATFileSystem.h"
5+
6+
using namespace arduino;
7+
8+
static void process_msd(USBMSD* obj) {
9+
while (1) {
10+
obj->process();
11+
rtos::ThisThread::sleep_for(1);
12+
}
13+
}
14+
15+
static mbed::FATFileSystem fs("fs");
16+
static FlashIAPBlockDevice bd(0x80000, 0x80000);
17+
static rtos::Thread th;
18+
19+
void USBMSD::begin()
20+
{
21+
int err = fs.mount(&bd);
22+
if (err) {
23+
err = fs.reformat(&bd);
24+
}
25+
26+
th.start(mbed::callback(process_msd, this));
27+
}
28+
29+
USBMSD MassStorage(&bd);

0 commit comments

Comments
 (0)