ASync (Asynchronous Task)
LibXR::ASync provides a simple and low-overhead asynchronous execution capability for time-consuming operations using a dedicated worker thread + counting semaphore. Users can assign Job callbacks within tasks or interrupt handlers. The framework sequentially executes these in a background thread and updates status, without requiring users to manage thread lifecycles or complex queues.
Typical use cases: Trigger FFT computation after SPI sampling interrupt; submit OTA verification in main loop; report events to the cloud from GPIO ISR, etc.
Design Highlights
| Goal | Description |
|---|---|
| Thread-exclusive | Each ASync instance creates one worker thread and wakes it up using a Semaphore to run Job, avoiding race conditions between tasks. |
| ISR-safe submission | AssignJobFromCallback() can be called from interrupt or callback context using Semaphore::PostFromCallback() to safely wake up the thread. |
| Status queryable | GetStatus() returns READY/BUSY/DONE. After a task completes, the state auto-resets—suitable for polling or timeout detection. |
| Minimal dependency | Only depends on Thread and Semaphore; can degrade into synchronous execution in bare-metal mode. |
| Minimal interface | No use of templated queues or dynamic allocation. Uses Callback<ASync*> for Job, making it easy to bind member or free functions. |
Core Interface
class ASync {
public:
enum class Status : uint8_t { READY, BUSY, DONE };
ASync(size_t stack_depth, Thread::Priority priority);
using Job = LibXR::Callback<ASync*>;
ErrorCode AssignJob(Job job); // Submit from task context
void AssignJobFromCallback(Job job, bool isr);// Submit from ISR/callback context
Status GetStatus(); // Query status and auto-reset
};
Error Codes
ErrorCode::OKSubmission successfulErrorCode::BUSYA task is already running
Usage Example
#include <libxr/async.hpp>
LibXR::ASync async_worker(2048, LibXR::Thread::Priority::NORMAL);
void HeavyCalc(bool, int *, LibXR::ASync*)
{
DoFFT(); // Time-consuming: 5‑10 ms
}
int arg = 0;
auto async_job = LibXR::ASync::Job::Create(HeavyCalc, &arg);
void SensorISR()
{
// Submit task in interrupt after sampling is done
async_worker.AssignJobFromCallback(HeavyCalc, true);
}
void Loop()
{
// ...
if (async_worker.GetStatus() == LibXR::ASync::Status::DONE) {
PublishResult();
}
// ...
}
Platform Adaptation
ASync itself is OS-agnostic. All platform-specific differences are abstracted by Thread and Semaphore layers:
| Function | Dependency Module |
|---|---|
| Thread creation | Thread::Create() |
| Task wakeup | Semaphore::Post/Wait |
| ISR-compatible | Semaphore::PostFromCallback() |
In bare-metal mode, async.cpp can be modified for synchronous direct calls: if the system lacks thread support, AssignJob() directly invokes job.Run(), making ASync a lightweight function call wrapper.
Although Callback design forbids blocking or delay, its interface and structure are reused here and renamed as Job to avoid confusion.