Skip to content

Commit c1494ec

Browse files
Add Frameworks documentation
1 parent c5402b2 commit c1494ec

File tree

2 files changed

+344
-1
lines changed

2 files changed

+344
-1
lines changed

docs/architecture/frameworks.md

Lines changed: 342 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,342 @@
1+
# Frameworks
2+
3+
MicroPythonOS provides a unified framework architecture for accessing system services. All frameworks follow a consistent, simple pattern that makes them easy to discover, use, and extend.
4+
5+
## Overview
6+
7+
Frameworks are centralized services that provide access to system capabilities like audio, networking, camera, sensors, and task management. They follow a **singleton class pattern with class methods**, ensuring a predictable and discoverable API across the entire system.
8+
9+
### Design Philosophy
10+
11+
- **Simple**: Single pattern, no `.get()` calls, clear imports
12+
- **Functional**: Supports all use cases (state management, async operations, callbacks)
13+
- **Harmonized**: All frameworks work identically
14+
- **Discoverable**: IDE autocomplete shows all available methods
15+
16+
## Unified Framework Pattern
17+
18+
All frameworks follow this standardized structure:
19+
20+
```python
21+
class MyFramework:
22+
"""Centralized service for [purpose]."""
23+
24+
_initialized = False
25+
_instance_data = {}
26+
27+
@classmethod
28+
def init(cls, *args, **kwargs):
29+
"""Initialize the framework (call once at startup)."""
30+
cls._initialized = True
31+
# initialization logic
32+
return True
33+
34+
@classmethod
35+
def is_available(cls):
36+
"""Check if framework is available."""
37+
return cls._initialized
38+
39+
@classmethod
40+
def method_name(cls, *args, **kwargs):
41+
"""Framework methods as class methods."""
42+
# implementation
43+
return result
44+
```
45+
46+
### Key Characteristics
47+
48+
| Aspect | Details |
49+
|--------|---------|
50+
| **Instantiation** | No instance creation needed - use class methods directly |
51+
| **Initialization** | Call `Framework.init()` once at startup |
52+
| **State Management** | Use class variables (`_instance_data`, `_initialized`) |
53+
| **API Access** | `Framework.method_name(...)` - no `.get()` needed |
54+
| **Async Support** | Class methods can be async (`async def`) |
55+
| **Testing** | Easy to mock class methods and class variables |
56+
57+
## Available Frameworks
58+
59+
### AudioFlinger
60+
Manages audio playback and recording.
61+
62+
```python
63+
from mpos import AudioFlinger
64+
65+
# Initialize at startup
66+
AudioFlinger.init()
67+
68+
# Use anywhere
69+
AudioFlinger.play_wav("path/to/audio.wav")
70+
AudioFlinger.stop()
71+
```
72+
73+
### DownloadManager
74+
Handles HTTP downloads with session management.
75+
76+
```python
77+
from mpos import DownloadManager
78+
79+
# Initialize at startup
80+
DownloadManager.init()
81+
82+
# Use anywhere
83+
await DownloadManager.download_url("https://example.com/file.bin", "local_path")
84+
```
85+
86+
### ConnectivityManager
87+
Monitors network connectivity status.
88+
89+
```python
90+
from mpos import ConnectivityManager
91+
92+
# Initialize at startup
93+
ConnectivityManager.init()
94+
95+
# Check connectivity
96+
if ConnectivityManager.is_online():
97+
print("Connected to network")
98+
```
99+
100+
### CameraManager
101+
Provides access to camera hardware.
102+
103+
```python
104+
from mpos import CameraManager
105+
106+
# Initialize at startup
107+
CameraManager.init()
108+
109+
# Capture image
110+
image_data = CameraManager.capture_photo()
111+
```
112+
113+
### SensorManager
114+
Manages sensor access (accelerometer, gyroscope, etc.).
115+
116+
```python
117+
from mpos import SensorManager
118+
119+
# Initialize at startup
120+
SensorManager.init()
121+
122+
# Read sensor data
123+
accel_data = SensorManager.read_accelerometer()
124+
```
125+
126+
### TaskManager
127+
Manages async task creation and lifecycle.
128+
129+
```python
130+
from mpos import TaskManager
131+
132+
# Create and track tasks
133+
task = TaskManager.create_task(my_coroutine())
134+
TaskManager.sleep(seconds)
135+
```
136+
137+
### SharedPreferences
138+
Per-app configuration storage (exception to the pattern - instance-based).
139+
140+
```python
141+
from mpos import SharedPreferences
142+
143+
# Create instance per app
144+
prefs = SharedPreferences("com.example.myapp")
145+
146+
# Store and retrieve values
147+
prefs.set_string("key", "value")
148+
value = prefs.get_string("key", default="default")
149+
```
150+
151+
## Framework Initialization
152+
153+
Frameworks should be initialized once at system startup in the board initialization file:
154+
155+
```python
156+
# In board/your_board.py
157+
from mpos import (
158+
AudioFlinger,
159+
DownloadManager,
160+
ConnectivityManager,
161+
CameraManager,
162+
SensorManager,
163+
TaskManager
164+
)
165+
166+
def init_frameworks():
167+
"""Initialize all frameworks."""
168+
AudioFlinger.init()
169+
DownloadManager.init()
170+
ConnectivityManager.init()
171+
CameraManager.init()
172+
SensorManager.init()
173+
TaskManager.init()
174+
```
175+
176+
## Creating New Frameworks
177+
178+
When creating a new framework, follow this template:
179+
180+
```python
181+
"""
182+
MyFramework - [Brief description of what this framework does]
183+
"""
184+
185+
class MyFramework:
186+
"""Centralized service for [purpose]."""
187+
188+
_initialized = False
189+
_instance_data = {}
190+
191+
@classmethod
192+
def init(cls, **kwargs):
193+
"""
194+
Initialize the framework.
195+
196+
Args:
197+
**kwargs: Configuration options
198+
199+
Returns:
200+
bool: True if initialization successful
201+
"""
202+
if cls._initialized:
203+
return True
204+
205+
# Perform initialization
206+
cls._instance_data['config'] = kwargs
207+
cls._initialized = True
208+
return True
209+
210+
@classmethod
211+
def is_available(cls):
212+
"""Check if framework is available."""
213+
return cls._initialized
214+
215+
@classmethod
216+
def your_method(cls, arg1, arg2):
217+
"""
218+
Do something.
219+
220+
Args:
221+
arg1: First argument
222+
arg2: Second argument
223+
224+
Returns:
225+
Result of operation
226+
"""
227+
if not cls.is_available():
228+
raise RuntimeError("MyFramework not initialized")
229+
230+
# Implementation
231+
return result
232+
```
233+
234+
### Checklist for New Frameworks
235+
236+
- [ ] Inherit from no base class (use class methods only)
237+
- [ ] Include `_initialized` class variable
238+
- [ ] Include `_instance_data` class variable for state
239+
- [ ] Implement `init()` classmethod for initialization
240+
- [ ] Implement `is_available()` classmethod to check status
241+
- [ ] All public methods are classmethods
242+
- [ ] Add docstrings to all methods
243+
- [ ] Import in `mpos/__init__.py`
244+
- [ ] Add to board initialization files
245+
- [ ] Write tests in `MicroPythonOS/tests/`
246+
247+
## Import Pattern
248+
249+
All frameworks are imported consistently as classes:
250+
251+
```python
252+
from mpos import (
253+
AudioFlinger,
254+
CameraManager,
255+
ConnectivityManager,
256+
DownloadManager,
257+
SensorManager,
258+
SharedPreferences,
259+
TaskManager,
260+
WifiService,
261+
PackageManager,
262+
)
263+
```
264+
265+
## Benefits of Harmonization
266+
267+
| Aspect | Before | After |
268+
|--------|--------|-------|
269+
| **API Consistency** | 5 different patterns | 1 unified pattern |
270+
| **Learning Curve** | High (multiple patterns) | Low (single pattern) |
271+
| **Import Clarity** | Mixed class/module imports | All consistent class imports |
272+
| **IDE Support** | Partial autocomplete | Full autocomplete |
273+
| **Testing** | Varies by framework | Consistent mocking approach |
274+
| **Documentation** | Per-framework docs | Single pattern reference |
275+
| **Onboarding** | Confusing for new developers | Clear and straightforward |
276+
277+
## Exception: SharedPreferences
278+
279+
`SharedPreferences` is intentionally instance-based rather than a singleton class method framework because:
280+
281+
1. **Per-app isolation**: Each app needs its own configuration namespace
282+
2. **Multiple instances**: Different apps may need different preference stores
283+
3. **Flexibility**: Apps can create multiple preference instances if needed
284+
285+
```python
286+
# Each app creates its own instance
287+
prefs = SharedPreferences("com.example.myapp")
288+
prefs.set_string("theme", "dark")
289+
```
290+
291+
## Best Practices
292+
293+
### Do's
294+
295+
✅ Call `Framework.init()` once at system startup
296+
✅ Use class methods directly without `.get()`
297+
✅ Check `is_available()` before using framework
298+
✅ Use class variables for state management
299+
✅ Document initialization requirements
300+
✅ Write tests for framework behavior
301+
302+
### Don'ts
303+
304+
❌ Create instances of framework classes
305+
❌ Call `.get()` to access frameworks
306+
❌ Mix module-level functions with class methods
307+
❌ Store framework state in global variables
308+
❌ Skip initialization in board files
309+
❌ Use different patterns for different frameworks
310+
311+
## Testing Frameworks
312+
313+
Frameworks are easy to test due to their class method design:
314+
315+
```python
316+
import unittest
317+
from mpos import MyFramework
318+
319+
class TestMyFramework(unittest.TestCase):
320+
def setUp(self):
321+
"""Reset framework state before each test."""
322+
MyFramework._initialized = False
323+
MyFramework._instance_data = {}
324+
325+
def test_initialization(self):
326+
"""Test framework initialization."""
327+
self.assertFalse(MyFramework.is_available())
328+
MyFramework.init()
329+
self.assertTrue(MyFramework.is_available())
330+
331+
def test_method(self):
332+
"""Test framework method."""
333+
MyFramework.init()
334+
result = MyFramework.your_method("arg1", "arg2")
335+
self.assertEqual(result, expected_value)
336+
```
337+
338+
## See Also
339+
340+
- [System Components](system-components.md): Overview of all system components
341+
- [Architecture Overview](overview.md): High-level design principles
342+
- [App Development Guide](../apps/index.md): How to use frameworks in apps

docs/architecture/index.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
# Architecture
22

3-
Learn about the design and structure of MicroPythonOS, inspired by Androids "thin" OS model.
3+
Learn about the design and structure of MicroPythonOS, inspired by Android's "thin" OS model.
44

55
- [Overview](overview.md): High-level architecture and design principles.
66
- [System Components](system-components.md): Key files and their roles.
7+
- [Frameworks](frameworks.md): Unified framework pattern for system services.
78
- [Filesystem Layout](filesystem.md): Directory structure for apps and data.

0 commit comments

Comments
 (0)