Tag Archives: c++

Robust sensors

Thanks to HobbyKings horrible shipping times, I’m forced to use my broken Crius UBLOX GPS to test the GPS code. I’m not sure what is broken but the symptoms vary from garbage data, wrong crc, loosing the fix every 2 minutes and random periods of complete silence.

To be able to continue working I had to add a watchdog that reinitializes the GPS if it’s silent for more than 5 seconds. However – my GPS::init function is blocking and takes a few seconds to do it’s work as it has to wait for the ACK messages and retry a few times if needed. So I moved it on the secondary thread using silk::async.

void GPS_UBLOX::process()
{
    QLOG_TOPIC("gps_ublox::process");
    if (!m_is_setup)
    {
        if (!m_setup_future.valid() || //first time we're starting this
             m_setup_future.get_state() == boost::future_state::ready) //the previous async setup failed
        {
            //start the async setup
            m_setup_future = silk::async([this]() { setup(); });
        }
        return;
    }

And the watchdog:

//check if we need to reset
if (q::Clock::now() - m_sample.last_complete_time_point >= REINIT_WATCHGOD_TIMEOUT)
{
    m_is_setup = false;
}

So if at any moment the GPS stops responding I’m firing the setup on the second thread – to avoid blocking the main control thread and keep doing it until the GPS responds again.

I’m thinking to add this king of hot restart to all sensors and in case something happens to trigger it from the GS.

Advertisements

silk::async

No intro for this one, it’s too late.

Here’s the code:

extern boost::asio::io_service s_io_service;

namespace silk
{
    template<typename F> auto async(F f) -> boost::unique_future<decltype(f())>
    {
        typedef decltype(f()) result_type;
        typedef boost::packaged_task<result_type> packaged_task;
        auto task = std::make_shared<packaged_task>(std::move(f));
        boost::unique_future<result_type> future = task->get_future();
        s_io_service.post(boost::bind(&packaged_task::operator(), task));
        return future;
    }
}

It’s std::async replacement that uses a boost::asio::io_service as a dispatcher.

I use it for any operation that might take too long and it’s in the middle of my control loop – like saving new PIDs to disk ot the battery state.

Usage is pretty simple – pass a lambda and that lambda will be executed some time later from the thread that is doing the io_service::run()

silk::async([=]()
{
    save_settings();
});

or

silk::async([=]()
{
    autojsoncxx::to_pretty_json_file("battery_state.cfg", m_saved_state);
    QLOGI("Capacity used: {}mAh", m_capacity_used_mah);
});

The function returns a boost::future so the result of the lambda can be pooled for.

I like the async ways. The future/promise mechanism is a very elegant way to express computations. It reminds me a bit of the Haskell’s lazyness.