Overview
Relevant source files
The following files were used as context for generating this wiki page:
- README.md
- Firmware/App/Version.h
- Firmware/App/Service/DataProc/DP_Shell.cpp
- Firmware/App/Utils/Shell/Shell.h
- Firmware/Vendor/Artery/Application/HAL/HAL_Config.h
- Firmware/App/Service/DataProc/DP_Version.cpp
- Firmware/Vendor/Artery/Platform/AT32F421/Config/mcu_config.h
- Firmware/App/Service/DataProc/Def/Version.h
- Firmware/App/Service/DataProc/Def/Power.h
The DutyCycle project is a "Work-Life Duty Cycle Clock," an embedded system that re-purposes an industrial power meter as a clock to represent the passage of time. The firmware is built for an Artery AT32F421 microcontroller. The project's core concept is to provide a unique and "hardcore poetic" representation of time and life's energy consumption.
The system features a custom time-to-meter-value mapping, user interaction via a single button, and system configuration through a serial command-line interface. The firmware is developed in C/C++ and is compiled using Keil MDK.
Sources: README.md, Firmware/Vendor/Artery/Platform/AT32F421/MDK-ARM/RTE/_AT32F421/RTE_Components.h
System Architecture
The project is composed of custom firmware running on specific hardware. The firmware is structured with a Hardware Abstraction Layer (HAL), application services, and utility modules.
Sources: Firmware/Vendor/Artery/Application/HAL/HAL_Config.h, Firmware/App/Service/HAL/HAL_Def.h
Hardware Components
The firmware is designed to interface with several key hardware components, with pins configured in HAL_Config.h. The central component is the AT32F421 MCU.
The following diagram shows the main hardware components and their connections to the MCU.
This diagram illustrates the primary peripherals controlled by the AT32F421 microcontroller.
Sources: Firmware/Vendor/Artery/Application/HAL/HAL_Config.h:19-35, Firmware/Vendor/Artery/Platform/AT32F421/Config/mcu_config.h:21-25
Firmware Architecture
The firmware uses a layered architecture with a data processing core that communicates using a publisher-subscriber model. Services like Clock, Power, and Ctrl are managed through DataNode objects. A command-line shell provides an interface for configuration and control.
This diagram shows the flow of data and control within the firmware.
Core Features
Time Display Modes
The device displays time by mapping it to the analog meter's needle position. Two modes are available for this mapping.
Sources: README.md:41-65
Power Factor (cos-phi) Mode
This is the default mode, using a non-linear scale.
| Meter Value | Time |
|---|---|
| 0.5 (upper) | 05:00 |
| 0.7 (upper) | 07:00 |
| 0.9 (upper) | 09:00 |
| 1.0 | 12:00 |
| 0.9 (lower) | 21:00 |
| 0.7 (lower) | 01:00 |
| 0.5 (lower) | 04:59 |
Sources: README.md:45-55
Linear Mode
This mode maps time linearly across the meter's scale.
| Meter Value | Time |
|---|---|
| 0 | 00:00 |
| 5 | 05:00 |
| 10 | 10:00 |
| 15 | 15:00 |
| 20 | 20:00 |
| 24 | 23:59 |
Sources: README.md:58-65
Button Operations
A single button provides basic user interaction.
| State | Action | Result |
|---|---|---|
| Off | Single Click | Powers on the device. Default time is firmware compile time. |
| On | Long Press (>10s) | Powers off the device, needle returns to zero. |
| On | Short Click | Displays remaining battery level. |
| On | Fast Double-Click | Toggles mute state for all sounds (button clicks, alarms, etc.). |
Sources: README.md:29-39
Serial Shell Interface
The system can be configured via a serial terminal (115200 8N1). This interface is implemented using a custom shell library. The DP_Shell service initializes this shell and registers commands.
Sources: README.md:23-25, Firmware/App/Utils/Shell/Shell.h, Firmware/App/Service/DataProc/DP_Shell.cpp:193-214
Shell Initialization
The shell is initialized with callbacks for reading from and writing to the serial device, and for getting the system tick.
// Firmware/App/Service/DataProc/DP_Shell.cpp:202-214
shell_init(
/* reader */
[](https://github.com/FASTSHIFT/DutyCycle/blob/HEAD/char*%20data) -> int {
return DP_Shell::_devSerial->read(data, sizeof(char));
},
/* writer */
[](https://github.com/FASTSHIFT/DutyCycle/blob/HEAD/char%20data) {
DP_Shell::_devSerial->write(&data, sizeof(data));
},
/* tick_get */
[]() -> uint32_t {
return HAL::GetTick();
},
nullptr, nullptr);
Sources: Firmware/App/Service/DataProc/DP_Shell.cpp:202-214
Shell Commands
The shell provides commands for system monitoring, configuration, and control.
| Command | Description |
|---|---|
help | Lists all available commands. |
loglevel | Sets the logging verbosity level (0-4). |
ps | Dumps memory usage information. |
publish | Publishes a message to a DataProc topic. |
clock | Gets or sets the system time. |
power | Issues power commands like SHUTDOWN or REBOOT. |
ctrl | Controls the motor and display modes. |
alarm | Configures alarms and sounds. |
kvdb | Manages the key-value database. |
Sources: Firmware/App/Service/DataProc/DP_Shell.cpp:216-224
The following diagram shows the sequence for handling a power --cmd REBOOT command.
Versioning
The firmware contains detailed version information, which is compiled into the binary and can be retrieved at runtime.
Version Information Structure
The Version_Info_t struct holds all version-related strings.
// Firmware/App/Service/DataProc/Def/Version.h:26-42
typedef struct Version_Info {
// ... constructor ...
const char* name;
const char* software;
const char* hardware;
const char* author;
const char* website;
const char* compiler;
const char* buildDate;
const char* buildTime;
} Version_Info_t;
Sources: Firmware/App/Service/DataProc/Def/Version.h:26-42
Version Constants
The primary version details are defined as macros.
| Macro | Value (Example) | File |
|---|---|---|
VERSION_FIRMWARE_NAME | "DutyCycle" | Firmware/App/Version.h |
VERSION_SOFTWARE | "v1.2" | Firmware/App/Version.h |
VERSION_HARDWARE | "v1.3" | Firmware/App/Version.h |
VERSION_AUTHOR_NAME | "_VIFEXTech" | Firmware/App/Version.h |
VERSION_WEBSITE | "..." | Firmware/App/Version.h |
VERSION_COMPILER | "ARMCC v..." | Firmware/App/Service/DataProc/DP_Version.cpp |
__DATE__ | Build Date | Firmware/App/Service/DataProc/DP_Version.cpp |
__TIME__ | Build Time | Firmware/App/Service/DataProc/DP_Version.cpp |
Sources: Firmware/App/Version.h:24-28, Firmware/App/Service/DataProc/DP_Version.cpp:33-47, 107-114
System Configuration
Key system parameters are defined in various configuration header files.
| Parameter | Default Value | Description | File |
|---|---|---|---|
CONFIG_WATCHDOG_TIMEOUT | 10 (seconds) | Watchdog timeout period. | Firmware/App/Config/Config.h |
CONFIG_LOG_SERIAL | Serial | The serial interface used for logging. | Firmware/Vendor/Artery/Application/HAL/HAL_Config.h |
CONFIG_MOTOR_OUT1_PIN | PA2 | Motor driver output pin 1. | Firmware/Vendor/Artery/Application/HAL/HAL_Config.h |
CONFIG_MOTOR_OUT2_PIN | PA3 | Motor driver output pin 2. | Firmware/Vendor/Artery/Application/HAL/HAL_Config.h |
CONFIG_BUZZ_PIN | PB1 | Buzzer control pin. | Firmware/Vendor/Artery/Application/HAL/HAL_Config.h |
CONFIG_BATT_DET_PIN | PB0 | Battery voltage detection pin. | Firmware/Vendor/Artery/Application/HAL/HAL_Config.h |
CONFIG_PWR_EN_PIN | PA6 | Power enable control pin. | Firmware/Vendor/Artery/Application/HAL/HAL_Config.h |
CONFIG_BUTTON_SEL_PIN | PA7 | Button input pin. | Firmware/Vendor/Artery/Application/HAL/HAL_Config.h |
SYSTICK_TICK_FREQ | 1000 Hz | System tick frequency. | Firmware/Vendor/Artery/Platform/AT32F421/Config/mcu_config.h |
SERIAL_RX_BUFFER_SIZE | 64 bytes | RX buffer size for hardware serial. | Firmware/Vendor/Artery/Platform/AT32F421/Config/mcu_config.h |
PWM_RESOLUTION_DEFAULT | 1000 | Default resolution for PWM signals. | Firmware/Vendor/Artery/Platform/AT32F421/Config/mcu_config.h |
PWM_FREQUENCY_DEFAULT | 10000 Hz | Default frequency for PWM signals. | Firmware/Vendor/Artery/Platform/AT32F421/Config/mcu_config.h |
Sources: Firmware/App/Config/Config.h:22-25, Firmware/Vendor/Artery/Application/HAL/HAL_Config.h:19-35, Firmware/Vendor/Artery/Platform/AT32F421/Config/mcu_config.h:18-91