@@ -170,6 +170,98 @@ class CDCProgCommand final : public CDCCommand {
170
170
BlitWriter writer;
171
171
};
172
172
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
+
173
265
class CDCListCommand final : public CDCCommand {
174
266
void init () override {
175
267
}
@@ -264,6 +356,7 @@ static CDCUserCommand user_command;
264
356
#define FLASH_COMMANDS
265
357
static CDCParseBuffer parse_buffer;
266
358
static CDCProgCommand prog_command (parse_buffer);
359
+ static CDCSaveCommand save_command (parse_buffer);
267
360
static CDCListCommand list_command;
268
361
static CDCLaunchCommand launch_command (parse_buffer);
269
362
static CDCEraseCommand erase_command (parse_buffer);
@@ -275,6 +368,7 @@ const std::tuple<uint32_t, CDCCommand *> cdc_commands[]{
275
368
276
369
#ifdef FLASH_COMMANDS
277
370
{to_cmd_id (" PROG" ), &prog_command},
371
+ {to_cmd_id (" SAVE" ), &save_command},
278
372
{to_cmd_id (" __LS" ), &list_command},
279
373
{to_cmd_id (" LNCH" ), &launch_command},
280
374
{to_cmd_id (" ERSE" ), &erase_command},
0 commit comments