|
rcbench
Servo and ESC test bench: panel, IOmcu and shared C
|
The file manager's jobs on the card: copy, move, rename, delete, make a folder, make an empty file, save a text and load a file, one step at a time. More...
#include <stdbool.h>#include <stddef.h>#include <stdint.h>#include "fm_io.h"#include "fm_rules.h"Go to the source code of this file.
Data Structures | |
| struct | fm_job_t |
| One job. The fields are the job's; the screen reads them through fm_job_state(). More... | |
Macros | |
| #define | FM_CHUNK 16384u |
| The chunk the panel copies, saves and loads in: 16KiB. | |
Typedefs | |
| typedef size_t(*) | fm_fill_fn(void *ctx, uint64_t at, uint8_t *dst, size_t cap) |
| The bytes a save writes, asked for one chunk at a time. | |
Enumerations | |
| enum | fm_job_kind_t { FM_JOB_NONE = 0 , FM_JOB_COPY , FM_JOB_MOVE , FM_JOB_RENAME , FM_JOB_DELETE , FM_JOB_MKDIR , FM_JOB_CREATE , FM_JOB_SAVE , FM_JOB_LOAD } |
| What a job does. | |
| enum | fm_job_state_t { FM_JOB_IDLE = 0 , FM_JOB_RUNNING , FM_JOB_DONE , FM_JOB_STOPPED , FM_JOB_FAILED } |
| Where a job stands. More... | |
Functions | |
| fm_err_t | fm_job_copy (fm_job_t *job, const fm_bench_t *bench, unsigned mount, const char *src_dir, const char *name, const char *dst_dir) |
Copy file name of folder src_dir into folder dst_dir under the same name. | |
| fm_err_t | fm_job_move (fm_job_t *job, const fm_bench_t *bench, unsigned mount, const char *src_dir, const char *name, bool is_dir, const char *dst_dir) |
Move file or empty folder name of src_dir into dst_dir. | |
| fm_err_t | fm_job_rename (fm_job_t *job, const fm_bench_t *bench, unsigned mount, const char *dir, const char *name, bool is_dir, const char *new_name) |
Give entry name of folder dir the name new_name. | |
| fm_err_t | fm_job_delete (fm_job_t *job, const fm_bench_t *bench, unsigned mount, const char *dir, const char *name, bool is_dir) |
Delete file or empty folder name of folder dir. | |
| fm_err_t | fm_job_mkdir (fm_job_t *job, const fm_bench_t *bench, unsigned mount, const char *dir, const char *name) |
Make folder name in folder dir. | |
| fm_err_t | fm_job_create (fm_job_t *job, const fm_bench_t *bench, unsigned mount, const char *dir, const char *name) |
Make the empty file name in folder dir. | |
| fm_err_t | fm_job_save (fm_job_t *job, const fm_bench_t *bench, unsigned mount, const char *dir, const char *name, uint64_t len, fm_fill_fn fill, void *fill_ctx) |
Write len bytes from fill as file name of folder dir, through "<name>.NEW" (the file's comment). | |
| fm_err_t | fm_job_load (fm_job_t *job, const fm_bench_t *bench, unsigned mount, const char *dir, const char *name, uint8_t *buf, size_t cap) |
Read file name of folder dir into buf. A read: the gate does not stop it. | |
| fm_job_state_t | fm_job_step (fm_job_t *job, const fm_io_t *io, const fm_bench_t *bench, uint8_t *chunk, size_t size) |
| Run the job's next step. | |
| void | fm_job_cancel (fm_job_t *job) |
| Ask the job to stop at its next chunk. A single call that has started finishes. | |
| fm_job_state_t | fm_job_state (const fm_job_t *job, uint64_t *done, uint64_t *total) |
| Where the job stands. | |
The file manager's jobs on the card: copy, move, rename, delete, make a folder, make an empty file, save a text and load a file, one step at a time.
A job is started by one of the fm_job_*() calls, which check what can be checked without the card: the arguments, the write gate and the places (fm_rules.h), and the names a path and a ".NEW" need. Nothing is read or written until fm_job_step(), which a task of its own calls until the job is no longer FM_JOB_RUNNING: one step is one call of the card, or a few short ones, or one chunk of a copy, a save or a load. The screen reads fm_job_state() for the progress box.
Every overwrite is refused: FAT (File Allocation Table) renames over no name, and no job of the file manager replaces a file it did not write. A target name that is taken is FM_ERR_EXISTS, and so is a ".NEW" of the target that is there already: it can be the only whole copy of a save that was cut short.
COPY writes "<name>.NEW" in the target folder in chunks, puts it on the card (sync) and gives it its name. A copy stopped part way, by CANCEL, by the gate or by a failure, closes both files and removes its ".NEW"; the source is never written.
SAVE is the servo programmer's journal pattern: write "<name>.NEW", sync, close, delete "<name>", rename "<name>.NEW" to "<name>". A "<name>" that was not there when the save opened its ".NEW" is never deleted: one that is there by the rename was made by someone else, and the save fails with FM_ERR_EXISTS, the ".NEW" kept and listed. Between the delete and the rename only "<name>.NEW" holds the text: a card pulled or a power cut there leaves "<name>.NEW" whole and "<name>" gone, and the next listing shows "<name>.NEW" for a RENAME. A rename that fails there keeps "<name>.NEW" for the same reason. A failure before the delete removes "<name>.NEW" and leaves "<name>" as it was.
The rules (fm_allowed(): the write gate, the place, the IOmcu link and the logger's files) are asked again as the job runs, with the bench as fm_job_step() is handed it. A MOVE, RENAME, DELETE or NEW asks them once more right before its single call: queued while SAFE and run once the bench is ARMED or a log is open, it fails (FM_JOB_FAILED) with the refusal and changes nothing. A copy, a save or a load asks before its files are opened and before every chunk: a bench switched to ARMED, a log run opened, or the IOmcu link gone while the fault log is copied stops it there (FM_JOB_STOPPED: FM_ERR_ARMED, FM_ERR_LOGGING, FM_ERR_BUSY), as CANCEL does (FM_ERR_CANCELLED). A single call that has started, and the end of a copy or a save (sync, close, rename), finish. MOVE, RENAME and DELETE find the entry as the kind it was listed as, or refuse with FM_ERR_ARG: a file listed that is a folder now was never asked about as a folder.
A job runs on the mount its names were listed from (fm_io.h hold()): on another card it fails with FM_ERR_CARD_GONE and writes nothing. A card pulled part way fails the job with FM_ERR_CARD_GONE; a ".NEW" written so far stays on that card.
DELETE of a run's log takes its report with it, as LOGS' DELETE does: ATEST042.CSV takes ATEST042.TXT (log_name_report_of()). A report that cannot be deleted fails the job with the card's answer, the log gone and the report there; the caller reads the folder again. A folder is moved or deleted only when it is empty.
Pure C, no ESP-IDF (Espressif Internet-of-Things Development Framework).
SPDX-License-Identifier: MIT
| typedef size_t(*) fm_fill_fn(void *ctx, uint64_t at, uint8_t *dst, size_t cap) |
The bytes a save writes, asked for one chunk at a time.
| ctx | the caller's context |
| at | the offset of the first byte wanted |
| dst | takes the bytes |
| cap | room in dst |
dst, 0 only past the text's end | enum fm_job_state_t |
Where a job stands.
| Enumerator | |
|---|---|
| FM_JOB_IDLE | no job started |
| FM_JOB_RUNNING | fm_job_step() has more to do |
| FM_JOB_DONE | finished |
| FM_JOB_STOPPED | stopped by CANCEL or the gate: err says which |
| FM_JOB_FAILED | refused or failed: err says why |
| void fm_job_cancel | ( | fm_job_t * | job | ) |
Ask the job to stop at its next chunk. A single call that has started finishes.
| job | the job |
| fm_err_t fm_job_copy | ( | fm_job_t * | job, |
| const fm_bench_t * | bench, | ||
| unsigned | mount, | ||
| const char * | src_dir, | ||
| const char * | name, | ||
| const char * | dst_dir ) |
Copy file name of folder src_dir into folder dst_dir under the same name.
| job | the job |
| bench | the gate and the rules; may be NULL |
| mount | the mount the names were listed from |
| src_dir | the source's folder |
| name | the file's name |
| dst_dir | the target folder |
| fm_err_t fm_job_create | ( | fm_job_t * | job, |
| const fm_bench_t * | bench, | ||
| unsigned | mount, | ||
| const char * | dir, | ||
| const char * | name ) |
Make the empty file name in folder dir.
| job | the job |
| bench | the gate and the rules; may be NULL |
| mount | the mount the folder was listed from |
| dir | the folder to make it in |
| name | the new file's name |
| fm_err_t fm_job_delete | ( | fm_job_t * | job, |
| const fm_bench_t * | bench, | ||
| unsigned | mount, | ||
| const char * | dir, | ||
| const char * | name, | ||
| bool | is_dir ) |
Delete file or empty folder name of folder dir.
| job | the job |
| bench | the gate and the rules; may be NULL |
| mount | the mount the names were listed from |
| dir | the folder |
| name | the entry's name |
| is_dir | the entry is a folder |
| fm_err_t fm_job_load | ( | fm_job_t * | job, |
| const fm_bench_t * | bench, | ||
| unsigned | mount, | ||
| const char * | dir, | ||
| const char * | name, | ||
| uint8_t * | buf, | ||
| size_t | cap ) |
Read file name of folder dir into buf. A read: the gate does not stop it.
| job | the job |
| bench | the rules; may be NULL |
| mount | the mount the file was listed from |
| dir | the file's folder |
| name | the file's name |
| buf | takes the bytes |
| cap | room in buf; a larger file is FM_ERR_TOO_BIG |
| fm_err_t fm_job_mkdir | ( | fm_job_t * | job, |
| const fm_bench_t * | bench, | ||
| unsigned | mount, | ||
| const char * | dir, | ||
| const char * | name ) |
Make folder name in folder dir.
| job | the job |
| bench | the gate and the rules; may be NULL |
| mount | the mount the folder was listed from |
| dir | the folder to make it in |
| name | the new folder's name |
| fm_err_t fm_job_move | ( | fm_job_t * | job, |
| const fm_bench_t * | bench, | ||
| unsigned | mount, | ||
| const char * | src_dir, | ||
| const char * | name, | ||
| bool | is_dir, | ||
| const char * | dst_dir ) |
Move file or empty folder name of src_dir into dst_dir.
| job | the job |
| bench | the gate and the rules; may be NULL |
| mount | the mount the names were listed from |
| src_dir | the source's folder |
| name | the entry's name |
| is_dir | the entry is a folder |
| dst_dir | the target folder |
| fm_err_t fm_job_rename | ( | fm_job_t * | job, |
| const fm_bench_t * | bench, | ||
| unsigned | mount, | ||
| const char * | dir, | ||
| const char * | name, | ||
| bool | is_dir, | ||
| const char * | new_name ) |
Give entry name of folder dir the name new_name.
A change of case alone is a rename of one entry, not an overwrite.
| job | the job |
| bench | the gate and the rules; may be NULL |
| mount | the mount the names were listed from |
| dir | the folder |
| name | the entry's name now |
| is_dir | the entry is a folder |
| new_name | its new name |
| fm_err_t fm_job_save | ( | fm_job_t * | job, |
| const fm_bench_t * | bench, | ||
| unsigned | mount, | ||
| const char * | dir, | ||
| const char * | name, | ||
| uint64_t | len, | ||
| fm_fill_fn | fill, | ||
| void * | fill_ctx ) |
Write len bytes from fill as file name of folder dir, through "<name>.NEW" (the file's comment).
| job | the job |
| bench | the gate and the rules; may be NULL |
| mount | the mount the file was read from |
| dir | the file's folder |
| name | the file's name; it need not be there yet |
| len | the text's bytes |
| fill | hands over the bytes |
| fill_ctx | passed to fill |
| fm_job_state_t fm_job_state | ( | const fm_job_t * | job, |
| uint64_t * | done, | ||
| uint64_t * | total ) |
Where the job stands.
| job | the job; NULL is FM_JOB_IDLE |
| done | takes the bytes done; may be NULL |
| total | takes the bytes to do; may be NULL |
| fm_job_state_t fm_job_step | ( | fm_job_t * | job, |
| const fm_io_t * | io, | ||
| const fm_bench_t * | bench, | ||
| uint8_t * | chunk, | ||
| size_t | size ) |
Run the job's next step.
| job | the job |
| io | the card |
| bench | the gate as it stands now; may be NULL |
| chunk | room for one chunk of a copy, a save or a load |
| size | bytes chunk takes; FM_CHUNK on the panel |