This commit is contained in:
2026-01-19 16:19:41 +01:00
commit edd3e96591
301 changed files with 36763 additions and 0 deletions

View File

@@ -0,0 +1,5 @@
idf_component_register(
SRCS "com/data_pool.cpp"
INCLUDE_DIRS "com"
REQUIRES logger
)

View File

@@ -0,0 +1,47 @@
/**
* @file data_pool.cpp
* @brief DataPool component implementation
* @author Mahmoud Elmohtady
* @company Nabd solutions - ASF
* @copyright Copyright (c) 2025
*/
#include "data_pool.hpp"
#include "logger.hpp"
static const char* TAG = "DataPool";
DataPool::DataPool()
: m_isInitialized(false)
{
}
DataPool::~DataPool()
{
deinitialize();
}
bool DataPool::initialize()
{
// TODO: Implement initialization
m_isInitialized = true;
ASF_LOGI(TAG, 4900, asf::logger::Criticality::LOW, "DataPool initialized successfully");
return true;
}
bool DataPool::deinitialize()
{
if (!m_isInitialized)
{
return false;
}
// TODO: Implement deinitialization
m_isInitialized = false;
return true;
}
bool DataPool::isInitialized() const
{
return m_isInitialized;
}

View File

@@ -0,0 +1,33 @@
/**
* @file data_pool.hpp
* @brief DataPool component header
* @author Mahmoud Elmohtady
* @company Nabd solutions - ASF
* @copyright Copyright (c) 2025
*/
#ifndef DATA_POOL_HPP
#define DATA_POOL_HPP
#include <cstdint>
/**
* @brief DataPool class
*
* Component description goes here.
*/
class DataPool
{
public:
DataPool();
~DataPool();
bool initialize();
bool deinitialize();
bool isInitialized() const;
private:
bool m_isInitialized;
};
#endif // DATA_POOL_HPP

View File

@@ -0,0 +1,2 @@
ID,Component,Level,Criticality,Message
4900,DataPool,INFO,Low,DataPool initialized successfully
1 ID Component Level Criticality Message
2 4900 DataPool INFO Low DataPool initialized successfully

View File

@@ -0,0 +1,34 @@
import sys
import os
import time
folder_path = os.path.abspath(os.path.join("components", "system_tests"))
if folder_path not in sys.path:
sys.path.append(folder_path)
from scan_serial import ESP32Runner
def test_data_pool_initialize():
runner = ESP32Runner(mode="SIM", port="COM9")
runner.start()
print("--- QEMU Runner Started ---", flush=True)
try:
start_time = time.time()
while time.time() - start_time < 30:
line = runner.get_line(timeout=1.0)
if line:
print(line, flush=True)
if "DataPool initialized successfully" in line:
print("SUCCESS CRITERIA MET!", flush=True)
return 0
if runner.process.poll() is not None:
print(f"Process exited with code: {runner.process.returncode}", flush=True)
return 1
finally:
runner.stop()
print("Done.", flush=True)
return 1
if __name__ == "__main__":
exit_code = test_data_pool_initialize()
sys.exit(exit_code)

View File

@@ -0,0 +1,14 @@
<?xml version="1.0" encoding="UTF-8"?>
<test_scenario>
<!-- The configuration for the test environment. -->
<!-- Available configurations: SIMULATE, HIL -->
<config>SIMULATE</config>
<test_case>
<test_case_id>DATA_POOL_INIT_TEST</test_case_id>
<!-- The main command that executes the test itself. -->
<test_exec>python components/application_layer/DP_stack/data_pool/test/data_pool_init_test.py</test_exec>
</test_case>
</test_scenario>

View File

@@ -0,0 +1,40 @@
/**
* @file test_data_pool.cpp
* @brief Unit tests for DataPool component
* @author Mahmoud Elmohtady
* @company Nabd solutions - ASF
* @copyright Copyright (c) 2025
*/
#include "unity.h"
#include "data_pool.hpp"
extern "C" {
void setUp(void)
{
}
void tearDown(void)
{
}
void test_data_pool_initialize(void)
{
DataPool comp;
bool result = comp.initialize();
TEST_ASSERT_TRUE(result);
TEST_ASSERT_TRUE(comp.isInitialized());
}
void test_data_pool_deinitialize(void)
{
DataPool comp;
comp.initialize();
bool result = comp.deinitialize();
TEST_ASSERT_TRUE(result);
TEST_ASSERT_FALSE(comp.isInitialized());
}
} // extern "C"

View File

@@ -0,0 +1,5 @@
idf_component_register(
SRCS "com/persistence.cpp"
INCLUDE_DIRS "com"
REQUIRES logger
)

View File

@@ -0,0 +1,257 @@
# Persistence Component Specification
**Component ID:** COMP-PERSIST
**Version:** 1.0
**Date:** 2025-01-19
**Location:** `application_layer/DP_stack/persistence/`
## 1. Purpose
The Persistence component provides the sole interface for persistent storage access. It abstracts storage media (SD card, NVM), manages serialization/deserialization, implements wear-aware storage, and ensures data integrity.
## 2. Responsibilities
### 2.1 Primary Responsibilities
- Abstract storage media (SD card, NVM)
- Serialize/deserialize structured data
- Manage wear-aware storage (SD card)
- Ensure data integrity
- Coordinate data flush operations
### 2.2 Non-Responsibilities
- Business logic (data semantics owned by components)
- Hardware access (delegated to storage drivers)
- Data validation (components validate before persistence)
## 3. Public API
### 3.1 Sensor Data Persistence
```c
/**
* @brief Write sensor data record
* @param record Sensor data record
* @return true if written, false on error
*/
bool persistence_writeSensorData(const sensor_data_record_t* record);
/**
* @brief Read sensor data records
* @param records Output buffer
* @param count Input: buffer size, Output: records read
* @param start_time Start timestamp filter (0 for all)
* @param end_time End timestamp filter (0 for all)
* @return true if read successful, false on error
*/
bool persistence_readSensorData(sensor_data_record_t* records, size_t* count, uint64_t start_time, uint64_t end_time);
```
### 3.2 Diagnostic Persistence
```c
/**
* @brief Write diagnostic event
* @param event Diagnostic event
* @return true if written, false on error
*/
bool persistence_writeDiagnostic(const diagnostic_event_t* event);
/**
* @brief Read diagnostic events
* @param events Output buffer
* @param count Input: buffer size, Output: events read
* @param filter Filter criteria (severity, component, etc.)
* @return true if read successful, false on error
*/
bool persistence_readDiagnostics(diagnostic_event_t* events, size_t* count, const diag_filter_t* filter);
/**
* @brief Clear diagnostic log
* @return true if cleared, false on error
*/
bool persistence_clearDiagnostics(void);
```
### 3.3 Machine Constants Persistence
```c
/**
* @brief Write machine constants
* @param mc Machine constants structure
* @return true if written, false on error
*/
bool persistence_writeMachineConstants(const machine_constants_t* mc);
/**
* @brief Read machine constants
* @param mc Output buffer
* @return true if read successful, false on error
*/
bool persistence_readMachineConstants(machine_constants_t* mc);
```
### 3.4 Flush Operations
```c
/**
* @brief Flush all critical data to storage
* @return true if flushed, false on error
*/
bool persistence_flushCriticalData(void);
/**
* @brief Check if flush is complete
* @return true if flush complete, false otherwise
*/
bool persistence_isFlushComplete(void);
/**
* @brief Get flush progress (0-100%)
* @return Flush progress percentage
*/
uint8_t persistence_getFlushProgress(void);
```
### 3.5 Storage Status
```c
/**
* @brief Check storage availability
* @param storage_type Storage type (SD_CARD, NVM)
* @return true if available, false otherwise
*/
bool persistence_isStorageAvailable(storage_type_t storage_type);
/**
* @brief Get storage usage statistics
* @param storage_type Storage type
* @param stats Output statistics
* @return true if retrieved, false on error
*/
bool persistence_getStorageStats(storage_type_t storage_type, storage_stats_t* stats);
```
## 4. Data Types
### 4.1 Storage Types
```c
typedef enum {
STORAGE_TYPE_SD_CARD = 0,
STORAGE_TYPE_NVM,
STORAGE_TYPE_COUNT
} storage_type_t;
```
### 4.2 Storage Statistics
```c
typedef struct {
uint64_t total_bytes;
uint64_t used_bytes;
uint64_t free_bytes;
uint32_t write_count;
bool is_healthy;
} storage_stats_t;
```
## 5. Threading Model
- **Owner Task:** Persistence Task (MEDIUM priority)
- **Thread Safety:** Thread-safe (all operations protected by mutex)
- **Blocking Operations:** Storage I/O operations (bounded by timing requirements)
- **ISR Access:** Not allowed (blocking operations)
## 6. Resource Ownership
- **SD Card Driver:** Owned exclusively by Persistence component
- **NVM Driver:** Owned exclusively by Persistence component
- **Storage Mutex:** Protects concurrent access
- **Write Buffers:** Pre-allocated static buffers
## 7. Error Model
### 7.1 Error Conditions
| Error | Condition | Response |
|-------|-----------|----------|
| `PERSIST_ERR_STORAGE_FULL` | Storage full | Trigger retention policy, log warning |
| `PERSIST_ERR_STORAGE_FAILED` | Storage failure | Enter SD_DEGRADED state, log error |
| `PERSIST_ERR_SERIALIZATION` | Serialization failure | Return false, log error |
| `PERSIST_ERR_INTEGRITY_CHECK` | Integrity check failed | Return false, log error, attempt recovery |
### 7.2 Diagnostics Emitted
- `DIAG-ST-PERSIST-0001`: Storage write failure (WARNING)
- `DIAG-ST-PERSIST-0002`: Storage full (WARNING)
- `DIAG-ST-PERSIST-0003`: Storage corruption detected (ERROR)
- `DIAG-ST-PERSIST-0004`: Storage failure (FATAL)
## 8. State-Dependent Behavior
### 8.1 All States
- Read operations allowed
- Write operations allowed (with restrictions)
### 8.2 TEARDOWN State
- Only authorized writes allowed (critical data flush)
- Read operations allowed
### 8.3 SD_DEGRADED State
- SD card writes disabled
- NVM writes allowed
- Read operations allowed (if storage accessible)
## 9. Dependencies
### 9.1 Required Components
- **SD Card Driver:** For SD card access
- **NVM Driver:** For NVM access
- **STM:** For state queries and transitions
- **Logger:** For diagnostic logging
### 9.2 Required Interfaces
- SD Card Driver interface
- NVM Driver interface
- STM state query interface
- Logger interface
## 10. Acceptance Tests
- **T-PERSIST-001:** Sensor data write/read operations
- **T-PERSIST-002:** Diagnostic event write/read operations
- **T-PERSIST-003:** Machine constants write/read operations
- **T-PERSIST-004:** Data flush completes within 200ms
- **T-PERSIST-005:** Storage failure handling (SD_DEGRADED state)
- **T-PERSIST-006:** Data integrity verification
- **T-PERSIST-007:** Wear-aware storage management
## 11. Traceability
- **SWR-DATA-001:** Persistent timestamped sensor data
- **SWR-DATA-004:** DP component as sole persistence interface
- **SWR-DATA-005:** Storage access isolation
- **SWR-DATA-006:** Structured data serialization
- **SWR-DATA-007:** Data flush before teardown
- **SWR-DATA-008:** Data integrity during updates
- **SWR-DATA-009:** Persistence verification
- **SWR-DATA-012:** SD card failure handling
- **SWR-DATA-013:** Wear-aware storage management
- **CFC-ARCH-01:** Hardware access via drivers only
- **CFC-DATA-01:** Single source of truth
- **CFC-DATA-02:** Data consistency during transitions
## 12. Implementation Notes
- Serialization SHALL use a well-defined format (e.g., CBOR, MessagePack, or custom binary)
- SD card writes SHALL be wear-aware (wear leveling, write frequency limits)
- Data integrity SHALL be verified using checksums or hashes
- Flush operations SHALL be coordinated with STM for state transitions
- Storage failures SHALL trigger state transitions (SD_DEGRADED)

