Skip to main content

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

GoalDescription
Thread-exclusiveEach ASync instance creates one worker thread and wakes it up using a Semaphore to run Job, avoiding race conditions between tasks.
ISR-safe submissionAssignJobFromCallback() can be called from interrupt or callback context using Semaphore::PostFromCallback() to safely wake up the thread.
Status queryableGetStatus() returns READY/BUSY/DONE. After a task completes, the state auto-resets—suitable for polling or timeout detection.
Minimal dependencyOnly depends on Thread and Semaphore; can degrade into synchronous execution in bare-metal mode.
Minimal interfaceNo 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::OK      Submission successful
  • ErrorCode::BUSY    A 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:

FunctionDependency Module
Thread creationThread::Create()
Task wakeupSemaphore::Post/Wait
ISR-compatibleSemaphore::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.