Skip to content

Commit

Permalink
New command: SYS:LFS? (#70)
Browse files Browse the repository at this point in the history
* Add new command: SYS:LFS?
* Update logging.
* Update README.
  • Loading branch information
tjko authored Jan 22, 2024
1 parent 83025b3 commit 6ca0eeb
Show file tree
Hide file tree
Showing 6 changed files with 165 additions and 7 deletions.
7 changes: 5 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,8 @@ Fanpico is a smart PWM (PC) fan controller based around [Raspberry Pi Pico](http
* Configuration stored on the device itself (in the flash memory).
* SCPI "like" programming interface (see [Command Reference](commands.md))
* Monitor each fan and motherboard output signals as well as temperatures.
* WiFi support if opting to mount Pico W on the board. This turns fanpico to "IoT" device with basic web interface.
* MQTT client (with TLS support) for loggin data and to receive commands (see [Wiki](https://github.com/tjko/fanpico/wiki/FanPico-MQTT-Tutorial) for more information).
* [WiFi support](https://github.com/tjko/fanpico/wiki/FanPico-Web-Interface) if opting to mount Pico W on the board. This turns fanpico into small "IoT" device with basic web interface.
* [MQTT client](https://github.com/tjko/fanpico/wiki/FanPico-MQTT-Tutorial) with TLS support for logging data and to receive commands.

### Interfaces

Expand Down Expand Up @@ -108,6 +108,9 @@ To help design and test Fanpico couple other projects were born:
* [Tiny PicoProbe](https://github.com/tjko/tiny-picoprobe/) - tiny PicoProbe implementation.
* [Fan Test Adapter](https://github.com/tjko/fan-test-adapter/) - adapter to help simulate motherboard fan outputs.

Projects based on FanPico firmware:
* [BrickPico](https://github.com/tjko/brickpico/) - (LEGO) LED Light Kit Controller.

### Models (PCB designs)
Currently following models are available:

Expand Down
15 changes: 15 additions & 0 deletions commands.md
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,7 @@ Fanpico supports following commands:
* [SYStem:FLASH?](#systemflash)
* [SYStem:LED](#systemled)
* [SYStem:LED?](#systemled-1)
* [SYStem:LFS?](#systemlfs)
* [SYStem:MBFANS?](#systemmbfans)
* [SYStem:MEM](#systemmem)
* [SYStem:MEM?](#systemmem-1)
Expand Down Expand Up @@ -1664,6 +1665,20 @@ SYS:LED?
```


#### SYStem:LFS?
Display information about the LittleFS filesystem in the flash memory.

Example:
```
SYS:LFS?
Filesystem size: 262144
Filesystem used: 24576
Filesystem free: 237568
Number of files: 3
Number of subdirectories: 0
```


#### SYStem:MBFANS?
Display number of MBFAN input ports available.

Expand Down
21 changes: 21 additions & 0 deletions src/command.c
Original file line number Diff line number Diff line change
Expand Up @@ -2234,6 +2234,26 @@ int cmd_name(const char *cmd, const char *args, int query, char *prev_cmd)
}


int cmd_littlefs(const char *cmd, const char *args, int query, char *prev_cmd)
{
size_t size, free, used, files, dirs;

if (!query)
return 1;
if (flash_get_fs_info(&size, &free, &files, &dirs, NULL) < 0)
return 2;

used = size - free;
printf("Filesystem size: %u\n", size);
printf("Filesystem used: %u\n", used);
printf("Filesystem free: %u\n", free);
printf("Number of files: %u\n", files);
printf("Number of subdirectories: %u\n", dirs);

return 0;
}


int cmd_flash(const char *cmd, const char *args, int query, char *prev_cmd)
{
if (!query)
Expand Down Expand Up @@ -2406,6 +2426,7 @@ const struct cmd_t system_commands[] = {
{ "FANS", 4, NULL, cmd_fans },
{ "FLASH", 5, NULL, cmd_flash },
{ "LED", 3, NULL, cmd_led },
{ "LFS", 3, NULL, cmd_littlefs },
{ "LOG", 3, NULL, cmd_log_level },
{ "MBFANS", 6, NULL, cmd_mbfans },
{ "MEMory", 3, NULL, cmd_memory },
Expand Down
9 changes: 4 additions & 5 deletions src/fanpico.c
Original file line number Diff line number Diff line change
Expand Up @@ -324,7 +324,7 @@ void core1_main()
delta = absolute_time_diff_us(t_last, t_now);
t_last = t_now;

if (delta > max_delta || delta > 1000000) {
if (delta > max_delta) {
max_delta = delta;
log_msg(LOG_INFO, "core1: max_loop_time=%lld", max_delta);
}
Expand Down Expand Up @@ -391,7 +391,7 @@ void core1_main()
memcpy(config, cfg, sizeof(*config));
mutex_exit(config_mutex);
} else {
log_msg(LOG_INFO, "failed to get config_mutex");
log_msg(LOG_DEBUG, "failed to get config_mutex");
}
}
if (time_passed(&t_state, 500)) {
Expand All @@ -400,7 +400,7 @@ void core1_main()
memcpy(&transfer_state, state, sizeof(transfer_state));
mutex_exit(state_mutex);
} else {
log_msg(LOG_INFO, "failed to get state_mutex");
log_msg(LOG_DEBUG, "failed to get state_mutex");
}
}

Expand Down Expand Up @@ -450,7 +450,7 @@ int main()
delta = absolute_time_diff_us(t_last, t_now);
t_last = t_now;

if (delta > max_delta || delta > 1000000) {
if (delta > max_delta) {
max_delta = delta;
log_msg(LOG_INFO, "core0: max_loop_time=%lld", max_delta);
}
Expand Down Expand Up @@ -484,7 +484,6 @@ int main()

/* Update display every 1000ms */
if (time_passed(&t_display, 1000)) {
log_msg(LOG_DEBUG, "Update display");
update_system_state();
display_status(fanpico_state, cfg);
}
Expand Down
3 changes: 3 additions & 0 deletions src/fanpico.h
Original file line number Diff line number Diff line change
Expand Up @@ -320,6 +320,9 @@ void oled_display_message(int rows, const char **text_lines);
int flash_read_file(char **bufptr, uint32_t *sizeptr, const char *filename, int init_flash);
int flash_write_file(const char *buf, uint32_t size, const char *filename);
int flash_delete_file(const char *filename);
int flash_get_fs_info(size_t *size, size_t *free, size_t *files,
size_t *directories, size_t *filesizetotal);


/* network.c */
void network_init();
Expand Down
117 changes: 117 additions & 0 deletions src/flash.c
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,8 @@

#include "fanpico.h"

extern struct lfs_config pico_cfg;


int flash_read_file(char **bufptr, uint32_t *sizeptr, const char *filename, int init_flash)
{
Expand Down Expand Up @@ -166,3 +168,118 @@ int flash_delete_file(const char *filename)
return ret;
}


int littlefs_scan_dir(const char *path, size_t *files, size_t *dirs, size_t *used)
{
lfs_dir_t dir;
struct lfs_info info;
char *dirname = NULL;
char separator[2] = "/";
int res;
size_t f_count = 0;
size_t d_count = 0;
size_t total = 0;
size_t path_len;

if (!path)
return -1;

/* Check if path ends with "/"... */
path_len = strnlen(path, LFS_NAME_MAX);
if (path_len > 0) {
if (path[path_len - 1] == '/')
separator[0] = 0;
}

log_msg(LOG_DEBUG, "littlefs_scan_dir(%s)", path);
if ((res = lfs_dir_open(&dir, path)) < 0)
return res;

while ((res = lfs_dir_read(&dir, &info) > 0)) {
if (info.type == LFS_TYPE_REG) {
f_count++;
total += info.size;
log_msg(LOG_DEBUG, "lfs: File '%s%s%s': size=%u",
path, separator, info.name, info.size);
}
else if (info.type == LFS_TYPE_DIR) {
/* Skip special directories ("." and "..") */
if (info.name[0] == '.') {
if (info.name[1] == 0)
continue;
if (info.name[1] == '.' && info.name[2] == 0)
continue;
}
d_count++;
log_msg(LOG_DEBUG, "lfs: Directory '%s%s%s'",
path, separator, info.name);
if ((dirname = malloc(LFS_NAME_MAX + 1))) {
res = snprintf(dirname, LFS_NAME_MAX + 1, "%s%s%s",
path, separator, info.name);
if (res > LFS_NAME_MAX)
log_msg(LOG_WARNING, "lfs: filename truncated '%s'", dirname);
littlefs_scan_dir(dirname, files, dirs, used);
free(dirname);
} else {
log_msg(LOG_WARNING, "littlefs_scan_dir: malloc failed");
}
}
else {
log_msg(LOG_NOTICE, "lfs: Unknown directory entry %s%s%s: type=%u, size=%u",
path, separator, info.name, info.type, info.size);
}
}

if (files)
*files += f_count;
if (dirs)
*dirs += d_count;
if (used)
*used += total;
log_msg(LOG_DEBUG, "littlefs_scan_dir(%s): files=%u (total size=%u), dirs=%u",
path, f_count, total, d_count);

return 0;
}


int flash_get_fs_info(size_t *size, size_t *free, size_t *files,
size_t *directories, size_t *filesizetotal)
{
int res;
size_t fs_dirs = 0;
size_t fs_files = 0;
size_t fs_total = 0;
size_t used, used_blocks, fs_size;

if (!size || !free)
return -1;

/* Mount flash filesystem... */
if ((res = pico_mount(false)) < 0) {
log_msg(LOG_ERR, "pico_mount() failed: %d (%s)", res, pico_errmsg(res));
return -2;
}

used_blocks = lfs_fs_size();
used = used_blocks * pico_cfg.block_size;
fs_size = pico_cfg.block_count * pico_cfg.block_size;

if ((res = littlefs_scan_dir("/", &fs_files, &fs_dirs, &fs_total)) < 0)
log_msg(LOG_ERR, "little_fs_scan_dir() failed: %d", res);

if (size)
*size = fs_size;
if (free)
*free = fs_size - used;
if (files)
*files = fs_files;
if (directories)
*directories = fs_dirs;
if (filesizetotal)
*filesizetotal = fs_total;

pico_unmount();

return 0;
}

0 comments on commit 6ca0eeb

Please sign in to comment.