View File

@@ -0,0 +1,47 @@
/**
* @file persistence.cpp
* @brief Persistence component implementation
* @author Mahmoud Elmohtady
* @company Nabd solutions - ASF
* @copyright Copyright (c) 2025
*/
#include "persistence.hpp"
#include "logger.hpp"
static const char* TAG = "Persistence";
Persistence::Persistence()
: m_isInitialized(false)
{
}
Persistence::~Persistence()
{
deinitialize();
}
bool Persistence::initialize()
{
// TODO: Implement initialization
m_isInitialized = true;
ASF_LOGI(TAG, 5000, asf::logger::Criticality::LOW, "Persistence initialized successfully");
return true;
}
bool Persistence::deinitialize()
{
if (!m_isInitialized)
{
return false;
}
// TODO: Implement deinitialization
m_isInitialized = false;
return true;
}
bool Persistence::isInitialized() const
{
return m_isInitialized;
}

View File

@@ -0,0 +1,33 @@
/**
* @file persistence.hpp
* @brief Persistence component header
* @author Mahmoud Elmohtady
* @company Nabd solutions - ASF
* @copyright Copyright (c) 2025
*/
#ifndef PERSISTENCE_HPP
#define PERSISTENCE_HPP
#include <cstdint>
/**
* @brief Persistence class
*
* Component description goes here.
*/
class Persistence
{
public:
Persistence();
~Persistence();
bool initialize();
bool deinitialize();
bool isInitialized() const;
private:
bool m_isInitialized;
};
#endif // PERSISTENCE_HPP

View File

@@ -0,0 +1,2 @@
ID,Component,Level,Criticality,Message
5000,Persistence,INFO,Low,Persistence initialized successfully
1 ID Component Level Criticality Message
2 5000 Persistence INFO Low Persistence initialized successfully

View File

@@ -0,0 +1,34 @@
import sys
import os
import time
folder_path = os.path.abspath(os.path.join("components", "system_tests"))
if folder_path not in sys.path:
sys.path.append(folder_path)
from scan_serial import ESP32Runner
def test_persistence_initialize():
runner = ESP32Runner(mode="SIM", port="COM9")
runner.start()
print("--- QEMU Runner Started ---", flush=True)
try:
start_time = time.time()
while time.time() - start_time < 30:
line = runner.get_line(timeout=1.0)
if line:
print(line, flush=True)
if "Persistence initialized successfully" in line:
print("SUCCESS CRITERIA MET!", flush=True)
return 0
if runner.process.poll() is not None:
print(f"Process exited with code: {runner.process.returncode}", flush=True)
return 1
finally:
runner.stop()
print("Done.", flush=True)
return 1
if __name__ == "__main__":
exit_code = test_persistence_initialize()
sys.exit(exit_code)

View File

@@ -0,0 +1,14 @@
<?xml version="1.0" encoding="UTF-8"?>
<test_scenario>
<!-- The configuration for the test environment. -->
<!-- Available configurations: SIMULATE, HIL -->
<config>SIMULATE</config>
<test_case>
<test_case_id>PERSISTENCE_INIT_TEST</test_case_id>
<!-- The main command that executes the test itself. -->
<test_exec>python components/application_layer/DP_stack/persistence/test/persistence_init_test.py</test_exec>
</test_case>
</test_scenario>

View File

@@ -0,0 +1,40 @@
/**
* @file test_persistence.cpp
* @brief Unit tests for Persistence component
* @author Mahmoud Elmohtady
* @company Nabd solutions - ASF
* @copyright Copyright (c) 2025
*/
#include "unity.h"
#include "persistence.hpp"
extern "C" {
void setUp(void)
{
}
void tearDown(void)
{
}
void test_persistence_initialize(void)
{
Persistence comp;
bool result = comp.initialize();
TEST_ASSERT_TRUE(result);
TEST_ASSERT_TRUE(comp.isInitialized());
}
void test_persistence_deinitialize(void)
{
Persistence comp;
comp.initialize();
bool result = comp.deinitialize();
TEST_ASSERT_TRUE(result);
TEST_ASSERT_FALSE(comp.isInitialized());
}
} // extern "C"

View File

@@ -0,0 +1,5 @@
idf_component_register(
SRCS "com/stm.cpp"
INCLUDE_DIRS "com"
REQUIRES logger
)

View File

