Skip to content

Commit 23f4653

Browse files
committed
pico: implement SAVE command
Shares a bit with PROG, but a bit simpler
1 parent fa14018 commit 23f4653

File tree

1 file changed

+94
-0
lines changed

1 file changed

+94
-0
lines changed

32blit-pico/usb.cpp

+94
Original file line numberDiff line numberDiff line change
@@ -170,6 +170,98 @@ class CDCProgCommand final : public CDCCommand {
170170
BlitWriter writer;
171171
};
172172

173+
class CDCSaveCommand final : public CDCCommand {
174+
public:
175+
CDCSaveCommand(CDCParseBuffer &buf) : buf(buf) {}
176+
177+
void init() override {
178+
parse_state = ParseState::Filename;
179+
buf.reset();
180+
}
181+
182+
Status update() override {
183+
while(true) {
184+
switch(parse_state) {
185+
case ParseState::Filename: {
186+
auto status = cdc_read_string(buf, MAX_FILENAME);
187+
if(status == Status::Done) {
188+
auto filename = (const char *)buf.get_data();
189+
190+
file = blit::api.open_file(filename, blit::OpenMode::write);
191+
if(!file) {
192+
blit::debugf("Failed to open %s", filename);
193+
return Status::Error;
194+
}
195+
196+
parse_state = ParseState::Length;
197+
buf.reset();
198+
continue;
199+
}
200+
201+
return status;
202+
}
203+
204+
case ParseState::Length: {
205+
auto status = cdc_read_string(buf, MAX_FILELEN);
206+
if(status == Status::Done) {
207+
file_length = strtoul((const char *)buf.get_data(), nullptr, 10);
208+
parse_state = ParseState::Data;
209+
buf.reset();
210+
continue;
211+
}
212+
213+
return status;
214+
}
215+
216+
case ParseState::Data: {
217+
// read data
218+
auto max = std::min(uint32_t(FLASH_PAGE_SIZE), file_length - file_offset);
219+
auto read = usb_cdc_read(buf.get_current_ptr(), max);
220+
221+
if(!read)
222+
return Status::Continue;
223+
224+
// write whatever we got, the fs is going to buffer anyway
225+
auto written = blit::api.write_file(file, file_offset, read, (const char *)buf.get_data());
226+
if(written != read) {
227+
blit::api.close_file(file);
228+
return Status::Error;
229+
}
230+
231+
file_offset += read;
232+
233+
// end of file
234+
if(file_offset == file_length) {
235+
blit::api.close_file(file);
236+
237+
// send response
238+
uint8_t res_data[]{'3', '2', 'B', 'L', '_', '_', 'O', 'K'};
239+
usb_cdc_write(res_data, sizeof(res_data));
240+
usb_cdc_flush_write();
241+
242+
return Status::Done;
243+
}
244+
245+
break;
246+
}
247+
}
248+
}
249+
250+
return Status::Continue;
251+
}
252+
253+
enum class ParseState {
254+
Filename,
255+
Length,
256+
Data
257+
} parse_state = ParseState::Filename;
258+
259+
CDCParseBuffer &buf;
260+
261+
void *file = nullptr;
262+
uint32_t file_length = 0, file_offset = 0;
263+
};
264+
173265
class CDCListCommand final : public CDCCommand {
174266
void init() override {
175267
}
@@ -264,6 +356,7 @@ static CDCUserCommand user_command;
264356
#define FLASH_COMMANDS
265357
static CDCParseBuffer parse_buffer;
266358
static CDCProgCommand prog_command(parse_buffer);
359+
static CDCSaveCommand save_command(parse_buffer);
267360
static CDCListCommand list_command;
268361
static CDCLaunchCommand launch_command(parse_buffer);
269362
static CDCEraseCommand erase_command(parse_buffer);
@@ -275,6 +368,7 @@ const std::tuple<uint32_t, CDCCommand *> cdc_commands[]{
275368

276369
#ifdef FLASH_COMMANDS
277370
{to_cmd_id("PROG"), &prog_command},
371+
{to_cmd_id("SAVE"), &save_command},
278372
{to_cmd_id("__LS"), &list_command},
279373
{to_cmd_id("LNCH"), &launch_command},
280374
{to_cmd_id("ERSE"), &erase_command},

0 commit comments

Comments
 (0)