Skip to content

File RBCXUltrasound.cpp

File List > demo-projets > esp > RBCXUltrasound.cpp

Go to the documentation of this file.

#include <esp_log.h>

#include "RBCXManager.h"
#include "RBCXUltrasound.h"
#include "rbcx.pb.h"

#define TAG "RBCXUltrasound"

namespace rb {

Ultrasound::Ultrasound()
    : m_index(0)
    , m_lastUs(0)
    , m_lastDistanceMm(0)
    , m_speedOfSound(defaultSpeedOfSound / 100.f)
    , m_measuring(false)
    , m_timeoutTimer(0) {}

Ultrasound::~Ultrasound() {}

void Ultrasound::init(uint8_t index) {
    m_index = index;

    m_timeoutTimer = Timers::get().schedule(0xFFFFFFFF, [this]() -> bool {
        ESP_LOGE(TAG, "Ultrasound %d response timeout!\n", m_index);
        onMeasuringDone(CoprocStat_UltrasoundStat { 0 });
        return true; // return true to prevent cancel, was stopped in onMeasuringDone
    });

    Timers::get().stop(m_timeoutTimer);
}

void Ultrasound::setSpeedOfSound(float speedOfSoundInMetersPerSecond) {
    m_mutex.lock();
    m_speedOfSound = speedOfSoundInMetersPerSecond / 100.f;
    recalculateLastDistanceLocked();
    m_mutex.unlock();
}

void Ultrasound::measureAsync(callback_t callback) {
    std::lock_guard<std::recursive_mutex> ul(m_mutex);

    if (!m_measuring) {
        m_measuring = true;
        Manager::get().sendToCoproc(CoprocReq {
            .which_payload = CoprocReq_ultrasoundReq_tag,
            .payload = {
                .ultrasoundReq = {
                    .utsIndex = m_index,
                    .which_utsCmd = CoprocReq_UltrasoundReq_singlePing_tag,
                },
            },
        });
        Timers::get().reset(m_timeoutTimer, 250);
    }

    if (callback)
        m_callbacks.emplace_back(std::move(callback));
}

uint32_t Ultrasound::measure() {
    if (Timers::get().isOnTimerTask()) {
        ESP_LOGE(TAG,
            "you can't call measure() from the ESP timer task, as it is a "
            "blocking function. Use measureAsync.\n");
        abort();
    }
    std::unique_lock<std::recursive_mutex> ul(m_mutex);
    measureAsync();
    m_measuringDone.wait(ul);
    return m_lastDistanceMm;
}

void Ultrasound::onMeasuringDone(const CoprocStat_UltrasoundStat& result) {
    uint32_t distance;

    {
        std::lock_guard<std::recursive_mutex> ul(m_mutex);

        m_lastUs = result.roundtripMicrosecs;
        recalculateLastDistanceLocked();
        distance = m_lastDistanceMm;
        m_measuring = false;
        Timers::get().stop(m_timeoutTimer);
        m_measuringDone.notify_all();

        for (auto itr = m_callbacks.begin(); itr != m_callbacks.end();) {
            if (!(*itr)(distance)) {
                itr = m_callbacks.erase(itr);
            } else {
                ++itr;
            }
        }

        if (!m_callbacks.empty()) {
            measureAsync();
        }
    }
}

void Ultrasound::recalculateLastDistanceLocked() {
    if (m_lastUs == 0) {
        m_lastDistanceMm = 0;
        return;
    }

    m_lastDistanceMm = uint32_t(m_speedOfSound * (float(m_lastUs) / 10.f)) / 2;
}

};