@@ -0,0 +1,291 @@
# State Manager (STM) Component Specification
**Component ID:** COMP-STM
**Version:** 1.0
**Date:** 2025-01-19
**Location:** `application_layer/business_stack/STM/`
## 1. Purpose
The State Manager (STM) component implements the system finite state machine (FSM) as defined in the System State Machine Specification. It manages system operational states, enforces valid state transitions, coordinates teardown sequences, and notifies components of state changes.
## 2. Responsibilities
### 2.1 Primary Responsibilities
- Implement system FSM with 11 states (INIT, BOOT_FAILURE, RUNNING, WARNING, FAULT, OTA_PREP, OTA_UPDATE, MC_UPDATE, TEARDOWN, SERVICE, SD_DEGRADED)
- Enforce valid state transitions according to transition table
- Coordinate controlled teardown sequences
- Notify registered components of state changes via Event System
- Provide state query interface for components
### 2.2 Non-Responsibilities
- Feature logic (sensor acquisition, communication, etc.)
- Hardware access (delegated to drivers)
- Fault detection (delegated to Error Handler)
- Diagnostic logging (delegated to Diagnostics Task)
## 3. Public API
### 3.1 State Query Functions
```c
/**
* @brief Get current system state
* @return Current system state
*/
system_state_t stm_getCurrentState(void);
/**
* @brief Check if a state is valid
* @param state State to validate
* @return true if state is valid, false otherwise
*/
bool stm_isStateValid(system_state_t state);
/**
* @brief Check if system is in a specific state
* @param state State to check
* @return true if current state matches, false otherwise
*/
bool stm_isInState(system_state_t state);
```
### 3.2 State Transition Functions
```c
/**
* @brief Request a state transition
* @param target_state Target state
* @param reason Transition reason
* @return true if transition initiated, false if rejected
*/
bool stm_requestTransition(system_state_t target_state, transition_reason_t reason);
/**
* @brief Validate if a state transition is allowed
* @param from Source state
* @param to Target state
* @return true if transition is valid, false otherwise
*/
bool stm_validateTransition(system_state_t target_state, transition_reason_t reason);
/**
* @brief Get transition reason for last transition
* @return Transition reason
*/
transition_reason_t stm_getLastTransitionReason(void);
```
### 3.3 Teardown Functions
```c
/**
* @brief Initiate controlled teardown sequence
* @param reason Teardown reason
* @return true if teardown initiated, false if rejected
*/
bool stm_initiateTeardown(teardown_reason_t reason);
/**
* @brief Check if teardown is complete
* @return true if teardown complete, false otherwise
*/
bool stm_isTeardownComplete(void);
/**
* @brief Get teardown progress (0-100%)
* @return Teardown progress percentage
*/
uint8_t stm_getTeardownProgress(void);
```
### 3.4 Component Registration
```c
/**
* @brief State listener callback type
* @param old_state Previous state
* @param new_state New state
* @param reason Transition reason
*/
typedef void (*state_listener_t)(system_state_t old_state, system_state_t new_state, transition_reason_t reason);
/**
* @brief Register a state change listener
* @param listener Callback function
* @return true if registered, false on error
*/
bool stm_registerStateListener(state_listener_t listener);
/**
* @brief Unregister a state change listener
* @param listener Callback function to remove
* @return true if unregistered, false if not found
*/
bool stm_unregisterStateListener(state_listener_t listener);
```
## 4. Data Types
### 4.1 System States
```c
typedef enum {
SYSTEM_STATE_INIT = 0,
SYSTEM_STATE_BOOT_FAILURE,
SYSTEM_STATE_RUNNING,
SYSTEM_STATE_WARNING,
SYSTEM_STATE_FAULT,
SYSTEM_STATE_OTA_PREP,
SYSTEM_STATE_OTA_UPDATE,
SYSTEM_STATE_MC_UPDATE,
SYSTEM_STATE_TEARDOWN,
SYSTEM_STATE_SERVICE,
SYSTEM_STATE_SD_DEGRADED,
SYSTEM_STATE_COUNT
} system_state_t;
```
### 4.2 Transition Reasons
```c
typedef enum {
TRANSITION_REASON_INIT_SUCCESS,
TRANSITION_REASON_SECURE_BOOT_FAIL,
TRANSITION_REASON_NON_FATAL_FAULT,
TRANSITION_REASON_FATAL_FAULT,
TRANSITION_REASON_FAULT_CLEARED,
TRANSITION_REASON_FAULT_ESCALATED,
TRANSITION_REASON_OTA_REQUEST,
TRANSITION_REASON_MC_UPDATE_REQUEST,
TRANSITION_REASON_DEBUG_SESSION,
TRANSITION_REASON_SD_FAILURE,
TRANSITION_REASON_SD_RECOVERED,
TRANSITION_REASON_RECOVERY_ATTEMPT,
TRANSITION_REASON_MANUAL_RESET,
TRANSITION_REASON_OTA_READY,
TRANSITION_REASON_OTA_REJECTED,
TRANSITION_REASON_TEARDOWN_COMPLETE,
TRANSITION_REASON_OTA_SUCCESS,
TRANSITION_REASON_OTA_FAILURE,
TRANSITION_REASON_MC_UPDATE_COMPLETE,
TRANSITION_REASON_SESSION_CLOSED,
TRANSITION_REASON_MANUAL_INTERVENTION
} transition_reason_t;
```
### 4.3 Teardown Reasons
```c
typedef enum {
TEARDOWN_REASON_OTA,
TEARDOWN_REASON_MC_UPDATE,
TEARDOWN_REASON_FATAL_FAULT,
TEARDOWN_REASON_MANUAL_COMMAND,
TEARDOWN_REASON_SYSTEM_RESET
} teardown_reason_t;
```
## 5. Threading Model
- **Owner Task:** System Management Task (HIGH priority)
- **Thread Safety:** Thread-safe (protected by mutex for state transitions)
- **Blocking Operations:** None (all operations are non-blocking)
- **ISR Access:** State queries allowed from ISR (read-only, lock-free)
## 6. Resource Ownership
- **State Machine State:** Owned exclusively by STM component
- **State Transition Lock:** Mutex-protected (prevents concurrent transitions)
- **State Listeners:** List maintained by STM (protected by mutex)
## 7. Error Model
### 7.1 Error Conditions
| Error | Condition | Response |
|-------|-----------|----------|
| `STM_ERR_INVALID_STATE` | Invalid state parameter | Return false, log warning |
| `STM_ERR_INVALID_TRANSITION` | Invalid transition requested | Return false, log warning |
| `STM_ERR_TEARDOWN_IN_PROGRESS` | Teardown already in progress | Return false, log info |
| `STM_ERR_LISTENER_FULL` | Too many listeners registered | Return false, log error |
### 7.2 Diagnostics Emitted
- `DIAG-SY-STM-0001`: Invalid state transition attempted (WARNING)
- `DIAG-SY-STM-0002`: State transition timeout (ERROR)
- `DIAG-SY-STM-0003`: Teardown sequence failure (FATAL)
## 8. State-Dependent Behavior
### 8.1 INIT State
- **Allowed Operations:** State queries, listener registration
- **Forbidden Operations:** State transitions (except to RUNNING or BOOT_FAILURE)
- **Duration:** Bounded (max 5 seconds)
### 8.2 RUNNING State
- **Allowed Operations:** All operations
- **Forbidden Operations:** None
- **Duration:** Indefinite (normal operation)
### 8.3 TEARDOWN State
- **Allowed Operations:** State queries, teardown progress queries
- **Forbidden Operations:** New state transitions (except completion transitions)
- **Duration:** Bounded (max 500ms)
## 9. Dependencies
### 9.1 Required Components
- **Event System:** For state change notifications
- **Error Handler:** For fault-triggered transitions
- **Persistence:** For data flush during teardown
- **Logger:** For diagnostic logging
### 9.2 Required Interfaces
- Event System publish interface
- Persistence flush interface
- Logger interface
## 10. Acceptance Tests
### 10.1 State Transition Tests
- **T-STM-001:** Valid state transitions succeed
- **T-STM-002:** Invalid state transitions are rejected
- **T-STM-003:** State transition timing meets requirements (≤50ms)
### 10.2 Teardown Tests
- **T-STM-004:** Teardown sequence completes within 500ms
- **T-STM-005:** Teardown coordinates data flush
- **T-STM-006:** Teardown prevents new transitions
### 10.3 Notification Tests
- **T-STM-007:** State change notifications are sent to all listeners
- **T-STM-008:** State change notifications are non-blocking
## 11. Traceability
- **SWR-SYS-001:** FSM implementation
- **SWR-SYS-002:** State transition enforcement
- **SWR-SYS-003:** State-based operation restriction
- **SWR-SYS-004:** State transition notification
- **SWR-SYS-005:** Controlled teardown execution
- **SWR-SYS-006:** Critical data persistence before teardown
- **SWR-SYS-007:** Data integrity protection during shutdown
## 12. Implementation Notes
- State machine SHALL be implemented as a table-driven FSM
- State transitions SHALL be atomic (protected by mutex)
- State listeners SHALL be called asynchronously via Event System
- Teardown sequence SHALL coordinate with Persistence component for data flush
- State queries SHALL be lock-free for ISR access (read-only)

View File

@@ -0,0 +1,47 @@
/**
* @file stm.cpp
* @brief Stm component implementation
* @author Mahmoud Elmohtady
* @company Nabd solutions - ASF
* @copyright Copyright (c) 2025
*/
#include "stm.hpp"
#include "logger.hpp"
static const char* TAG = "Stm";
Stm::Stm()
: m_isInitialized(false)
{
}
Stm::~Stm()
{
deinitialize();
}
bool Stm::initialize()
{
// TODO: Implement initialization
m_isInitialized = true;
ASF_LOGI(TAG, 4600, asf::logger::Criticality::LOW, "Stm initialized successfully");
return true;
}
bool Stm::deinitialize()
{
if (!m_isInitialized)
{
return false;
}
// TODO: Implement deinitialization
m_isInitialized = false;
return true;
}
bool Stm::isInitialized() const
{
return m_isInitialized;
}

View File

@@ -0,0 +1,33 @@
/**
* @file stm.hpp
* @brief Stm component header
* @author Mahmoud Elmohtady
* @company Nabd solutions - ASF
* @copyright Copyright (c) 2025
*/
#ifndef STM_HPP
#define STM_HPP
#include <cstdint>
/**
* @brief Stm class
*
* Component description goes here.
*/
class Stm
{
public:
Stm();
~Stm();
bool initialize();
bool deinitialize();
bool isInitialized() const;
private:
bool m_isInitialized;
};
#endif // STM_HPP

View File

@@ -0,0 +1,2 @@
ID,Component,Level,Criticality,Message
4600,STM,INFO,Low,Stm initialized successfully
1 ID Component Level Criticality Message
2 4600 STM INFO Low Stm initialized successfully

View File

