/
USB_MSC.h
executable file
·233 lines (207 loc) · 5.82 KB
/
USB_MSC.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
//-------------------------------------------------------------------------------
// TinyCircuits TinyTV Firmware
//
// Changelog:
// 05/26/2023 Initial Release for TinyTV 2/Mini
// 02/08/2023 Cross-platform base committed
//
// Written by Mason Watmough, Ben Rose, and Jason Marcum for TinyCircuits, http://TinyCircuits.com
//
//-------------------------------------------------------------------------------
bool ejected = false;
bool mscStart = false;
bool fs_flushed = false;
bool mscActive = false;
volatile uint32_t lbaToRead = 0;
volatile uint8_t* lbaToReadPos = NULL;
volatile uint32_t lbaToReadCount = 0;
volatile uint32_t lbaToWrite = 0;
volatile uint8_t lbaToWritePos = 0;
volatile uint32_t lbaToWriteCount = 0;
uint8_t lbaWriteBuff[512 * 8];
uint32_t sectorLBACount = 1;
const bool secondCoreSD = false;
uint32_t lastMSCRead = 0;
uint32_t lastMSCWrite = 0;
int32_t msc_read_cb(uint32_t lba, void* buffer, uint32_t bufsize)
{
if (secondCoreSD /*&& !ejected*/ ) {
while (lbaToWriteCount || lbaToReadCount);
volatile int count = bufsize / 512;
lbaToRead = lba * sectorLBACount;
lbaToReadPos = (uint8_t*)buffer;
lbaToReadCount = count;
while (lbaToReadCount == count) {};
return bufsize;
} else if (/*!ejected*/ 1) {
lastMSCRead = millis();
return sd.card()->readSectors(lba * sectorLBACount, (uint8_t *)buffer, bufsize / 512) ? bufsize : -1;
}
return 0;
}
// Callback invoked when received WRITE10 command.
// Process data in buffer to disk's storage and
// return number of written bytes (must be multiple of block size)
int32_t msc_write_cb(uint32_t lba, uint8_t* buffer, uint32_t bufsize)
{
if (secondCoreSD /* && !ejected*/ ) {
while (lbaToWriteCount || lbaToReadCount);
memcpy(lbaWriteBuff, buffer, bufsize);
int count = bufsize / 512;
lbaToWrite = lba * sectorLBACount;
lbaToWritePos = 0;
lbaToWriteCount = count;
return bufsize;
} else if (/*!ejected*/ 1) {
lastMSCWrite = millis();
return sd.card()->writeSectors(lba * sectorLBACount, buffer, bufsize / 512) ? bufsize : -1;
}
return 0;
}
// Callback invoked when WRITE10 command is completed (status received and accepted by host).
// used to flush any pending cache.
void msc_flush_cb(void)
{
if (secondCoreSD /*&& !ejected*/ ) {
fs_flushed = true;
} else if (/*!ejected*/ 1) {
sd.card()->syncDevice();
sd.cacheClear();
}
}
// This callback is a C symbol because our Adafruit USB version doesn't expose a function pointer to it
#ifdef __cplusplus
extern "C" {
#endif
extern void displayNoVideosFound();
bool tud_msc_start_stop_cb(uint8_t lun, uint8_t power_condition, bool start, bool load_eject)
{
(void) lun;
//(void) power_condition;
// cdc.print(power_condition);
// cdc.print(" ");
// cdc.print(load_eject);
// cdc.print(" ");
// cdc.println(start);
//ejected = true;
if (load_eject)
{
if (start)
{
mscStart = true;
}
else
{
ejected = true;
//return false;
}
}
return true;
}
#ifdef __cplusplus
}
#endif
void USBMSCInit() {
usb_msc.setID("TinyCircuits", "RP2040TV", "1.0");
//usb_msc.setReadWriteCallback(msc_read_cb, msc_write_cb, msc_flush_cb);
usb_msc.setUnitReady(false);
usb_msc.begin();
}
void USBMSCReady() {
uint32_t block_count = sd.card()->sectorCount();
usb_msc.setCapacity(block_count, 512);
}
bool lastState = false;
int count = 0;
int timer = 0;
bool ended = false;
bool USBJustConnected() {
if (tud_connected()) {
if (lastState == false && ejected == false) {
lastState = true;
return true;
}
} else {
lastState = false;
ejected = false;
}
return false;
}
void USBMSCStart() {
count = 0;
timer = millis();
mscActive = true;
usb_msc.setReadWriteCallback(msc_read_cb, msc_write_cb, msc_flush_cb);
usb_msc.setUnitReady(true);
}
bool USBMSCJustStopped() {
if (ended) {
ended = false;
return true;
}
return false;
}
bool USBMSCRecentActivity(){
if( millis()- lastMSCRead < 500)
return true;
if( millis()- lastMSCWrite < 500)
return true;
return false;
}
bool handleUSBMSC(bool stopMSC) {
if (mscActive) {
//tud_ready doesn't seem to work, rely on ejected- doesn't seem to work in macos?
if (count < 100 && !stopMSC && !ejected) {
if ((millis() - timer > 1000) && !tud_ready() ) {
count++;
delay(1);
} else {
count = 0;
}
yield();
return true;
}
for (int i = 0; i < 50 || USBMSCRecentActivity(); i++) {
delay(1);
yield();
}
usb_msc.setUnitReady(false);
usb_msc.setReadWriteCallback(nullptr, nullptr, nullptr);
for (int i = 0; i < 50 || USBMSCRecentActivity(); i++) {
delay(1);
yield();
}
mscActive = false;
sd.card()->syncDevice();
sd.cacheClear();
while (sd.card()->isBusy()) {}
//usb_msc.setReadWriteCallback(nullptr, nullptr, nullptr);
ended = true;
}
return false;
}
void MSCloopCore1() {
if (secondCoreSD && !ejected ) {
if (lbaToReadCount) {
sd.card()->readSectors(lbaToRead, (uint8_t*) lbaToReadPos, 1);
lbaToReadPos += 512;
lbaToRead += 1;
lbaToReadCount -= 1;
//read first block, then remainder
if (lbaToReadCount) {
sd.card()->readSectors(lbaToRead, (uint8_t*) lbaToReadPos, lbaToReadCount);
}
lbaToReadCount = 0;
}
if (lbaToWriteCount) {
sd.card()->writeSectors(lbaToWrite, (uint8_t*)lbaWriteBuff + lbaToWritePos, lbaToWriteCount);
lbaToWriteCount = 0;
}
if (fs_flushed) {
sd.card()->syncDevice();
//sd.cacheClear();
while (sd.card()->isBusy()) {}
fs_flushed = false;
}
}
}