Program Listing for File error_controller.cpp

Return to documentation for file (src/tap/errors/error_controller.cpp)

/*
 * Copyright (c) 2020-2021 Advanced Robotics at the University of Washington <robomstr@uw.edu>
 *
 * This file is part of Taproot.
 *
 * Taproot is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * Taproot is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with Taproot.  If not, see <https://www.gnu.org/licenses/>.
 */

#include "error_controller.hpp"

#include "tap/algorithms/strtok.hpp"
#include "tap/communication/gpio/leds.hpp"
#include "tap/drivers.hpp"

#include "modm/container/linked_list.hpp"

namespace tap::errors
{
void ErrorController::addToErrorList(const SystemError& error)
{
    // only add error if it is not already added
    // Note that we are okay with comparing raw char pointers because an error generated
    // in our codebase use char pointers located in literals.
    for (SystemError sysErr : errorList)
    {
        if (sysErr.getDescription() == error.getDescription() &&
            sysErr.getFilename() == error.getFilename() &&
            sysErr.getLineNumber() == error.getLineNumber())
        {
            return;  // the error is already added
        }
    }
    if (errorList.getSize() >= errorList.getMaxSize())
    {
        errorList.removeFront();  // remove the oldest element in the error list
    }
    errorList.append(error);
}

void ErrorController::init()
{
    drivers->terminalSerial.addHeader("error", &drivers->errorController);
}

bool ErrorController::removeSystemErrorAtIndex(error_index_t index)
{
    if (index >= errorList.getSize())
    {
        return false;
    }
    if (index == 0)
    {
        errorList.removeFront();
        return true;
    }
    else if (index == errorList.getSize() - 1)
    {
        errorList.removeBack();
        return true;
    }
    error_index_t size = errorList.getSize();
    for (error_index_t i = 0; i < size; i++)
    {
        SystemError se = errorList.get(0);
        errorList.removeFront();
        if (i != index)
        {
            errorList.append(se);
        }
    }
    return true;
}

void ErrorController::removeAllSystemErrors()
{
    while (errorList.getSize() > 0)
    {
        errorList.removeBack();
    }
}

bool ErrorController::terminalSerialCallback(
    char* inputLine,
    modm::IOStream& outputStream,
    bool streamingEnabled)
{
    if (streamingEnabled)
    {
        outputStream << "Error Controller: streaming is not supported" << modm::endl;
        return false;
    }
    char* arg = strtokR(inputLine, communication::serial::TerminalSerial::DELIMITERS, &inputLine);
    if (arg == nullptr || strcmp(arg, "-H") == 0)
    {
        outputStream << USAGE;
        return arg != nullptr;
    }
    else if (strcmp(arg, "printall") == 0)
    {
        outputStream << "printing errors" << modm::endl;
        displayAllErrors(outputStream);
    }
    else if (strcmp(arg, "removeall") == 0)
    {
        clearAllTerminalErrors(outputStream);
    }
    else if (strcmp(arg, "remove") == 0)
    {
        arg = strtokR(inputLine, communication::serial::TerminalSerial::DELIMITERS, &inputLine);
        if (arg == nullptr)
        {
            outputStream << "Error Controller: must specify an index" << modm::endl;
            return false;
        }
        char* indexEnd;
        int index = strtol(arg, &indexEnd, 10);
        if (indexEnd != arg + strlen(arg))
        {
            outputStream << "Error Controller: invalid index: " << arg << modm::endl;
            return false;
        }
        removeTerminalError(index, outputStream);
    }
    else
    {
        outputStream << "Command not found, try again, type \"error -H\" for more." << modm::endl;
        return false;
    }
    return true;
}

void ErrorController::displayAllErrors(modm::IOStream& outputStream)
{
    int index = 0;
    if (errorList.getSize() == 0)
    {
        outputStream << "No errors found" << modm::endl;
    }
    else
    {
        for (SystemError sysErr : errorList)
        {
            outputStream << index++ << ") " << sysErr.getDescription() << " ["
                         << sysErr.getFilename() << ':' << sysErr.getLineNumber() << ']'
                         << modm::endl;
        }
    }
}

// Syntax: Error RemoveTerminalError [Index]
void ErrorController::removeTerminalError(int index, modm::IOStream& outputStream)
{
    outputStream << "Removing terminal error at index..." << index << modm::endl;
    if (!removeSystemErrorAtIndex(index))
    {
        outputStream << "Invalid index" << modm::endl;
    }
}

void ErrorController::clearAllTerminalErrors(modm::IOStream& outputStream)
{
    outputStream << "Removing all terminal errors..." << modm::endl;
    removeAllSystemErrors();
}

}  // namespace tap::errors