1
+
2
+ #include "sdkconfig.h"
3
+ #if CONFIG_USB_ENABLED
4
+
5
+
6
+ #include <stdlib.h>
7
+ #include "esp_log.h"
8
+ #include "freertos/FreeRTOS.h"
9
+ #include "freertos/task.h"
10
+ #include "driver/gpio.h"
11
+ #include "tinyusb.h"
12
+
13
+ static const char * TAG = "example" ;
14
+
15
+ #if CONFIG_USB_MSC_ENABLED
16
+
17
+ #define README_CONTENTS "This is tinyusb's MassStorage Class demo.\r\n\r\nIf you find any bugs or get any questions, feel free to file an\r\nissue at github.com/hathach/tinyusb"
18
+
19
+ enum
20
+ {
21
+ DISK_BLOCK_NUM = 2 * 140 , // 8KB is the smallest size that windows allow to mount
22
+ DISK_BLOCK_SIZE = 512
23
+ };
24
+
25
+ #ifdef CFG_EXAMPLE_MSC_READONLY
26
+ const
27
+ #endif
28
+ uint8_t msc_disk [DISK_BLOCK_NUM ][DISK_BLOCK_SIZE ] =
29
+ {
30
+ //------------- Block0: Boot Sector -------------//
31
+ // byte_per_sector = DISK_BLOCK_SIZE; fat12_sector_num_16 = DISK_BLOCK_NUM;
32
+ // sector_per_cluster = 1; reserved_sectors = 1;
33
+ // fat_num = 1; fat12_root_entry_num = 16;
34
+ // sector_per_fat = 1; sector_per_track = 1; head_num = 1; hidden_sectors = 0;
35
+ // drive_number = 0x80; media_type = 0xf8; extended_boot_signature = 0x29;
36
+ // filesystem_type = "FAT12 "; volume_serial_number = 0x1234; volume_label = "TinyUSB MSC";
37
+ // FAT magic code at offset 510-511
38
+ {
39
+ 0xEB , 0x3C , 0x90 , 0x4D , 0x53 , 0x44 , 0x4F , 0x53 , 0x35 , 0x2E , 0x30 , 0x00 , 0x02 , 0x01 , 0x01 , 0x00 ,
40
+ 0x01 , 0x10 , 0x00 , 0x10 , 0x00 , 0xF8 , 0x01 , 0x00 , 0x01 , 0x00 , 0x01 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 ,
41
+ 0x00 , 0x00 , 0x00 , 0x00 , 0x80 , 0x00 , 0x29 , 0x34 , 0x12 , 0x00 , 0x00 , 'E' , 'S' , 'P' , '3' , '2' ,
42
+ 'S' , '2' , ' ' , 'M' , 'S' , 'C' , 0x46 , 0x41 , 0x54 , 0x31 , 0x32 , 0x20 , 0x20 , 0x20 , 0x00 , 0x00 ,
43
+
44
+ // Zero up to 2 last bytes of FAT magic code
45
+ 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 ,
46
+ 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 ,
47
+ 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 ,
48
+ 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 ,
49
+ 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 ,
50
+ 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 ,
51
+ 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 ,
52
+ 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 ,
53
+
54
+ 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 ,
55
+ 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 ,
56
+ 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 ,
57
+ 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 ,
58
+ 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 ,
59
+ 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 ,
60
+ 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 ,
61
+ 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 ,
62
+
63
+ 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 ,
64
+ 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 ,
65
+ 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 ,
66
+ 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 ,
67
+ 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 ,
68
+ 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 ,
69
+ 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 ,
70
+ 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 ,
71
+
72
+ 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 ,
73
+ 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 ,
74
+ 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 ,
75
+ 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x55 , 0xAA
76
+ },
77
+
78
+ //------------- Block1: FAT12 Table -------------//
79
+ {
80
+ 0xF8 , 0xFF , 0xFF , 0xFF , 0x0F // // first 2 entries must be F8FF, third entry is cluster end of readme file
81
+ },
82
+
83
+ //------------- Block2: Root Directory -------------//
84
+ {
85
+ // first entry is volume label
86
+ 'E' , 'S' , 'P' , '3' , '2' , 'S' , '2' , ' ' , 'M' , 'S' , 'C' , 0x08 , 0x00 , 0x00 , 0x00 , 0x00 ,
87
+ 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x4F , 0x6D , 0x65 , 0x43 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 ,
88
+ // second entry is readme file
89
+ 'R' , 'E' , 'A' , 'D' , 'M' , 'E' , ' ' , ' ' , 'T' , 'X' , 'T' , 0x20 , 0x00 , 0xC6 , 0x52 , 0x6D ,
90
+ 0x65 , 0x43 , 0x65 , 0x43 , 0x00 , 0x00 , 0x88 , 0x6D , 0x65 , 0x43 , 0x02 , 0x00 ,
91
+ sizeof (README_CONTENTS ) - 1 , 0x00 , 0x00 , 0x00 // readme's files size (4 Bytes)
92
+ },
93
+
94
+ //------------- Block3: Readme Content -------------//
95
+ README_CONTENTS
96
+ };
97
+
98
+ // Invoked when received SCSI_CMD_INQUIRY
99
+ // Application fill vendor id, product id and revision with string up to 8, 16, 4 characters respectively
100
+ void tud_msc_inquiry_cb (uint8_t lun , uint8_t vendor_id [8 ], uint8_t product_id [16 ], uint8_t product_rev [4 ])
101
+ {
102
+ (void ) lun ;
103
+
104
+ const char vid [] = "Espressif" ;
105
+ const char pid [] = "Mass Storage" ;
106
+ const char rev [] = "1.0" ;
107
+
108
+ memcpy (vendor_id , vid , strlen (vid ));
109
+ memcpy (product_id , pid , strlen (pid ));
110
+ memcpy (product_rev , rev , strlen (rev ));
111
+ ESP_LOGI (__func__ , "" );
112
+ }
113
+
114
+ // Invoked when received Test Unit Ready command.
115
+ // return true allowing host to read/write this LUN e.g SD card inserted
116
+ bool tud_msc_test_unit_ready_cb (uint8_t lun )
117
+ {
118
+ (void ) lun ;
119
+ ESP_LOGI (__func__ , "" );
120
+
121
+ return true; // RAM disk is always ready
122
+ }
123
+
124
+ // Invoked when received SCSI_CMD_READ_CAPACITY_10 and SCSI_CMD_READ_FORMAT_CAPACITY to determine the disk size
125
+ // Application update block count and block size
126
+ void tud_msc_capacity_cb (uint8_t lun , uint32_t * block_count , uint16_t * block_size )
127
+ {
128
+ (void ) lun ;
129
+ ESP_LOGI (__func__ , "" );
130
+
131
+ * block_count = DISK_BLOCK_NUM ;
132
+ * block_size = DISK_BLOCK_SIZE ;
133
+ }
134
+
135
+ // Invoked when received Start Stop Unit command
136
+ // - Start = 0 : stopped power mode, if load_eject = 1 : unload disk storage
137
+ // - Start = 1 : active mode, if load_eject = 1 : load disk storage
138
+ bool tud_msc_start_stop_cb (uint8_t lun , uint8_t power_condition , bool start , bool load_eject )
139
+ {
140
+ (void ) lun ;
141
+ (void ) power_condition ;
142
+ ESP_LOGI (__func__ , "" );
143
+
144
+ if ( load_eject )
145
+ {
146
+ if (start )
147
+ {
148
+ // load disk storage
149
+ } else
150
+ {
151
+ // unload disk storage
152
+ }
153
+ }
154
+
155
+ return true;
156
+ }
157
+
158
+ // Callback invoked when received READ10 command.
159
+ // Copy disk's data to buffer (up to bufsize) and return number of copied bytes.
160
+ int32_t tud_msc_read10_cb (uint8_t lun , uint32_t lba , uint32_t offset , void * buffer , uint32_t bufsize )
161
+ {
162
+ (void ) lun ;
163
+ ESP_LOGI (__func__ , "" );
164
+
165
+ uint8_t const * addr = msc_disk [lba ] + offset ;
166
+ memcpy (buffer , addr , bufsize );
167
+
168
+ return bufsize ;
169
+ }
170
+
171
+ // Callback invoked when received WRITE10 command.
172
+ // Process data in buffer to disk's storage and return number of written bytes
173
+ int32_t tud_msc_write10_cb (uint8_t lun , uint32_t lba , uint32_t offset , uint8_t * buffer , uint32_t bufsize )
174
+ {
175
+ (void ) lun ;
176
+ ESP_LOGI (__func__ , "" );
177
+
178
+ #ifndef CFG_EXAMPLE_MSC_READONLY
179
+ uint8_t * addr = msc_disk [lba ] + offset ;
180
+ memcpy (addr , buffer , bufsize );
181
+ #else
182
+ (void ) lba ; (void ) offset ; (void ) buffer ;
183
+ #endif
184
+
185
+ return bufsize ;
186
+ }
187
+
188
+ // Callback invoked when received an SCSI command not in built-in list below
189
+ // - READ_CAPACITY10, READ_FORMAT_CAPACITY, INQUIRY, MODE_SENSE6, REQUEST_SENSE
190
+ // - READ10 and WRITE10 has their own callbacks
191
+ int32_t tud_msc_scsi_cb (uint8_t lun , uint8_t const scsi_cmd [16 ], void * buffer , uint16_t bufsize )
192
+ {
193
+ // read10 & write10 has their own callback and MUST not be handled here
194
+ ESP_LOGI (__func__ , "" );
195
+
196
+ void const * response = NULL ;
197
+ uint16_t resplen = 0 ;
198
+
199
+ // most scsi handled is input
200
+ bool in_xfer = true;
201
+
202
+ switch (scsi_cmd [0 ])
203
+ {
204
+ case SCSI_CMD_PREVENT_ALLOW_MEDIUM_REMOVAL :
205
+ // Host is about to read/write etc ... better not to disconnect disk
206
+ resplen = 0 ;
207
+ break ;
208
+
209
+ default :
210
+ // Set Sense = Invalid Command Operation
211
+ tud_msc_set_sense (lun , SCSI_SENSE_ILLEGAL_REQUEST , 0x20 , 0x00 );
212
+
213
+ // negative means error -> tinyusb could stall and/or response with failed status
214
+ resplen = -1 ;
215
+ break ;
216
+ }
217
+
218
+ // return resplen must not larger than bufsize
219
+ if ( resplen > bufsize ) resplen = bufsize ;
220
+
221
+ if ( response && (resplen > 0 ) )
222
+ {
223
+ if (in_xfer )
224
+ {
225
+ memcpy (buffer , response , resplen );
226
+ } else
227
+ {
228
+ // SCSI output
229
+ }
230
+ }
231
+
232
+ return resplen ;
233
+ }
234
+
235
+ #endif /* CONFIG_USB_MSC_ENABLED */
236
+
237
+ #if CONFIG_USB_CDC_ENABLED
238
+ void tud_cdc_line_state_cb (uint8_t itf , bool dtr , bool rts ) {
239
+ if (dtr && rts ) {
240
+ tud_cdc_write_str ("Welcome to tinyUSB CDC example!!!\r\n" );
241
+ }
242
+ }
243
+ #endif /* CONFIG_USB_CDC_ENABLED */
244
+
245
+ // USB Device Driver task
246
+ // This top level thread processes all usb events and invokes callbacks
247
+ void usb_device_task (void * param ) {
248
+ (void )param ;
249
+ ESP_LOGI (TAG , "USB task started" );
250
+ while (1 ) {
251
+ tud_task (); // RTOS forever loop
252
+ }
253
+ }
254
+
255
+ void cloop () {
256
+ #if CONFIG_USB_CDC_ENABLED
257
+ if (tud_cdc_connected ()) {
258
+ // connected and there are data available
259
+ if ( tud_cdc_available () ) {
260
+ uint8_t buf [64 ];
261
+ // read and echo back
262
+ uint32_t count = tud_cdc_read (buf , sizeof (buf ));
263
+ for (uint32_t i = 0 ; i < count ; i ++ ) {
264
+ tud_cdc_write_char (buf [i ]);
265
+ if ( buf [i ] == '\r' ) {
266
+ tud_cdc_write_str ("\n > " );
267
+ }
268
+ }
269
+ tud_cdc_write_flush ();
270
+ }
271
+ }
272
+ #endif /* CONFIG_USB_CDC_ENABLED */
273
+ }
274
+
275
+ void csetup () {
276
+ tinyusb_config_t tusb_cfg = {
277
+ .descriptor = NULL ,
278
+ .string_descriptor = NULL ,
279
+ .external_phy = false
280
+ };
281
+
282
+ ESP_ERROR_CHECK (tinyusb_driver_install (& tusb_cfg ));
283
+ xTaskCreate (usb_device_task , "usbd" , 4096 , NULL , 24 , NULL );
284
+ }
285
+
286
+ #endif /* CONFIG_USB_ENABLED */
0 commit comments