Notes / Firmware Design & Quality
Modules and interfaces: drawing boundaries with headers
The .h shows only what the outside should see, and the .c hides the inside. How to design a module with static, opaque types and an init function.
The shape of a good module
/* motor.h : only what the outside should see */
typedef enum { MOTOR_OK, MOTOR_FAULT } motor_status_t;
void motor_init(void);
void motor_set_duty(int16_t duty_permille); // -1000 to 1000
motor_status_t motor_status(void);
/* motor.c : the inside */
static int16_t s_duty; // cannot be touched from outside
static void apply_pwm(void) { ... }
Principles
- Do not expose global variables with
extern; read and write them through functions. Range checks and logging can then live in one place. staticon internal functions and variables- State the unit in the name or a comment:
duty_permille,speed_rpm,current_mA - A header compiles by itself (it includes what it needs)
- One module, one responsibility: "motor driver" and "speed control" are separate modules
Write the interface first
Write the header before the implementation and agree it with the team, and others can start developing and testing against that interface before the implementation is finished.