SDK Overviewο
The UNA Watch SDK provides a comprehensive suite of tools, libraries, and interfaces for building high-performance wearable applications. For platform architecture overview, see platform overview.
Key Componentsο
Core Interfaces: Type-safe APIs for system services, communication, and hardware access.
Message System: High-performance inter-process communication (IPC) framework.
Sensor APIs: Simplified access to PPG, IMU, and GNSS sensors.
File System: Multi-volume storage management (Flash, USB, External).
Build Tools: Automated scripts for compilation and
.uapppackaging.Simulator: Desktop-based environment for rapid prototyping and testing.
SDK Setup and Build Referenceο
To start using this SDK, see the SDK setup
SDK Project Structureο
una-sdk/
βββ Libs/
β βββ Header/SDK/ # Public SDK headers
β β βββ Interfaces/ # Core API interfaces
β β βββ Messages/ # Message type definitions
β β βββ SensorLayer/ # Sensor data structures
β β βββ Kernel/ # Kernel provider interfaces
β β βββ Port/ # Platform port headers (TouchGFX)
β β βββ Simulator/ # Simulator headers (mocks, sim sensors)
β β βββ Wrappers/ # Standard library wrappers
β βββ Source/ # SDK implementation
β βββ Port/TouchGFX/ # TouchGFX integration
β βββ Simulator/ # Mock kernel and desktop simulator runtime
βββ ThirdParty/ # Vendored dependencies
β βββ coreJSON/ # JSON parsing library
β βββ tinycbor_version/ # CBOR encoder/decoder
β βββ touchgfx/ # TouchGFX framework (sources + prebuilt libs)
βββ Utilities/Scripts/ # Build and packaging tools
βββ Examples/ # Sample reference applications
βββ cmake/ # CMake toolchain and helpers
βββ Docs/ # Documentation and tutorials
High-Level Utilitiesο
In addition to core interfaces, the SDK provides several high-level utilities to simplify common tasks:
GSModel & GSBridge (GUI-Service Communication)ο
The GSModel provides a type-safe, bidirectional bridge between the GUI and Service processes using std::variant and std::visit. This is the recommended way to handle application-level events between processes.
// Define events in G2SEvents.hpp and S2GEvents.hpp
// In Service:
GSModel model(serviceHandler);
model.process(); // Drain GUI->Service events
// In GUI:
IGUIModel* bridge = ...;
bridge->post(G2SEvent::SomeEvent{data});
Glance UI Systemο
A lightweight UI framework for the 240x60 pixel notification area. It uses a Form to manage GlanceControl items like Text, Image, Line, and Rectangle. This system is optimized for low-power notification display.
SDK::Glance::Form form(240, 60);
auto text = form.createText();
text.init({0, 0}, {240, 20}, "Notification", FONT_SMALL, COLOR_WHITE);
SDK::Fit (Fitness Data)ο
A native FIT-format encoder for exporting activity data in the standard format compatible with major fitness platforms (no external dependency). Define each messageβs fields from the FIT profile, then stream values through the builder.
SDK::Fit::FitWriter fit(file);
fit.begin(/*profileVersion=*/0);
fit.defineMessage(0, SDK::Fit::mesgNum(SDK::Fit::MesgNum::Record),
{SDK::Fit::field::Record::Timestamp, SDK::Fit::field::Record::HeartRate});
fit.data(0).u32(timestamp).u8(heartRate).write();
fit.finish();
TrackMapBuilder (GPS Visualization)ο
Creates a simplified pixel-based map representation of GPS tracks. It handles coordinate scaling, rotation, and filtering to fit a track into a circular or rectangular display area.
SDK::TrackMapBuilder builder;
builder.addPoint({lat, lon});
auto screenMap = builder.build(radiusPx);
Serialization (CBOR & JSON)ο
The SDK includes stream-based readers and writers for both CBOR and JSON formats, optimized for memory-constrained environments. These are used for settings persistence and BLE data exchange.
CBOR:
CborStreamReader,CborStreamWriter(efficient binary format)JSON:
JsonStreamReader,JsonStreamWriter(human-readable format)
Signal Processing & Toolsο
Filters: Basic signal processing filters like
FilterSmoothfor noise reduction.FixedQueue: A template-based fixed-capacity queue for efficient data buffering.
CircularBuffer: A thread-safe circular buffer implementation integrated with kernel synchronization primitives.
SwTimer: High-level software timers for application-level periodic tasks.
python app_packer/app_packer.py -e <elf_file> -o <output_dir> -v <version>
ELF Processing: Parses compiled ELF files
Package Creation: Generates .uapp container files
Metadata Injection: Embeds version and configuration data
App Merging Script (app_merging.py)ο
python app_merging.py -name <name> -type <Activity|Utility|Glance|Clockface> \
-autostart -header -normal_icon <60x60.png> \
-small_icon <30x30.png> -appid <16hex> -appver <A.B.C> \
-scripts <SDK/Utilities/Scripts>
App Metadata: Defines app properties and capabilities
Icon Processing: Converts and embeds PNG icons
Type Configuration: Sets app behavior and permissions
ID Assignment: Unique application identifiers
Build Integration Scriptsο
CMake Integration: Post-build scripts for automatic
.uapppackagingVersion Management: Automatic version incrementing
Dependency Checking: Validates build prerequisites
SDK Interfacesο
The SDK provides a comprehensive set of interfaces that apps use to interact with the watchβs kernel and hardware:
IAppComm (Communication Interface)ο
class IAppComm {
public:
virtual uint32_t getProcessId() const = 0;
virtual bool getMessage(MessageBase*& msg, uint32_t timeoutMs = 0xFFFFFFFF) = 0;
virtual void sendResponse(MessageBase* msg) = 0;
virtual void releaseMessage(MessageBase* msg) = 0;
virtual bool sendMessage(MessageBase* msg, uint32_t timeoutMs = 0) = 0;
template<typename T>
T* allocateMessage() { ... }
};
Process Identity: Unique process identifier assigned by kernel.
Message Reception: Receive messages with configurable timeout (blocking by default).
Response Handling: Send responses for request-response patterns.
Memory Management: Explicit message release back to kernel pool.
Type-safe Allocation: Template-based message allocation from kernel pools.
ISystem (System Services Interface)ο
class ISystem {
public:
virtual void exit(int status = 0) = 0;
virtual uint32_t getTimeMs() = 0;
virtual void delay(uint32_t ms) = 0;
virtual void yield() = 0;
};
Lifecycle: Terminate the application with an exit status.
Timing: Get system time in milliseconds and perform millisecond-precision delays.
Scheduling: Yield execution back to the kernel.
IFileSystem (Storage Interface)ο
class IFileSystem {
public:
virtual bool mkdir(const char* path) = 0;
virtual std::unique_ptr<IFile> file(const char* path) = 0;
virtual std::unique_ptr<IDirectory> dir(const char* path) = 0;
virtual bool exist(const char* path) const = 0;
virtual bool remove(const char* path) = 0;
virtual bool rename(const char* oldPath, const char* newPath) = 0;
virtual bool copy(const char* oldPath, const char* newPath) = 0;
virtual bool objectInfo(const char* path, ObjectInfo& item) const = 0;
};
Object-Oriented API: Uses
IFileandIDirectoryobjects for file and directory operations.Path Management: Support for internal flash (
0:/), external storage (1:/), and USB (2:/).File Operations: Standard read/write/seek via
IFileinterface.Metadata: Retrieve object information (size, type, timestamps).
ILogger (Debugging Interface)ο
class ILogger {
public:
virtual void printf(const char *format, ...) = 0;
virtual void vprintf(const char *format, va_list args) = 0;
virtual void mvprintf(const char *level, const char *module_name,
const char *func, int line, const char *fmt, va_list args) = 0;
};
Formatted Output: Standard
printf-style logging.Metadata Support: Log with level, module name, function, and line number.
ISensorManager (Sensor Interface)ο
class ISensorManager {
public:
virtual SDK::Interface::ISensorDriver* getDefaultSensor(SDK::Sensor::Type type) = 0;
virtual std::vector<SDK::Interface::ISensorDriver*> getSensorList(SDK::Sensor::Type type) = 0;
};
Sensor Discovery: Retrieve default sensors or a list of available sensors by type.
Driver-based Access: Interact with sensors via the
ISensorDriverinterface.
IGlance (Glance Application Interface)ο
class IGlance {
public:
virtual Info glanceGetInfo() = 0;
virtual void glanceUpdate() = 0;
virtual void glanceClose() = 0;
};
Lifecycle Management: Methods for initializing, updating, and closing glance views.
Meta-information: Retrieve control information and alternative names for the glance.
Message System Architectureο
Message Types and Rangesο
The SDK uses a structured message system for inter-process communication:
Range |
Type |
Purpose |
|---|---|---|
0x01010000 - 0x01060000 |
Commands |
Kernel-to-app directives (response expected) |
0x01070000 - 0x01090000 |
App Control |
App-to-kernel lifecycle requests |
0x02010000 - 0x020A0000 |
System/Hardware |
Requests for system info, display, backlight, etc. |
0x03010000 - 0x03040000 |
Events |
System-level notifications (fire-and-forget) |
0x030A0000 - 0x030E0000 |
Glances |
Glance-specific updates and events |
0x03100000 - 0x03180000 |
Sensors |
Sensor discovery and data events |
0x00000000 - 0x0000FFFF |
Custom |
Application-specific internal communication |
Key System Messagesο
// Application Control
COMMAND_APP_RUN // Start application
COMMAND_APP_STOP // Stop application
REQUEST_APP_TERMINATE // App requesting its own termination
// System Info & Settings
REQUEST_BATTERY_STATUS // Get battery level
REQUEST_SYSTEM_SETTINGS // Get watch settings
REQUEST_SYSTEM_INFO // Get firmware version, device name
// Hardware Control
REQUEST_DISPLAY_CONFIG // Get screen dimensions
REQUEST_BACKLIGHT_SET // Set screen brightness
REQUEST_VIBRO_PLAY // Trigger vibration
REQUEST_BUZZER_PLAY // Trigger sound
// Sensor Messages
REQUEST_SENSOR_LAYER_GET_DEFAULT // Request default sensor
REQUEST_SENSOR_LAYER_CONNECT // Start sensor sampling
EVENT_SENSOR_LAYER_DATA // Asynchronous sensor data update
Message Processing Patternο
// App message handling loop
void Service::run() {
MessageBase* msg = nullptr;
while (comm->getMessage(msg, 100)) { // 100ms timeout
switch (msg->getType()) {
case MessageType::EVENT_SENSOR_LAYER_DATA:
handleSensorData(static_cast<SensorDataEvent*>(msg));
break;
case MessageType::COMMAND_APP_STOP:
handleStopCommand(static_cast<StopCommand*>(msg));
break;
// ... other message types
}
// Send response if required
if (msg->needsResponse()) {
comm->sendResponse(msg);
}
// Always release message when done
comm->releaseMessage(msg);
}
}
Simulator Environmentο
The SDK includes a comprehensive simulator for app development and testing:
Simulator Featuresο
Hardware Emulation: Mock implementations of all watch hardware
Sensor Simulation: Realistic sensor data generation
UI Testing: TouchGFX simulator integration
Debugging Tools: Enhanced logging and breakpoint support
Simulator Architectureο
// Mock hardware interfaces
class MockLcd : public ILcd {
void setPixel(int x, int y, Color color) override {
// Render to simulator window
simulatorWindow.setPixel(x, y, color);
}
};
class MockSensorManager : public ISensorManager {
bool requestDefaultSensor(SensorType type, SensorHandle& handle) override {
// Create simulated sensor
return sensorSimulator.createSensor(type, handle);
}
};
Development Workflow with Simulatorο
Code Development: Write app logic using SDK interfaces
Compile for Simulator: Build with simulator target
Run Tests: Execute automated test suites
UI Testing: Interact with simulated watch interface
Debugging: Step through code with full debugger support
Third-Party Libraries & Standard Libraryο
Core Componentsο
coreJSON: Lightweight JSON parsing for settings and data.
Shared libc++: A memory-optimized standard C++ library shared across all applications to minimize binary size.
FreeRTOS: The underlying real-time operating system (kernel-side).
TouchGFX: UI framework for embedded systems.
Integration Pointsο
Automatic Inclusion: Libraries linked automatically in build process
Header-Only: Many utilities available as headers only
Namespace Isolation: Prevent symbol conflicts
Version Management: Controlled library versions for compatibility
Development Best Practicesο
Memory Managementο
Pool Allocation: Use kernel message pools for IPC
RAII Pattern: Automatic resource cleanup
Stack Awareness: Monitor stack usage in constrained environment
Performance Optimizationο
Event-Driven Design: Avoid polling, use callbacks
Message Batching: Group related operations
Sensor Optimization: Configure appropriate sampling rates
Error Handlingο
Graceful Degradation: Handle missing hardware gracefully
Timeout Management: Prevent infinite waits
Logging: Comprehensive error reporting
Testingο
Unit Tests: Test individual components
Integration Tests: Validate IPC communication
Simulator Validation: Test on simulated hardware
Hardware Testing: Final validation on real device
SDK Version Compatibilityο
Versioning Schemeο
Major Version: Breaking API changes
Minor Version: New features, backward compatible
Patch Version: Bug fixes and improvements