Skip to content

File Dispatcher.cpp

File List > fw > rbcx-coprocessor > src > Dispatcher.cpp

Go to the documentation of this file.

#include "Dispatcher.hpp"
#include "FreeRTOS.h"
#include "utils/Debug.hpp"

#include "Bsp.hpp"
#include "BuzzerController.hpp"
#include "ControlLink.hpp"
#include "Esp32Manager.hpp"
#include "I2cController.hpp"
#include "MotorController.hpp"
#include "Power.hpp"
#include "SmartServoController.hpp"
#include "StupidServoController.hpp"
#include "UltrasoundController.hpp"
#include "queue.h"
#include "rbcx.pb.h"
#include "utils/QueueWrapper.hpp"

static QueueWrapper<CoprocStat, 64> statusQueue;
static QueueWrapper<CoprocReq, 8> requestQueue;

void dispatcherInit() {
    statusQueue.create();
    requestQueue.create();
}

bool dispatcherEnqueueStatus(const CoprocStat& status) {
    BaseType_t pxHigherPriorityTaskWoken = pdFALSE;
    auto ok = statusQueue.push_back(status, 0, &pxHigherPriorityTaskWoken);
    if (!ok) {
        DEBUG("Status queue overflow\n");
    }
    portYIELD_FROM_ISR(pxHigherPriorityTaskWoken);
    return ok;
}

bool dispatcherEnqueueRequest(const CoprocReq& request) {
    BaseType_t pxHigherPriorityTaskWoken = pdFALSE;
    auto ok = requestQueue.push_back(request, 0, &pxHigherPriorityTaskWoken);
    if (!ok) {
        DEBUG("Request queue overflow\n");
    }
    portYIELD_FROM_ISR(pxHigherPriorityTaskWoken);
    return ok;
}

static void sendButtonsStat() {
    CoprocStat status = {
        .which_payload = CoprocStat_buttonsStat_tag,
    };
    status.payload.buttonsStat.buttonsPressed
        = CoprocStat_ButtonsEnum(getButtons());
    controlLinkTx(status);
}

static void sendVersionStat() {
    CoprocStat status = {
        .which_payload = CoprocStat_versionStat_tag,
    };

    auto& v = status.payload.versionStat;

    static_assert(sizeof(v.revision) == 8);
    static_assert(sizeof(RBCX_VER_REVISION) == 9); // + NULL byte
    memcpy(v.revision, RBCX_VER_REVISION, 8);

    v.dirty = RBCX_VER_DIRTY;
    v.number = RBCX_VER_NUMBER;
    controlLinkTx(status);
}

static void dispatcherProcessReq(const CoprocReq& request) {
    switch (request.which_payload) {
    case CoprocReq_setLeds_tag: {
        setLeds(request.payload.setLeds.ledsOn);
        const CoprocStat status = {
            .which_payload = CoprocStat_ledsStat_tag,
        };
        controlLinkTx(status);
        break;
    }
    case CoprocReq_getButtons_tag:
        sendButtonsStat();
        break;
    case CoprocReq_setStupidServo_tag:
        stupidServoDispatch(request.payload.setStupidServo);
        break;
    case CoprocReq_ultrasoundReq_tag:
        ultrasoundDispatch(request.payload.ultrasoundReq);
        break;
    case CoprocReq_buzzerReq_tag:
        buzzerSetState(request.payload.buzzerReq.on);
        buzzerSetState(request.payload.buzzerReq.on);
        break;
    case CoprocReq_versionReq_tag:
        sendVersionStat();
        break;
    case CoprocReq_calibratePower_tag: {
        const auto& c = request.payload.calibratePower;
        powerCalibrate(c.vccMv, c.battMidMv, c.vRef33Mv, c.temperatureC);
        break;
    }
    case CoprocReq_shutdownPower_tag:
        powerShutDown();
        break;
    case CoprocReq_motorReq_tag:
        motorDispatch(request.payload.motorReq);
        break;
    case CoprocReq_i2cReq_tag:
        i2cDispatch(request.payload.i2cReq);
        break;
    case CoprocReq_espWatchdogSettings_tag:
        sEsp32Manager.handleSettings(request.payload.espWatchdogSettings);
        break;
    case CoprocReq_coprocStartupMessage_tag: {
        const auto& m = request.payload.coprocStartupMessage;
        if (m.getButtons) {
            sendButtonsStat();
        }
        if (m.getVersion) {
            sendVersionStat();
        }
        if (m.getRtc) {
            // TODO RTC not yet implemented
        }
        if (m.has_espWatchdogSettings) {
            sEsp32Manager.handleSettings(m.espWatchdogSettings);
        }
        break;
    }
    case CoprocReq_smartServoReq_tag:
        smartServoSendRequest(request.payload.smartServoReq);
        break;
    }
}

void dispatcherPoll() {
    CoprocReq request;
    CoprocStat status;

    if (controlLinkRx(request)) {
        sEsp32Manager.resetWatchdog();
        dispatcherProcessReq(request);
    }

    if (requestQueue.pop_front(request, 0)) {
        dispatcherProcessReq(request);
    }

    if (statusQueue.pop_front(status, 0)) {
        controlLinkTx(status);
    }
}

void dispatcherReset() {
    requestQueue.reset();
    statusQueue.reset();
}