Skip to content

Commit 7b1882d

Browse files
committed
Move storage functions to class
1 parent 50cfe3a commit 7b1882d

3 files changed

Lines changed: 212 additions & 228 deletions

File tree

lib/storage/storage.cpp

Lines changed: 147 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,35 +1,159 @@
11
#include "storage.hpp"
2+
#include <FFat.h>
3+
#include <USB.h>
4+
#include <USBMSC.h>
5+
#include <cstdint>
26
#include <iostream>
7+
#include <string>
8+
9+
#if defined(ARDUINO_USB_MODE)
10+
static_assert(ARDUINO_USB_MODE == 0, "USB must be in OTG mode");
11+
#endif
312

413
const esp_partition_t *check_ffat_partition(const char *label); // defined in FFat.cpp
514

6-
Storage::Storage(const bool formatFsOnFail, const char *const partitionLabel, ESPUSB &usb, fs::F_Fat &fs, const std::size_t blockSize):
7-
partition(check_ffat_partition(partitionLabel)),
8-
blockSize(blockSize),
9-
fs(fs),
10-
usb(usb)
15+
static const std::string rootPath = "/";
16+
static constexpr std::size_t blockSize = 512; // bytes
17+
18+
static const esp_partition_t *partition;
19+
static USBMSC usbMsc;
20+
static bool usbIsRunning = false;
21+
static bool fileSystemIsReady = false;
22+
23+
static void callbackUsbStarted(void *, esp_event_base_t, int32_t event_id, void *)
24+
{
25+
usbIsRunning = true;
26+
Storage::switchToUsbMode();
27+
}
28+
29+
static void callbackUsbStopped(void *, esp_event_base_t, int32_t event_id, void *)
30+
{
31+
if (!usbIsRunning) /* https://github.com/espressif/arduino-esp32/issues/7228 */
32+
{
33+
return;
34+
}
35+
usbIsRunning = false;
36+
Storage::switchToApplicationMode();
37+
}
38+
39+
/**
40+
* Callback invoked when received WRITE10 command.
41+
*
42+
* Process data in buffer to disk's storage.
43+
*
44+
* @param lba logical block address
45+
* @returns the number of written bytes (must be multiple of block size)
46+
*/
47+
static std::int32_t usbMsc_onWrite(const std::uint32_t lba, const std::uint32_t offset, std::uint8_t *const buffer,
48+
const uint32_t bufsize)
49+
{
50+
std::cout << "MSC WRITE: lba: " << lba << ", offset: " << offset << ", bufsize: " << bufsize << std::endl;
51+
const std::uint32_t byteOffset = lba * blockSize + offset;
52+
ESP_ERROR_CHECK(esp_partition_erase_range(partition, byteOffset, bufsize)); // erase must be called before write
53+
ESP_ERROR_CHECK(esp_partition_write(partition, byteOffset, buffer, bufsize));
54+
return bufsize;
55+
}
56+
57+
// and
58+
// return
59+
60+
/**
61+
* Callback invoked when received READ10 command.
62+
*
63+
* Copy disk's data to buffer (up to bufsize).
64+
*
65+
* @param lba logical block address
66+
* @returns the number of copied bytes (must be multiple of block size)
67+
*/
68+
static std::int32_t usbMsc_onRead(const std::uint32_t lba, const std::uint32_t offset, void *const buffer,
69+
const std::uint32_t bufsize)
70+
{
71+
std::cout << "MSC READ: lba: " << lba << ", offset: " << offset << ", bufsize: " << bufsize << std::endl;
72+
const std::uint32_t byteOffset = lba * blockSize + offset;
73+
ESP_ERROR_CHECK(esp_partition_read(partition, byteOffset, buffer, bufsize));
74+
return bufsize;
75+
}
76+
77+
static bool usbMsc_onStartStop(const std::uint8_t power_condition, const bool start, const bool load_eject)
78+
{
79+
std::cout << "MSC START/STOP: power: " << power_condition << ", start: " << start << ", eject: " << load_eject
80+
<< std::endl;
81+
return true;
82+
}
83+
84+
std::size_t Storage::size()
85+
{
86+
return FFat.totalBytes();
87+
}
88+
89+
void Storage::begin(const bool formatFsOnFail, const char *const partitionLabel)
90+
{
91+
partition = check_ffat_partition(partitionLabel);
92+
93+
if (!partition)
94+
{
95+
std::cerr << "Error with partition!" << std::endl;
96+
return;
97+
}
98+
99+
// initialize file system
100+
const auto basePath = rootPath + partitionLabel;
101+
constexpr auto maxOpenFiles = 10U;
102+
if (!FFat.begin(formatFsOnFail, basePath.c_str(), maxOpenFiles, partitionLabel))
103+
{
104+
std::cerr << "File-system initialization failed!" << std::endl;
105+
return;
106+
}
107+
std::cout << "Storage has a size of " << size() << " bytes." << std::endl;
108+
109+
// setup USB Mass Storage Class
110+
usbMsc.vendorID("TTS"); // max 8 chars
111+
usbMsc.productID("TTD"); // max 16 chars
112+
usbMsc.productRevision("1.0"); // max 4 chars
113+
usbMsc.onStartStop(usbMsc_onStartStop);
114+
// Set callback
115+
usbMsc.onRead(usbMsc_onRead);
116+
usbMsc.onWrite(usbMsc_onWrite);
117+
// usbMsc is ready for read/write
118+
usbMsc.mediaPresent(true);
119+
usbMsc.begin(FFat.totalBytes() / blockSize, blockSize);
120+
fileSystemIsReady = true;
121+
122+
// subscribe to USB events
123+
USB.onEvent(ARDUINO_USB_STARTED_EVENT, callbackUsbStarted);
124+
USB.onEvent(ARDUINO_USB_STOPPED_EVENT, callbackUsbStopped);
125+
USB.begin();
126+
}
127+
128+
void Storage::end()
11129
{
12-
if(!partition){
13-
std::cerr << "Error with partition!" << std::endl;
14-
return;
15-
}
130+
usbMsc.end();
131+
usbIsRunning = false;
132+
FFat.end();
133+
fileSystemIsReady = false;
134+
}
16135