@@ -0,0 +1,34 @@
import sys
import os
import time
folder_path = os.path.abspath(os.path.join("components", "system_tests"))
if folder_path not in sys.path:
sys.path.append(folder_path)
from scan_serial import ESP32Runner
def test_stm_initialize():
runner = ESP32Runner(mode="SIM", port="COM9")
runner.start()
print("--- QEMU Runner Started ---", flush=True)
try:
start_time = time.time()
while time.time() - start_time < 30:
line = runner.get_line(timeout=1.0)
if line:
print(line, flush=True)
if "Stm initialized successfully" in line:
print("SUCCESS CRITERIA MET!", flush=True)
return 0
if runner.process.poll() is not None:
print(f"Process exited with code: {runner.process.returncode}", flush=True)
return 1
finally:
runner.stop()
print("Done.", flush=True)
return 1
if __name__ == "__main__":
exit_code = test_stm_initialize()
sys.exit(exit_code)

View File

@@ -0,0 +1,14 @@
<?xml version="1.0" encoding="UTF-8"?>
<test_scenario>
<!-- The configuration for the test environment. -->
<!-- Available configurations: SIMULATE, HIL -->
<config>SIMULATE</config>
<test_case>
<test_case_id>STM_INIT_TEST</test_case_id>
<!-- The main command that executes the test itself. -->
<test_exec>python components/application_layer/business_stack/STM/test/stm_init_test.py</test_exec>
</test_case>
</test_scenario>

View File

@@ -0,0 +1,40 @@
/**
* @file test_stm.cpp
* @brief Unit tests for Stm component
* @author Mahmoud Elmohtady
* @company Nabd solutions - ASF
* @copyright Copyright (c) 2025
*/
#include "unity.h"
#include "stm.hpp"
extern "C" {
void setUp(void)
{
}
void tearDown(void)
{
}
void test_stm_initialize(void)
{
Stm comp;
bool result = comp.initialize();
TEST_ASSERT_TRUE(result);
TEST_ASSERT_TRUE(comp.isInitialized());
}
void test_stm_deinitialize(void)
{
Stm comp;
comp.initialize();
bool result = comp.deinitialize();
TEST_ASSERT_TRUE(result);
TEST_ASSERT_FALSE(comp.isInitialized());
}
} // extern "C"

View File

@@ -0,0 +1,5 @@
idf_component_register(
SRCS "com/actuator_manager.cpp"
INCLUDE_DIRS "com"
REQUIRES logger
)

View File

@@ -0,0 +1,46 @@
/**
* @file actuator_manager.cpp
* @brief ActuatorManager component implementation
* @author Mahmoud Elmohtady
* @company Nabd solutions - ASF
* @copyright Copyright (c) 2025
*/
#include "logger.hpp"
#include "actuator_manager.hpp"
static const char* TAG = "actuator_manager";
ActuatorManager::ActuatorManager()
: m_isInitialized(false)
{
}
ActuatorManager::~ActuatorManager()
{
deinitialize();
}
bool ActuatorManager::initialize()
{
// TODO: Implement initialization
m_isInitialized = true;
ASF_LOGI(TAG, 4000, asf::logger::Criticality::LOW, "actuator manager initialized successfully");
return true;
}
bool ActuatorManager::deinitialize()
{
if (!m_isInitialized)
{
return false;
}
// TODO: Implement deinitialization
m_isInitialized = false;
return true;
}
bool ActuatorManager::isInitialized() const
{
return m_isInitialized;
}

View File

@@ -0,0 +1,33 @@
/**
* @file actuator_manager.hpp
* @brief ActuatorManager component header
* @author Mahmoud Elmohtady
* @company Nabd solutions - ASF
* @copyright Copyright (c) 2025
*/
#ifndef ACTUATOR_MANAGER_HPP
#define ACTUATOR_MANAGER_HPP
#include <cstdint>
/**
* @brief ActuatorManager class
*
* Component description goes here.
*/
class ActuatorManager
{
public:
ActuatorManager();
~ActuatorManager();
bool initialize();
bool deinitialize();
bool isInitialized() const;
private:
bool m_isInitialized;
};
#endif // ACTUATOR_MANAGER_HPP

View File

@@ -0,0 +1,2 @@
ID,Component,Level,Criticality,Message
4000,ActuatorManager,INFO,Low,actuator manager initialized successfully
1 ID Component Level Criticality Message
2 4000 ActuatorManager INFO Low actuator manager initialized successfully

View File

@@ -0,0 +1,34 @@
import sys
import os
import time
folder_path = os.path.abspath(os.path.join("components", "system_tests"))
if folder_path not in sys.path:
sys.path.append(folder_path)
from scan_serial import ESP32Runner
def test_actuator_manager_initialize():
runner = ESP32Runner(mode="SIM", port="COM9")
runner.start()
print("--- QEMU Runner Started ---", flush=True)
try:
start_time = time.time()
while time.time() - start_time < 30:
line = runner.get_line(timeout=1.0)
if line:
print(line, flush=True)
if "Actuator Manager initialized successfully" in line or "actuator manager initialized successfully" in line.lower():
print("SUCCESS CRITERIA MET!", flush=True)
return 0
if runner.process.poll() is not None:
print(f"Process exited with code: {runner.process.returncode}", flush=True)
return 1
finally:
runner.stop()
print("Done.", flush=True)
return 1
if __name__ == "__main__":
exit_code = test_actuator_manager_initialize()
sys.exit(exit_code)

View File

@@ -0,0 +1,12 @@
<?xml version="1.0" encoding="UTF-8"?>
<test_scenario>
<!-- The configuration for the test environment. -->
<!-- Available configurations: SIMULATE, HIL -->
<config>SIMULATE</config>
<test_case>
<test_case_id>ACTUATOR_MANAGER_INIT_TEST</test_case_id>
<!-- The main command that executes the test itself. -->
<test_exec>python components/application_layer/business_stack/actuator_manager/test/actuator_manager_init_test.py</test_exec>
</test_case>
</test_scenario>

View File

@@ -0,0 +1,56 @@
import sys
import os
# Get the absolute path to the folder you want to add
# Example: Adding a folder named 'my_components' located in the current directory
folder_path = os.path.abspath("components/system_tests")
if folder_path not in sys.path:
sys.path.append(folder_path)
from scan_serial import ESP32Runner
import time
# --- Main Logic ---
if __name__ == "__main__":
runner = ESP32Runner(mode="SIM", port="COM9")
runner.start()
keyword_found = False
# Force print to terminal immediately
print("--- QEMU Runner Started ---", flush=True)
try:
start_time = time.time()
import sys
import os
import time
folder_path = os.path.abspath(os.path.join("components", "system_tests"))
if folder_path not in sys.path:
sys.path.append(folder_path)
from scan_serial import ESP32Runner
def test_actuator_manager_initialize():
runner = ESP32Runner(mode="SIM", port="COM9")
runner.start()
print("--- QEMU Runner Started ---", flush=True)
try:
start_time = time.time()
while time.time() - start_time < 30:
line = runner.get_line(timeout=1.0)
if line:
print(line, flush=True)
if "actuator manager initialized successfully" in line.lower() or "Actuator Manager initialized successfully" in line:
print("SUCCESS CRITERIA MET!", flush=True)
return 0
if runner.process.poll() is not None:
print(f"Process exited with code: {runner.process.returncode}", flush=True)
return 1
finally:
runner.stop()
print("Done.", flush=True)
return 1
if __name__ == "__main__":
exit_code = test_actuator_manager_initialize()
sys.exit(exit_code)

View File

@@ -0,0 +1,40 @@
/**
* @file test_actuator_manager.cpp
* @brief Unit tests for ActuatorManager component
* @author Mahmoud Elmohtady
* @company Nabd solutions - ASF
* @copyright Copyright (c) 2025
*/
#include "unity.h"
#include "actuator_manager.hpp"
extern "C" {
void setUp(void)
{
}
void tearDown(void)
{
}
void test_actuator_manager_initialize(void)
{
ActuatorManager comp;
bool result = comp.initialize();
TEST_ASSERT_TRUE(result);
TEST_ASSERT_TRUE(comp.isInitialized());
}
void test_actuator_manager_deinitialize(void)
{
ActuatorManager comp;
comp.initialize();
bool result = comp.deinitialize();
TEST_ASSERT_TRUE(result);
TEST_ASSERT_FALSE(comp.isInitialized());
}
} // extern "C"

View File

@@ -0,0 +1,5 @@
idf_component_register(
SRCS "com/event_system.cpp"
INCLUDE_DIRS "com"
REQUIRES logger
)

View File

