@@ -27,19 +27,49 @@ static constexpr std::uint16_t blockSize = 512; // Should be 512
2727static const esp_partition_t *partition = nullptr ;
2828static const char *const TAG = " STORAGE" ;
2929
30+ /* *
31+ * Lists files and directories at path.
32+ */
33+ static void listFiles (const char *const dirname)
34+ {
35+ std::cout << " Directory: '" << dirname << " '" << std::endl;
36+ File root = FFat.open (dirname);
37+ if (!root || !root.isDirectory ())
38+ {
39+ ESP_LOGE (TAG, " Error: '%s' is not a directory!\n " , dirname);
40+ return ;
41+ }
42+
43+ File file = root.openNextFile ();
44+ while (file)
45+ {
46+ std::cout << " \t " << file.name () << " (" << (file.isDirectory () ? " d" : " f" ) << " , " << file.size () << " Bytes)"
47+ << std::endl;
48+ file.close ();
49+ file = root.openNextFile ();
50+ }
51+ file.close ();
52+ root.close ();
53+ }
54+
3055class FileSystemSwitcher
3156{
3257 public:
33- typedef decltype (FFat) FileSystem;
34- std::shared_ptr<FileSystem> getFileSystem_locking ()
58+ void begin (const bool fsIsActive)
59+ {
60+ fileSystemIsActive = fsIsActive;
61+ stateMachine = std::thread (&FileSystemSwitcher::processStateRequests, this );
62+ }
63+
64+ std::shared_ptr<fs::FS> getFileSystem_locking ()
3565 {
3666 std::unique_lock fs_state_lock{fileSystemState_mutex};
3767 if (!fileSystemIsActive)
3868 {
3969 stateChanged.wait (fs_state_lock, [this ]() { return fileSystemIsActive; });
4070 }
4171 fs_state_lock.release ();
42- return {&FFat, [this ](FileSystem *) { fileSystemState_mutex.unlock (); }};
72+ return {&FFat, [this ](fs::FS *) { fileSystemState_mutex.unlock (); }};
4373 }
4474 void requestState (const bool fileSystemActive)
4575 {
@@ -52,7 +82,27 @@ class FileSystemSwitcher
5282 {
5383 return fileSystemIsActive;
5484 }
55- void refreshState ();
85+ void processStateRequests ()
86+ {
87+ while (true )
88+ {
89+ std::unique_lock fs_state_lock{fileSystemState_mutex};
90+ stateChangeRequested.wait (fs_state_lock,
91+ [this ]() { return requestFileSystemActive != fileSystemIsActive; });
92+ if (fileSystemIsActive = requestFileSystemActive)
93+ {
94+ usbMsc.mediaPresent (false );
95+ FFat.end (); // invalidate cache
96+ assert (FFat.begin ()); // update data
97+ listFiles (" /" );
98+ }
99+ else
100+ {
101+ FFat.end (); // flush and unmount
102+ usbMsc.mediaPresent (true );
103+ }
104+ }
105+ }
56106
57107 private:
58108 std::condition_variable stateChangeRequested;
@@ -63,31 +113,7 @@ class FileSystemSwitcher
63113 bool fileSystemIsActive; // !< describes the current state
64114};
65115
66- class ReadyCondition
67- {
68- public:
69- void setReady (const bool new_state)
70- {
71- ready = new_state;
72- conditionVariable.notify_all ();
73- }
74- bool isReady () const
75- {
76- return ready;
77- }
78- void wait_unitl_ready () const
79- {
80- std::mutex cv_m;
81- std::unique_lock<std::mutex> lock (cv_m);
82- conditionVariable.wait (lock, [this ] { return isReady (); });
83- }
84-
85- private:
86- mutable std::condition_variable conditionVariable;
87- std::atomic<bool > ready;
88- };
89-
90- static ReadyCondition fileSystemState;
116+ static FileSystemSwitcher fileSystemSwitcher;
91117
92118/* *
93119 * Callback invoked when received WRITE10 command.
@@ -135,79 +161,20 @@ std::size_t Storage::size()
135161 return FFat.totalBytes ();
136162}
137163
138- /* *
139- * Lists files and directories at path.
140- */
141- static void listFiles (const char *const dirname)
142- {
143- std::cout << " Directory: '" << dirname << " '" << std::endl;
144- File root = FFat.open (dirname);
145- if (!root || !root.isDirectory ())
146- {
147- ESP_LOGE (TAG, " Error: '%s' is not a directory!\n " , dirname);
148- return ;
149- }
150-
151- File file = root.openNextFile ();
152- while (file)
153- {
154- std::cout << " \t " << file.name () << " (" << (file.isDirectory () ? " d" : " f" ) << " , " << file.size () << " Bytes)"
155- << std::endl;
156- file.close ();
157- file = root.openNextFile ();
158- }
159- file.close ();
160- root.close ();
161- }
162-
163- /* *
164- * Switch from USB MSC to application mode (file system).
165- */
166- static void switchToApplicationMode ()
167- {
168- usbMsc.mediaPresent (false );
169- FFat.end (); // invalidate cache
170- assert (FFat.begin ()); // update data
171- fileSystemState.setReady (true );
172- }
173-
174- /* *
175- * Switch from application mode (file system) to USB MSC.
176- */
177- static void switchToUSBMode ()
178- {
179- FFat.end (); // flush and unmount
180- fileSystemState.setReady (false );
181- usbMsc.mediaPresent (true );
182- }
183-
184- static void usb_stopped_cb (void *const pvParameters)
185- {
186- switchToApplicationMode ();
187- listFiles (" /" );
188- vTaskDelete (nullptr );
189- }
190-
191- static void usb_started_cb (void *const pvParameters)
192- {
193- switchToUSBMode ();
194- vTaskDelete (nullptr );
195- }
196-
197- static bool usbIsRunning = false ;
164+ static std::atomic<bool > usbIsRunning = false ;
198165static void usbStoppedCallback (void *, esp_event_base_t , int32_t , void *)
199166{
200167 if (!usbIsRunning)
201168 {
202169 return ;
203170 }
204171 usbIsRunning = false ;
205- xTaskCreate (usb_stopped_cb, " USB_Stopped_CB " , 4096 , nullptr , 5 , nullptr );
172+ fileSystemSwitcher. requestState ( true );
206173}
207174static void usbStartedCallback (void *, esp_event_base_t , int32_t , void *)
208175{
209176 usbIsRunning = true ;
210- xTaskCreate (usb_started_cb, " USB_Started_CB " , 4096 , nullptr , 5 , nullptr );
177+ fileSystemSwitcher. requestState ( false );
211178}
212179
213180void Storage::begin ()
@@ -228,17 +195,18 @@ void Storage::begin()
228195 }
229196 ESP_LOGI (TAG, " Flash has a size of %u bytes\n " , FFat.totalBytes ());
230197
231- USB. onEvent (ARDUINO_USB_STARTED_EVENT, usbStartedCallback);
232- USB. onEvent (ARDUINO_USB_STOPPED_EVENT, usbStoppedCallback);
198+ fileSystemSwitcher. begin ( true ); // define state before callbacks are activated
199+
233200 usbMsc.vendorID (" ESP32" ); // max 8 chars
234201 usbMsc.productID (" USB_MSC" ); // max 16 chars
235202 usbMsc.productRevision (" 1.0" ); // max 4 chars
236203 usbMsc.onStartStop (usbMsc_onStartStop);
204+ usbMsc.mediaPresent (false );
237205 // Set callback
238206 usbMsc.onRead (usbMsc_onRead);
239207 usbMsc.onWrite (usbMsc_onWrite);
240- // MSC is ready for read/write
241- usbMsc. mediaPresent ( true );
208+ USB. onEvent (ARDUINO_USB_STARTED_EVENT, usbStartedCallback);
209+ USB. onEvent (ARDUINO_USB_STOPPED_EVENT, usbStoppedCallback );
242210
243211 // Set disk size, block size should be 512 regardless of spi flash page size
244212 if (!usbMsc.begin (FFat.totalBytes () / blockSize, blockSize))
@@ -257,9 +225,3 @@ void Storage::end()
257225 usbIsRunning = false ;
258226 FFat.end ();
259227}
260-
261- void Storage::waitForFileSystem ()
262- {
263- fileSystemState.wait_unitl_ready ();
264- listFiles (" /" );
265- }
0 commit comments