17-
// initialize file system
18-
const auto basePath = rootPath + partitionLabel;
19-
constexpr auto maxOpenFiles = 10;
20-
if(!fs.begin(formatFsOnFail, basePath.c_str(), maxOpenFiles, partitionLabel)){
21-
std::cerr << "File-system initialization failed!" << std::endl;
22-
return;
23-
}
24-
std::cout << "Storage has a size of " << size() << " bytes." << std::endl;
136+
void Storage::switchToUsbMode()
137+
{
138+
FFat.end(); // flush and unmount
139+
fileSystemIsReady = false;
140+
usbMsc.mediaPresent(true);
141+
}
25142

26-
// subscribe to USB events
27-
callbackSubscribers.push_back(this);
28-
usb.onEvent(ARDUINO_USB_STARTED_EVENT, callbackUsbStarted_s);
29-
usb.onEvent(ARDUINO_USB_STOPPED_EVENT, callbackUsbStopped_s);
143+
bool Storage::isFileSystemReady()
144+
{
145+
return fileSystemIsReady;
146+
}
147+
148+
void Storage::switchToApplicationMode()
149+
{
150+
usbMsc.mediaPresent(false);
151+
FFat.end(); // invalidate cache
152+
FFat.begin(); // update data
153+
fileSystemIsReady = true;
30154
}
31155

32-
std::size_t Storage::size() const
156+
fs::FS &Storage::getFileSystem()
33157
{
34-
return fs.totalBytes();
158+
return FFat;
35159
}

lib/storage/storage.hpp

Lines changed: 16 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1,42 +1,30 @@
11
#pragma once
22
#include <FFat.h>
3-
#include <USB.h>
3+
#include <FS.h>
44
#include <USBMSC.h>
55
#include <cstddef>
6+
#include <esp_event_base.h>
67
#include <esp_partition.h>
7-
#include <optional>
88
#include <string>
9-
#include <vector>
109

1110
class Storage
1211
{
1312
public:
14-
Storage(bool formatFsOnFail = false, const char *partitionLabel = FFAT_PARTITION_LABEL, ESPUSB &usb = USB,
15-
fs::F_Fat &fs = FFat, std::size_t blockSize = 512);
16-
bool isFileSystemReady() const;
17-
void setCallbackFsReady();
18-
void setCallbackFsBusy();
19-
std::size_t size() const;
20-
std::string getFileContents(const char *path) const;
21-
~Storage();
13+
static void begin(bool formatFsOnFail = false, const char *partitionLabel = FFAT_PARTITION_LABEL);
14+
static void end();
15+
static bool isFileSystemReady();
16+
static std::size_t size();
17+
static std::string getFileContent(const char *path);
2218

23-
static constexpr std::string rootPath = "/";
24-
25-
protected:
26-
fs::FS &getFileSystem();
27-
28-
private:
29-
const esp_partition_t *partition;
3019
/**
31-
* Interface to USB mass storage class.
20+
* Switch from application mode (file system) to USB MSC.
3221
*/
33-
USBMSC usbMsc;
34-
const std::size_t blockSize;
35-
fs::F_Fat &fs;
36-
ESPUSB &usb;
37-
static std::vector<Storage *> callbackSubscribers;
38-
static esp_event_handler_t callbackUsbStarted_s;
39-
void callbackUsbStarted();
40-
static esp_event_handler_t callbackUsbStopped_s;
41-
void callbackUsbStopped();
22+
static void switchToUsbMode();
23+
/**
24+
* Switch from USB MSC to application mode (file system).
25+
*/
26+
static void switchToApplicationMode();
27+
28+
protected:
29+
static fs::FS &getFileSystem();
4230
};

0 commit comments

Comments
 (0)