@@ -0,0 +1,200 @@
# Event System Component Specification
**Component ID:** COMP-EVENT
**Version:** 1.0
**Date:** 2025-01-19
**Location:** `application_layer/business_stack/event_system/`
## 1. Purpose
The Event System provides a publish/subscribe event bus for cross-component communication. It decouples components, enables asynchronous event delivery, and ensures non-blocking operation.
## 2. Responsibilities
### 2.1 Primary Responsibilities
- Provide publish/subscribe event bus
- Decouple components via events
- Ensure non-blocking event delivery
- Support multiple subscribers per event type
- Queue management for event delivery
### 2.2 Non-Responsibilities
- Business logic (components handle events)
- Event payload validation (components validate)
- Event ordering guarantees (best-effort)
## 3. Public API
### 3.1 Event Publishing
```c
/**
* @brief Publish an event
* @param type Event type
* @param payload Event payload (may be NULL)
* @param payload_size Payload size in bytes (0 if payload is NULL)
* @return true if published, false on error
*/
bool event_publish(event_type_t type, const void* payload, size_t payload_size);
/**
* @brief Publish an event with timestamp
* @param type Event type
* @param payload Event payload
* @param payload_size Payload size
* @param timestamp Event timestamp
* @return true if published, false on error
*/
bool event_publishWithTimestamp(event_type_t type, const void* payload, size_t payload_size, uint64_t timestamp);
```
### 3.2 Event Subscription
```c
/**
* @brief Event handler callback type
* @param type Event type
* @param payload Event payload
* @param payload_size Payload size
* @param timestamp Event timestamp
*/
typedef void (*event_handler_t)(event_type_t type, const void* payload, size_t payload_size, uint64_t timestamp);
/**
* @brief Subscribe to an event type
* @param type Event type to subscribe to
* @param handler Callback function
* @return true if subscribed, false on error
*/
bool event_subscribe(event_type_t type, event_handler_t handler);
/**
* @brief Unsubscribe from an event type
* @param type Event type to unsubscribe from
* @param handler Callback function to remove
* @return true if unsubscribed, false if not found
*/
bool event_unsubscribe(event_type_t type, event_handler_t handler);
```
### 3.3 Event Queue Management
```c
/**
* @brief Get number of pending events
* @param type Event type (EVENT_TYPE_ALL for all types)
* @return Number of pending events
*/
size_t event_getPendingCount(event_type_t type);
/**
* @brief Clear pending events
* @param type Event type (EVENT_TYPE_ALL for all types)
* @return Number of events cleared
*/
size_t event_clearPending(event_type_t type);
```
## 4. Data Types
### 4.1 Event Types
```c
typedef enum {
EVENT_SENSOR_DATA_UPDATE = 0,
EVENT_DIAGNOSTIC_EVENT,
EVENT_STATE_CHANGED,
EVENT_OTA_REQUEST,
EVENT_OTA_STATUS,
EVENT_MC_UPDATE_REQUEST,
EVENT_COMMUNICATION_LINK_STATUS,
EVENT_STORAGE_STATUS,
EVENT_SYSTEM_HEALTH_UPDATE,
EVENT_TYPE_ALL = 0xFF,
EVENT_TYPE_COUNT
} event_type_t;
```
### 4.2 Event Structure
```c
typedef struct {
event_type_t type;
uint64_t timestamp;
size_t payload_size;
uint8_t payload[]; // Variable-length payload
} event_t;
```
## 5. Threading Model
- **Owner Task:** Event System Task (MEDIUM priority) or shared with components
- **Thread Safety:** Thread-safe (lock-free queue for publishing, mutex for subscription management)
- **Blocking Operations:** None (all operations are non-blocking)
- **ISR Access:** Publish allowed from ISR (lock-free queue)
## 6. Resource Ownership
- **Event Queue:** Owned by Event System (lock-free ring buffer)
- **Subscriber List:** Protected by mutex
- **Event Buffers:** Pre-allocated static buffers (no dynamic allocation)
## 7. Error Model
### 7.1 Error Conditions
| Error | Condition | Response |
|-------|-----------|----------|
| `EVENT_ERR_QUEUE_FULL` | Event queue full | Drop oldest event, log warning |
| `EVENT_ERR_INVALID_TYPE` | Invalid event type | Return false, log warning |
| `EVENT_ERR_PAYLOAD_TOO_LARGE` | Payload exceeds maximum | Return false, log error |
| `EVENT_ERR_SUBSCRIBER_FULL` | Too many subscribers | Return false, log error |
### 7.2 Diagnostics Emitted
- `DIAG-SY-EVENT-0001`: Event queue full (WARNING)
- `DIAG-SY-EVENT-0002`: Event dropped due to queue full (WARNING)
- `DIAG-SY-EVENT-0003`: Subscriber callback failure (ERROR)
## 8. State-Dependent Behavior
- **All States:** Event System operates in all states
- **TEARDOWN State:** Event publishing limited to teardown-related events
- **FAULT State:** Event publishing limited to diagnostic events
## 9. Dependencies
### 9.1 Required Components
- **Logger:** For diagnostic logging
- **Time Utils:** For timestamp generation
### 9.2 Required Interfaces
- Logger interface
- Time Utils interface
## 10. Acceptance Tests
- **T-EVENT-001:** Events are published successfully
- **T-EVENT-002:** Subscribers receive events
- **T-EVENT-003:** Multiple subscribers receive same event
- **T-EVENT-004:** Event publishing is non-blocking
- **T-EVENT-005:** Event queue overflow handling
- **T-EVENT-006:** Event unsubscription works correctly
## 11. Traceability
- **SWR-DESIGN-006:** Event System for cross-component communication
- **CFC-TIME-01:** Non-blocking operation
- **Architecture Requirement:** Event-driven communication
## 12. Implementation Notes
- Event queue SHALL be implemented as lock-free ring buffer
- Maximum queue size: 100 events
- Maximum payload size: 256 bytes
- Maximum subscribers per event type: 10
- Event handlers SHALL be called synchronously (in publisher's context) or asynchronously (in event task context) based on configuration

View File

@@ -0,0 +1,46 @@
/**
* @file event_system.cpp
* @brief EventSystem component implementation
* @author Mahmoud Elmohtady
* @company Nabd solutions - ASF
* @copyright Copyright (c) 2025
*/
#include "logger.hpp"
#include "event_system.hpp"
static const char* TAG = "event system";
EventSystem::EventSystem()
: m_isInitialized(false)
{
}
EventSystem::~EventSystem()
{
deinitialize();
}
bool EventSystem::initialize()
{
// TODO: Implement initialization
m_isInitialized = true;
ASF_LOGI(TAG, 4200, asf::logger::Criticality::LOW, "event system initialized successfully");
return true;
}
bool EventSystem::deinitialize()
{
if (!m_isInitialized)
{
return false;
}
// TODO: Implement deinitialization
m_isInitialized = false;
return true;
}
bool EventSystem::isInitialized() const
{
return m_isInitialized;
}

View File

@@ -0,0 +1,33 @@
/**
* @file event_system.hpp
* @brief EventSystem component header
* @author Mahmoud Elmohtady
* @company Nabd solutions - ASF
* @copyright Copyright (c) 2025
*/
#ifndef EVENT_SYSTEM_HPP
#define EVENT_SYSTEM_HPP
#include <cstdint>
/**
* @brief EventSystem class
*
* Component description goes here.
*/
class EventSystem
{
public:
EventSystem();
~EventSystem();
bool initialize();
bool deinitialize();
bool isInitialized() const;
private:
bool m_isInitialized;
};
#endif // EVENT_SYSTEM_HPP

View File

@@ -0,0 +1,2 @@
ID,Component,Level,Criticality,Message
4200,EventSystem,INFO,Low,event system initialized successfully
1 ID Component Level Criticality Message
2 4200 EventSystem INFO Low event system initialized successfully

View File

@@ -0,0 +1,34 @@
import sys
import os
import time
folder_path = os.path.abspath(os.path.join("components", "system_tests"))
if folder_path not in sys.path:
sys.path.append(folder_path)
from scan_serial import ESP32Runner
def test_event_system_initialize():
runner = ESP32Runner(mode="SIM", port="COM9")
runner.start()
print("--- QEMU Runner Started ---", flush=True)
try:
start_time = time.time()
while time.time() - start_time < 30:
line = runner.get_line(timeout=1.0)
if line:
print(line, flush=True)
if "event system initialized successfully" in line.lower() or "Event System initialized successfully" in line:
print("SUCCESS CRITERIA MET!", flush=True)
return 0
if runner.process.poll() is not None:
print(f"Process exited with code: {runner.process.returncode}", flush=True)
return 1
finally:
runner.stop()
print("Done.", flush=True)
return 1
if __name__ == "__main__":
exit_code = test_event_system_initialize()
sys.exit(exit_code)

View File

@@ -0,0 +1,14 @@
<?xml version="1.0" encoding="UTF-8"?>
<test_scenario>
<!-- The configuration for the test environment. -->
<!-- Available configurations: SIMULATE, HIL -->
<config>SIMULATE</config>
<test_case>
<test_case_id>ACTUATOR_MANAGER_INIT_TEST</test_case_id>
<!-- The main command that executes the test itself. -->
<test_exec>python components/application_layer/business_stack/event_system/test/event_system_init_test.py</test_exec>
</test_case>
</test_scenario>

View File

@@ -0,0 +1,40 @@
/**
* @file test_event_system.cpp
* @brief Unit tests for EventSystem component
* @author Mahmoud Elmohtady
* @company Nabd solutions - ASF
* @copyright Copyright (c) 2025
*/
#include "unity.h"
#include "event_system.hpp"
extern "C" {
void setUp(void)
{
}
void tearDown(void)
{
}
void test_event_system_initialize(void)
{
EventSystem comp;
bool result = comp.initialize();
TEST_ASSERT_TRUE(result);
TEST_ASSERT_TRUE(comp.isInitialized());
}
void test_event_system_deinitialize(void)
{
EventSystem comp;
comp.initialize();
bool result = comp.deinitialize();
TEST_ASSERT_TRUE(result);
TEST_ASSERT_FALSE(comp.isInitialized());
}
} // extern "C"

View File

@@ -0,0 +1,5 @@
idf_component_register(
SRCS "com/fw_upgrader.cpp"
INCLUDE_DIRS "com"
REQUIRES logger
)

View File

@@ -0,0 +1,47 @@
/**
* @file fw_upgrader.cpp
* @brief FwUpgrader component implementation
* @author Mahmoud Elmohtady
* @company Nabd solutions - ASF
* @copyright Copyright (c) 2025
*/
#include "fw_upgrader.hpp"
#include "logger.hpp"
static const char* TAG = "FwUpgrader";
FwUpgrader::FwUpgrader()
: m_isInitialized(false)
{
}
FwUpgrader::~FwUpgrader()
{
deinitialize();
}
bool FwUpgrader::initialize()
{
// TODO: Implement initialization
m_isInitialized = true;
ASF_LOGI(TAG, 4300, asf::logger::Criticality::LOW, "FwUpgrader initialized successfully");
return true;
}
bool FwUpgrader::deinitialize()
{
if (!m_isInitialized)
{
return false;
}
// TODO: Implement deinitialization
m_isInitialized = false;
return true;
}
bool FwUpgrader::isInitialized() const
{
return m_isInitialized;
}

View File

@@ -0,0 +1,33 @@
/**
* @file fw_upgrader.hpp
* @brief FwUpgrader component header
* @author Mahmoud Elmohtady
* @company Nabd solutions - ASF
* @copyright Copyright (c) 2025
*/
#ifndef FW_UPGRADER_HPP
#define FW_UPGRADER_HPP
#include <cstdint>
/**
* @brief FwUpgrader class
*
* Component description goes here.
*/
class FwUpgrader
{
public:
FwUpgrader();
~FwUpgrader();
bool initialize();
bool deinitialize();
bool isInitialized() const;
private:
bool m_isInitialized;
};
#endif // FW_UPGRADER_HPP

View File

@@ -0,0 +1,2 @@
ID,Component,Level,Criticality,Message
4300,FwUpgrader,INFO,Low,FwUpgrader initialized successfully
1 ID Component Level Criticality Message
2 4300 FwUpgrader INFO Low FwUpgrader initialized successfully

View File

@@ -0,0 +1,44 @@
import sys
import os
import time
folder_path = os.path.abspath(os.path.join("components", "system_tests"))
if folder_path not in sys.path:
sys.path.append(folder_path)
from scan_serial import ESP32Runner
import sys
import os
import time
folder_path = os.path.abspath(os.path.join("components", "system_tests"))
if folder_path not in sys.path:
sys.path.append(folder_path)
def test_fw_upgrader_initialize():
runner = ESP32Runner(mode="SIM", port="COM9")
runner.start()
print("--- QEMU Runner Started ---", flush=True)
try:
start_time = time.time()
while time.time() - start_time < 30:
line = runner.get_line(timeout=1.0)
if line:
print(line, flush=True)
if "FwUpgrader initialized successfully" in line:
print("SUCCESS CRITERIA MET!", flush=True)
return 0
if runner.process.poll() is not None:
print(f"Process exited with code: {runner.process.returncode}", flush=True)
return 1
finally:
runner.stop()
print("Done.", flush=True)
return 1
if __name__ == "__main__":
exit_code = test_fw_upgrader_initialize()
sys.exit(exit_code)

View File

@@ -0,0 +1,14 @@
<?xml version="1.0" encoding="UTF-8"?>
<test_scenario>
<!-- The configuration for the test environment. -->
<!-- Available configurations: SIMULATE, HIL -->
<config>SIMULATE</config>
<test_case>
<test_case_id>FW_UPGRADER_INIT_TEST</test_case_id>
<!-- The main command that executes the test itself. -->
<test_exec>python components/application_layer/business_stack/fw_upgrader/test/fw_upgrader_init_test.py</test_exec>
</test_case>
</test_scenario>

View File

@@ -0,0 +1,40 @@
/**
* @file test_fw_upgrader.cpp
* @brief Unit tests for FwUpgrader component
* @author Mahmoud Elmohtady
* @company Nabd solutions - ASF
* @copyright Copyright (c) 2025
*/
#include "unity.h"
#include "fw_upgrader.hpp"
extern "C" {
void setUp(void)
{
}
void tearDown(void)
{
}
void test_fw_upgrader_initialize(void)
{
FwUpgrader comp;
bool result = comp.initialize();
TEST_ASSERT_TRUE(result);
TEST_ASSERT_TRUE(comp.isInitialized());
}
void test_fw_upgrader_deinitialize(void)
{
FwUpgrader comp;
comp.initialize();
bool result = comp.deinitialize();
TEST_ASSERT_TRUE(result);
TEST_ASSERT_FALSE(comp.isInitialized());
}
} // extern "C"

View File

@@ -0,0 +1,5 @@
idf_component_register(
SRCS "com/machine_constant_manager.cpp"
INCLUDE_DIRS "com"
REQUIRES logger
)

View File

@@ -0,0 +1,47 @@
/**
* @file machine_constant_manager.cpp
* @brief MachineConstantManager component implementation
* @author Mahmoud Elmohtady
* @company Nabd solutions - ASF
* @copyright Copyright (c) 2025
*/
#include "machine_constant_manager.hpp"
#include "logger.hpp"
static const char* TAG = "MachineConstantManager";
MachineConstantManager::MachineConstantManager()
: m_isInitialized(false)
{
}
MachineConstantManager::~MachineConstantManager()
{
deinitialize();
}
bool MachineConstantManager::initialize()
{
// TODO: Implement initialization
m_isInitialized = true;
ASF_LOGI(TAG, 4400, asf::logger::Criticality::LOW, "MachineConstantManager initialized successfully");
return true;
}
bool MachineConstantManager::deinitialize()
{
if (!m_isInitialized)
{
return false;
}
// TODO: Implement deinitialization
m_isInitialized = false;
return true;
}
bool MachineConstantManager::isInitialized() const
{
return m_isInitialized;
}

View File

@@ -0,0 +1,33 @@
/**
* @file machine_constant_manager.hpp
* @brief MachineConstantManager component header
* @author Mahmoud Elmohtady
* @company Nabd solutions - ASF
* @copyright Copyright (c) 2025
*/
#ifndef MACHINE_CONSTANT_MANAGER_HPP
#define MACHINE_CONSTANT_MANAGER_HPP
#include <cstdint>
/**
* @brief MachineConstantManager class
*
* Component description goes here.
*/
class MachineConstantManager
{
public:
MachineConstantManager();
~MachineConstantManager();
bool initialize();
bool deinitialize();
bool isInitialized() const;
private:
bool m_isInitialized;
};
#endif // MACHINE_CONSTANT_MANAGER_HPP

View File

@@ -0,0 +1,2 @@
ID,Component,Level,Criticality,Message
4400,MachineConstantManager,INFO,Low,MachineConstantManager initialized successfully
1 ID Component Level Criticality Message
2 4400 MachineConstantManager INFO Low MachineConstantManager initialized successfully

View File

@@ -0,0 +1,34 @@
import sys
import os
import time
folder_path = os.path.abspath(os.path.join("components", "system_tests"))
if folder_path not in sys.path:
sys.path.append(folder_path)
from scan_serial import ESP32Runner
def test_machine_constant_manager_initialize():
runner = ESP32Runner(mode="SIM", port="COM9")
runner.start()
print("--- QEMU Runner Started ---", flush=True)
try:
start_time = time.time()
while time.time() - start_time < 30:
line = runner.get_line(timeout=1.0)
if line:
print(line, flush=True)
if "MachineConstantManager initialized successfully" in line:
print("SUCCESS CRITERIA MET!", flush=True)
return 0
if runner.process.poll() is not None:
print(f"Process exited with code: {runner.process.returncode}", flush=True)
return 1
finally:
runner.stop()
print("Done.", flush=True)
return 1
if __name__ == "__main__":
exit_code = test_machine_constant_manager_initialize()
sys.exit(exit_code)

View File

@@ -0,0 +1,14 @@
<?xml version="1.0" encoding="UTF-8"?>
<test_scenario>
<!-- The configuration for the test environment. -->
<!-- Available configurations: SIMULATE, HIL -->
<config>SIMULATE</config>
<test_case>
<test_case_id>MACHINE_CONSTANT_MANAGER_INIT_TEST</test_case_id>
<!-- The main command that executes the test itself. -->
<test_exec>python components/application_layer/business_stack/machine_constant_manager/test/machine_constant_manager_init_test.py</test_exec>
</test_case>
</test_scenario>

View File

@@ -0,0 +1,40 @@
/**
* @file test_machine_constant_manager.cpp
* @brief Unit tests for MachineConstantManager component
* @author Mahmoud Elmohtady
* @company Nabd solutions - ASF
* @copyright Copyright (c) 2025
*/
#include "unity.h"
#include "machine_constant_manager.hpp"
extern "C" {
void setUp(void)
{
}
void tearDown(void)
{
}
void test_machine_constant_manager_initialize(void)
{
MachineConstantManager comp;
bool result = comp.initialize();
TEST_ASSERT_TRUE(result);
TEST_ASSERT_TRUE(comp.isInitialized());
}
void test_machine_constant_manager_deinitialize(void)
{
MachineConstantManager comp;
comp.initialize();
bool result = comp.deinitialize();
TEST_ASSERT_TRUE(result);
TEST_ASSERT_FALSE(comp.isInitialized());
}
} // extern "C"

View File

@@ -0,0 +1,5 @@
idf_component_register(
SRCS "com/main_hub_apis.cpp"
INCLUDE_DIRS "com"
REQUIRES logger
)

View File

@@ -0,0 +1,47 @@
/**
* @file main_hub_apis.cpp
* @brief MainHubApis component implementation
* @author Mahmoud Elmohtady
* @company Nabd solutions - ASF
* @copyright Copyright (c) 2025
*/
#include "main_hub_apis.hpp"
#include "logger.hpp"
static const char* TAG = "MainHubApis";
MainHubApis::MainHubApis()
: m_isInitialized(false)
{
}
MainHubApis::~MainHubApis()
{
deinitialize();
}
bool MainHubApis::initialize()
{
// TODO: Implement initialization
m_isInitialized = true;
ASF_LOGI(TAG, 4500, asf::logger::Criticality::LOW, "MainHubApis initialized successfully");
return true;
}
bool MainHubApis::deinitialize()
{
if (!m_isInitialized)
{
return false;
}
// TODO: Implement deinitialization
m_isInitialized = false;
return true;
}
bool MainHubApis::isInitialized() const
{
return m_isInitialized;
}

View File

@@ -0,0 +1,33 @@
/**
* @file main_hub_apis.hpp
* @brief MainHubApis component header
* @author Mahmoud Elmohtady
* @company Nabd solutions - ASF
* @copyright Copyright (c) 2025
*/
#ifndef MAIN_HUB_APIS_HPP
#define MAIN_HUB_APIS_HPP
#include <cstdint>
/**
* @brief MainHubApis class
*
* Component description goes here.
*/
class MainHubApis
{
public:
MainHubApis();
~MainHubApis();
bool initialize();
bool deinitialize();
bool isInitialized() const;
private:
bool m_isInitialized;
};
#endif // MAIN_HUB_APIS_HPP

View File

@@ -0,0 +1,2 @@
ID,Component,Level,Criticality,Message
4500,MainHubApis,INFO,Low,MainHubApis initialized successfully
1 ID Component Level Criticality Message
2 4500 MainHubApis INFO Low MainHubApis initialized successfully

View File

@@ -0,0 +1,34 @@
import sys
import os
import time
folder_path = os.path.abspath(os.path.join("components", "system_tests"))
if folder_path not in sys.path:
sys.path.append(folder_path)
from scan_serial import ESP32Runner
def test_main_hub_apis_initialize():
runner = ESP32Runner(mode="SIM", port="COM9")
runner.start()
print("--- QEMU Runner Started ---", flush=True)
try:
start_time = time.time()
while time.time() - start_time < 30:
line = runner.get_line(timeout=1.0)
if line:
print(line, flush=True)
if "MainHubApis initialized successfully" in line:
print("SUCCESS CRITERIA MET!", flush=True)
return 0
if runner.process.poll() is not None:
print(f"Process exited with code: {runner.process.returncode}", flush=True)
return 1
finally:
runner.stop()
print("Done.", flush=True)
return 1
if __name__ == "__main__":
exit_code = test_main_hub_apis_initialize()
sys.exit(exit_code)

View File

@@ -0,0 +1,14 @@
<?xml version="1.0" encoding="UTF-8"?>
<test_scenario>
<!-- The configuration for the test environment. -->
<!-- Available configurations: SIMULATE, HIL -->
<config>SIMULATE</config>
<test_case>
<test_case_id>MAIN_HUB_APIS_INIT_TEST</test_case_id>
<!-- The main command that executes the test itself. -->
<test_exec>python components/application_layer/business_stack/main_hub_apis/test/main_hub_apis_init_test.py</test_exec>
</test_case>
</test_scenario>

View File

@@ -0,0 +1,40 @@
/**
* @file test_main_hub_apis.cpp
* @brief Unit tests for MainHubApis component
* @author Mahmoud Elmohtady
* @company Nabd solutions - ASF
* @copyright Copyright (c) 2025
*/
#include "unity.h"
#include "main_hub_apis.hpp"
extern "C" {
void setUp(void)
{
}
void tearDown(void)
{
}
void test_main_hub_apis_initialize(void)
{
MainHubApis comp;
bool result = comp.initialize();
TEST_ASSERT_TRUE(result);
TEST_ASSERT_TRUE(comp.isInitialized());
}
void test_main_hub_apis_deinitialize(void)
{
MainHubApis comp;
comp.initialize();
bool result = comp.deinitialize();
TEST_ASSERT_TRUE(result);
TEST_ASSERT_FALSE(comp.isInitialized());
}
} // extern "C"

View File

@@ -0,0 +1,5 @@
idf_component_register(
SRCS "com/sensor_manager.cpp"
INCLUDE_DIRS "com"
REQUIRES logger
)

View File

@@ -0,0 +1,47 @@
/**
* @file sensor_manager.cpp
* @brief SensorManager component implementation
* @author Mahmoud Elmohtady
* @company Nabd solutions - ASF
* @copyright Copyright (c) 2025
*/
#include "sensor_manager.hpp"
#include "logger.hpp"
static const char* TAG = "SensorManager";
SensorManager::SensorManager()
: m_isInitialized(false)
{
}
SensorManager::~SensorManager()
{
deinitialize();
}
bool SensorManager::initialize()
{
// TODO: Implement initialization
m_isInitialized = true;
ASF_LOGI(TAG, 4100, asf::logger::Criticality::LOW, "SensorManager initialized successfully");
return true;
}
bool SensorManager::deinitialize()
{
if (!m_isInitialized)
{
return false;
}
// TODO: Implement deinitialization
m_isInitialized = false;
return true;
}
bool SensorManager::isInitialized() const
{
return m_isInitialized;
}

View File

@@ -0,0 +1,33 @@
/**
* @file sensor_manager.hpp
* @brief SensorManager component header
* @author Mahmoud Elmohtady
* @company Nabd solutions - ASF
* @copyright Copyright (c) 2025
*/
#ifndef SENSOR_MANAGER_HPP
#define SENSOR_MANAGER_HPP
#include <cstdint>
/**
* @brief SensorManager class
*
* Component description goes here.
*/
class SensorManager
{
public:
SensorManager();
~SensorManager();
bool initialize();
bool deinitialize();
bool isInitialized() const;
private:
bool m_isInitialized;
};
#endif // SENSOR_MANAGER_HPP

View File

@@ -0,0 +1,2 @@
ID,Component,Level,Criticality,Message
4100,SensorManager,INFO,Low,SensorManager initialized successfully
1 ID Component Level Criticality Message
2 4100 SensorManager INFO Low SensorManager initialized successfully

View File

@@ -0,0 +1,34 @@
import sys
import os
import time
folder_path = os.path.abspath(os.path.join("components", "system_tests"))
if folder_path not in sys.path:
sys.path.append(folder_path)
from scan_serial import ESP32Runner
def test_sensor_manager_initialize():
runner = ESP32Runner(mode="SIM", port="COM9")
runner.start()
print("--- QEMU Runner Started ---", flush=True)
try:
start_time = time.time()
while time.time() - start_time < 30:
line = runner.get_line(timeout=1.0)
if line:
print(line, flush=True)
if "SensorManager initialized successfully" in line or "Sensor Manager initialized successfully" in line:
print("SUCCESS CRITERIA MET!", flush=True)
return 0
if runner.process.poll() is not None:
print(f"Process exited with code: {runner.process.returncode}", flush=True)
return 1
finally:
runner.stop()
print("Done.", flush=True)
return 1
if __name__ == "__main__":
exit_code = test_sensor_manager_initialize()
sys.exit(exit_code)

View File

@@ -0,0 +1,14 @@
<?xml version="1.0" encoding="UTF-8"?>
<test_scenario>
<!-- The configuration for the test environment. -->
<!-- Available configurations: SIMULATE, HIL -->
<config>SIMULATE</config>
<test_case>
<test_case_id>SENSOR_MANAGER_INIT_TEST</test_case_id>
<!-- The main command that executes the test itself. -->
<test_exec>python components/application_layer/business_stack/sensor_manager/test/sensor_manager_init_test.py</test_exec>
</test_case>
</test_scenario>

View File

@@ -0,0 +1,40 @@
/**
* @file test_sensor_manager.cpp
* @brief Unit tests for SensorManager component
* @author Mahmoud Elmohtady
* @company Nabd solutions - ASF
* @copyright Copyright (c) 2025
*/
#include "unity.h"
#include "sensor_manager.hpp"
extern "C" {
void setUp(void)
{
}
void tearDown(void)
{
}
void test_sensor_manager_initialize(void)
{
SensorManager comp;
bool result = comp.initialize();
TEST_ASSERT_TRUE(result);
TEST_ASSERT_TRUE(comp.isInitialized());
}
void test_sensor_manager_deinitialize(void)
{
SensorManager comp;
comp.initialize();
bool result = comp.deinitialize();
TEST_ASSERT_TRUE(result);
TEST_ASSERT_FALSE(comp.isInitialized());
}
} // extern "C"

View File

@@ -0,0 +1,5 @@
idf_component_register(
SRCS "com/diag_task.cpp"
INCLUDE_DIRS "com"
REQUIRES logger
)

View File

@@ -0,0 +1,47 @@
/**
* @file diag_task.cpp
* @brief DiagTask component implementation
* @author Mahmoud Elmohtady
* @company Nabd solutions - ASF
* @copyright Copyright (c) 2025
*/
#include "diag_task.hpp"
#include "logger.hpp"
static const char* TAG = "DiagTask";
DiagTask::DiagTask()
: m_isInitialized(false)
{
}
DiagTask::~DiagTask()
{
deinitialize();
}
bool DiagTask::initialize()
{
// TODO: Implement initialization
m_isInitialized = true;
ASF_LOGI(TAG, 4700, asf::logger::Criticality::LOW, "DiagTask initialized successfully");
return true;
}
bool DiagTask::deinitialize()
{
if (!m_isInitialized)
{
return false;
}
// TODO: Implement deinitialization
m_isInitialized = false;
return true;
}
bool DiagTask::isInitialized() const
{
return m_isInitialized;
}

View File

@@ -0,0 +1,33 @@
/**
* @file diag_task.hpp
* @brief DiagTask component header
* @author Mahmoud Elmohtady
* @company Nabd solutions - ASF
* @copyright Copyright (c) 2025
*/
#ifndef DIAG_TASK_HPP
#define DIAG_TASK_HPP
#include <cstdint>
/**
* @brief DiagTask class
*
* Component description goes here.
*/
class DiagTask
{
public:
DiagTask();
~DiagTask();
bool initialize();
bool deinitialize();
bool isInitialized() const;
private:
bool m_isInitialized;
};
#endif // DIAG_TASK_HPP

View File

@@ -0,0 +1,2 @@
ID,Component,Level,Criticality,Message
4700,DiagTask,INFO,Low,DiagTask initialized successfully
1 ID Component Level Criticality Message
2 4700 DiagTask INFO Low DiagTask initialized successfully

View File

@@ -0,0 +1,34 @@
import sys
import os
import time
folder_path = os.path.abspath(os.path.join("components", "system_tests"))
if folder_path not in sys.path:
sys.path.append(folder_path)
from scan_serial import ESP32Runner
def test_diag_task_initialize():
runner = ESP32Runner(mode="SIM", port="COM9")
runner.start()
print("--- QEMU Runner Started ---", flush=True)
try:
start_time = time.time()
while time.time() - start_time < 30:
line = runner.get_line(timeout=1.0)
if line:
print(line, flush=True)
if "DiagTask initialized successfully" in line:
print("SUCCESS CRITERIA MET!", flush=True)
return 0
if runner.process.poll() is not None:
print(f"Process exited with code: {runner.process.returncode}", flush=True)
return 1
finally:
runner.stop()
print("Done.", flush=True)
return 1
if __name__ == "__main__":
exit_code = test_diag_task_initialize()
sys.exit(exit_code)

View File

@@ -0,0 +1,14 @@
<?xml version="1.0" encoding="UTF-8"?>
<test_scenario>
<!-- The configuration for the test environment. -->
<!-- Available configurations: SIMULATE, HIL -->
<config>SIMULATE</config>
<test_case>
<test_case_id>DIAG_TASK_INIT_TEST</test_case_id>
<!-- The main command that executes the test itself. -->
<test_exec>python components/application_layer/diag_task/test/diag_task_init_test.py</test_exec>
</test_case>
</test_scenario>

View File

@@ -0,0 +1,40 @@
/**
* @file test_diag_task.cpp
* @brief Unit tests for DiagTask component
* @author Mahmoud Elmohtady
* @company Nabd solutions - ASF
* @copyright Copyright (c) 2025
*/
#include "unity.h"
#include "diag_task.hpp"
extern "C" {
void setUp(void)
{
}
void tearDown(void)
{
}
void test_diag_task_initialize(void)
{
DiagTask comp;
bool result = comp.initialize();
TEST_ASSERT_TRUE(result);
TEST_ASSERT_TRUE(comp.isInitialized());
}
void test_diag_task_deinitialize(void)
{
DiagTask comp;
comp.initialize();
bool result = comp.deinitialize();
TEST_ASSERT_TRUE(result);
TEST_ASSERT_FALSE(comp.isInitialized());
}
} // extern "C"

View File

@@ -0,0 +1,5 @@
idf_component_register(
SRCS "com/error_handler.cpp"
INCLUDE_DIRS "com"
REQUIRES logger
)

View File

@@ -0,0 +1,47 @@
/**
* @file error_handler.cpp
* @brief ErrorHandler component implementation
* @author Mahmoud Elmohtady
* @company Nabd solutions - ASF
* @copyright Copyright (c) 2025
*/
#include "error_handler.hpp"
#include "logger.hpp"
static const char* TAG = "ErrorHandler";
ErrorHandler::ErrorHandler()
: m_isInitialized(false)
{
}
ErrorHandler::~ErrorHandler()
{
deinitialize();
}
bool ErrorHandler::initialize()
{
// TODO: Implement initialization
m_isInitialized = true;
ASF_LOGI(TAG, 4800, asf::logger::Criticality::LOW, "ErrorHandler initialized successfully");
return true;
}
bool ErrorHandler::deinitialize()
{
if (!m_isInitialized)
{
return false;
}
// TODO: Implement deinitialization
m_isInitialized = false;
return true;
}
bool ErrorHandler::isInitialized() const
{
return m_isInitialized;
}

View File

@@ -0,0 +1,33 @@
/**
* @file error_handler.hpp
* @brief ErrorHandler component header
* @author Mahmoud Elmohtady
* @company Nabd solutions - ASF
* @copyright Copyright (c) 2025
*/
#ifndef ERROR_HANDLER_HPP
#define ERROR_HANDLER_HPP
#include <cstdint>
/**
* @brief ErrorHandler class
*
* Component description goes here.
*/
class ErrorHandler
{
public:
ErrorHandler();
~ErrorHandler();
bool initialize();
bool deinitialize();
bool isInitialized() const;
private:
bool m_isInitialized;
};
#endif // ERROR_HANDLER_HPP

View File

@@ -0,0 +1,2 @@
ID,Component,Level,Criticality,Message
4800,ErrorHandler,INFO,Low,ErrorHandler initialized successfully
1 ID Component Level Criticality Message
2 4800 ErrorHandler INFO Low ErrorHandler initialized successfully

View File

@@ -0,0 +1,34 @@
import sys
import os
import time
folder_path = os.path.abspath(os.path.join("components", "system_tests"))
if folder_path not in sys.path:
sys.path.append(folder_path)
from scan_serial import ESP32Runner
def test_error_handler_initialize():
runner = ESP32Runner(mode="SIM", port="COM9")
runner.start()
print("--- QEMU Runner Started ---", flush=True)
try:
start_time = time.time()
while time.time() - start_time < 30:
line = runner.get_line(timeout=1.0)
if line:
print(line, flush=True)
if "ErrorHandler initialized successfully" in line:
print("SUCCESS CRITERIA MET!", flush=True)
return 0
if runner.process.poll() is not None:
print(f"Process exited with code: {runner.process.returncode}", flush=True)
return 1
finally:
runner.stop()
print("Done.", flush=True)
return 1
if __name__ == "__main__":
exit_code = test_error_handler_initialize()
sys.exit(exit_code)

View File

@@ -0,0 +1,14 @@
<?xml version="1.0" encoding="UTF-8"?>
<test_scenario>
<!-- The configuration for the test environment. -->
<!-- Available configurations: SIMULATE, HIL -->
<config>SIMULATE</config>
<test_case>
<test_case_id>ERROR_HANDLER_INIT_TEST</test_case_id>
<!-- The main command that executes the test itself. -->
<test_exec>python components/application_layer/error_handler/test/error_handler_init_test.py</test_exec>
</test_case>
</test_scenario>

View File

@@ -0,0 +1,40 @@
/**
* @file test_error_handler.cpp
* @brief Unit tests for ErrorHandler component
* @author Mahmoud Elmohtady
* @company Nabd solutions - ASF
* @copyright Copyright (c) 2025
*/
#include "unity.h"
#include "error_handler.hpp"
extern "C" {
void setUp(void)
{
}
void tearDown(void)
{
}
void test_error_handler_initialize(void)
{
ErrorHandler comp;
bool result = comp.initialize();
TEST_ASSERT_TRUE(result);
TEST_ASSERT_TRUE(comp.isInitialized());
}
void test_error_handler_deinitialize(void)
{
ErrorHandler comp;
comp.initialize();
bool result = comp.deinitialize();
TEST_ASSERT_TRUE(result);
TEST_ASSERT_FALSE(comp.isInitialized());
}
} // extern "C"