Skip to content

Commit

Permalink
tinyusb/msc_fat_view: Add write support for config.txt
Browse files Browse the repository at this point in the history
Code allows to write back configuration.
  • Loading branch information
kasjer committed May 29, 2024
1 parent 050fd7c commit e835c9f
Showing 1 changed file with 180 additions and 4 deletions.
184 changes: 180 additions & 4 deletions hw/usb/tinyusb/msc_fat_view/src/entry_config.c
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
*/

#include <stdint.h>
#include <ctype.h>
#include <stream/stream.h>
#include <msc_fat_view/msc_fat_view.h>
#include <modlog/modlog.h>
Expand All @@ -26,9 +27,13 @@

struct config_export_stream {
struct out_stream out_stream;
/* Buffer to write to (can be NULL) */
uint8_t *buffer;
/* Stream start offset, writes to stream preceding this will be dropped */
uint32_t buffer_start_offset;
/* Stream end offset, writes to stream after this will be dropped */
uint16_t buffer_end_offset;
/* Current stream write offset */
uint32_t write_offset;
};

Expand Down Expand Up @@ -84,6 +89,17 @@ config_text_export(char *name, char *val)
ostream_write(&export_stream.out_stream, (const uint8_t *)"\n", 1, false);
}

static const char *const CONFIG_BEGIN = "#### Config begin ####\n";
static const char *const CONFIG_END = "##### Config end #####\n";

void
config_txt_render_file(struct out_stream *stream)
{
ostream_write_str(&export_stream.out_stream, CONFIG_BEGIN);
conf_export(config_text_export, CONF_EXPORT_SHOW);
ostream_write_str(&export_stream.out_stream, CONFIG_END);
}

static uint32_t
config_txt_size(const file_entry_t *file_entry)
{
Expand All @@ -92,7 +108,7 @@ config_txt_size(const file_entry_t *file_entry)
export_stream.buffer_end_offset = 0;
export_stream.write_offset = 0;

conf_export(config_text_export, CONF_EXPORT_SHOW);
config_txt_render_file(&export_stream.out_stream);

return export_stream.write_offset;
}
Expand All @@ -105,8 +121,168 @@ config_txt_read(const struct file_entry *entry, uint32_t file_sector, uint8_t bu
export_stream.buffer_end_offset = export_stream.buffer_start_offset + 512;
export_stream.write_offset = 0;

MSC_FAT_VIEW_LOG_DEBUG("Config.txt read %d\n", file_sector);
conf_export(config_text_export, CONF_EXPORT_SHOW);
MSC_FAT_VIEW_LOG_DEBUG("Config.txt read sector %d\n", file_sector);
config_txt_render_file(&export_stream.out_stream);
}

static uint8_t *line;
static size_t line_len;

enum config_write_state {
WRITE_STATE_IDLE,
WRITE_STATE_DROP,
WRITE_STATE_CONFIG_LINES,
WRITE_STATE_CONFIG_WRITTEN,

} config_write_state;

static struct os_callout reboot_callout;

static void
reboot_fun(struct os_event *ev)
{
os_reboot(0);
}

static void
handle_line(uint8_t *bl, uint8_t *el)
{
size_t len = el - bl;
uint8_t *p;
uint8_t *nb;
uint8_t *ne;
uint8_t *vb;

if (config_write_state == WRITE_STATE_IDLE) {
if (memcmp(CONFIG_BEGIN, bl, len) == 0) {
config_write_state = WRITE_STATE_CONFIG_LINES;
return;
}
} else if (config_write_state == WRITE_STATE_CONFIG_LINES) {
if (memcmp(CONFIG_END, bl, len) == 0) {
conf_commit(NULL);
conf_save();
config_write_state = WRITE_STATE_CONFIG_WRITTEN;
os_callout_init(&reboot_callout, os_eventq_dflt_get(), reboot_fun, NULL);
os_callout_reset(&reboot_callout, os_time_ms_to_ticks32(2000));
return;
}

/* Trim line to first # */
for (p = bl; p < el && *p != '#'; ++p) {
}
el = p;
/* Trim trailing spaces */
for (p = el - 1; p >= bl && isspace(*p); --p) {
}
el = p + 1;

/* Trim leading spaces */
for (p = bl; p < el && isspace(*p); ++p) {
}
if (p >= el) {
return;
}
/* Variable name start found */
nb = p;
/* Find variable name end */
for (; p < el && !isspace(*p) && *p != '='; ++p) {
}
ne = p;
/* Skip spaces if any */
for (; p < el && isspace(*p); ++p) {
}
/* If next character is not = nothing to set */
if (p >= el || *p != '=') {
return;
}
/* Trim spaces after = */
for (++p; p < el && isspace(*p); ++p) {
}
if (p >= el) {
return;
}
vb = p;
/* Add string terminators */
*ne = '\0';
*el = '\0';
conf_set_value((char *)nb, (char *)vb);
}
}

static int
config_write_sector(uint32_t sector, uint8_t *buffer)
{
uint8_t *p;
uint8_t *e = buffer + 512;
uint8_t *line_begin = buffer;
uint8_t *bl;
uint8_t *el;
int c;

for (p = buffer; p < e; ++p) {
if (config_write_state == WRITE_STATE_CONFIG_WRITTEN) {
config_write_state = WRITE_STATE_IDLE;
return 512;
} else if (config_write_state == WRITE_STATE_DROP) {
return 0;
} else {
c = *p;
if (c == '\r' || c == '\n') {
if (line) {
line_len += (p - line_begin);
line = os_realloc(line, line_len + (p - line_begin));
bl = line;
el = bl + line_len;
} else {
bl = line_begin;
el = p;
line_len = p - bl;
}
if (line_len) {
handle_line(bl, el);
}
os_free(line);
line = NULL;
line_begin = p + 1;
} else if (iscntrl(c)) {
if (config_write_state != WRITE_STATE_IDLE) {
config_write_state = WRITE_STATE_IDLE;
return 512;
}
}
}
}
return config_write_state == WRITE_STATE_IDLE ? 0 : 512;
}


static void
config_txt_write(const struct file_entry *entry, uint32_t file_sector, uint8_t buffer[512])
{
MSC_FAT_VIEW_LOG_DEBUG("Config.txt write sector %d\n", file_sector);

config_write_sector(file_sector, buffer);
}

static int
config_write_sector_handler(struct msc_fat_view_write_handler *handler, uint32_t sector,
uint8_t *buffer)
{
MSC_FAT_VIEW_LOG_DEBUG("config_write_sector_handler %d\n", (int)sector);

return config_write_sector(sector, buffer);
}

static int
config_file_written(struct msc_fat_view_write_handler *handler, uint32_t size, uint32_t sector,
bool first_sector)
{
MSC_FAT_VIEW_LOG_DEBUG("config_file_written %d %d\n", (unsigned)size, (unsigned )sector);

return 0;
}

ROOT_DIR_ENTRY(config_txt, "CONFIG.TXT", FAT_FILE_ENTRY_ATTRIBUTE_READ_ONLY, config_txt_size, config_txt_read, NULL, NULL);
ROOT_DIR_ENTRY(config_txt, "CONFIG.TXT", FAT_FILE_ENTRY_ATTRIBUTE_FILE, config_txt_size,
config_txt_read, config_txt_write, NULL, NULL);
MSC_FAT_VIEW_WRITE_HANDLER(config_handler, config_write_sector_handler, config_file_written);

0 comments on commit e835c9f

Please sign in to comment.