These are general guidelines all the C code should follow within this repository.
Naming Convention
- Variable names should be snake case (e.g.,
packet_buffer
, not packetBuffer
).
- Cross-file variable/function names should the namespace conventions in:
docs/C_Namespaces.md
- E.g., all EPS-related functions should start with
EPS_
.
- Include guards should follow the style
INCLUDE_GUARD__FILE_NAME_H
.
Best Coding Practices
- Please use braces around all
if/else/while/for
, even if the body is only a single line.
- Includes should go in
.c
files and not in .h
files, if possible. This limits the scope of the functions.
- For all systems, we must differentiate at least between functions which are meant to be used only internally to that system (e.g.,
FLASH_activate_chip_select()
) and functions which are meant to be used from anywhere in the codebase (e.g., LFS_read_file_from_filesystem()
). They must go in separate files (e.g., named eps_drivers.c
/eps_internal_drivers.c
for internal functions; and eps_helpers.c
/eps_commands.c
/eps_datatypes.h
for external functions).
- Do not commit changes to
main.c
to git, ever. Instead, create a file called your_subsystem_testing.c
in the folder with the rest of the code you're working on, if you need to use test code. You can call that code from a telecommand or from a single line in main.c.
- Everything must be allocated on the stack! No heap allocation. No using
free()
. No using malloc()
.
- If you create a new telecommand parsing related function, you must create unit tests for it.
- No null pointers. No void pointers.
Error Handling
- When a function runs successfully, it should return
0
. If it errors, it should return a non-zero value.
- The return value from all functions must be used/checked. Errors must be propagated up the call stack. All HAL functions must have their return values checked.
- Consider whether each error is fatal (e.g., "failed to mount filesystem"), vs. non-fatal (e.g., "tried to mount the filesystem, but it's already mounted").
Documentation
- Please use the comment prefixes
// TODO:
and // FIXME:
to denote things you need to come back to/check on later.
- Functions must have docstrings, like this:
uint8_t function_name(int input1, int input2, int *output_arr, int output_arr_len) {
}
For telecommands executors (TCMDEXEC_
functions), the docstring should be formatted to describle each argument, in this exact format. For example:
uint8_t TCMDEXEC_fs_write_file(const char *args_str, TCMD_TelecommandChannel_enum_t tcmd_channel,
char *response_output_buf, uint16_t response_output_buf_len) {
char arg_file_name[64] = {0};
char arg_file_content[100] = {0};
const uint8_t parse_file_content_result =
TCMD_extract_string_arg(args_str, 1, arg_file_content,
sizeof(arg_file_content));
}
uint8_t TCMD_extract_string_arg(const char *str, uint8_t arg_index, char *result, uint16_t result_max_len)
Extracts the nth comma-separated argument from the input string, assuming it's a string.
Definition telecommand_args_helpers.c:178