Invalid C++ errors when running pio build in Clion on Mac M3

About a week ago, I was doing some refactoring and all of a sudden I get a huge number of C++ compiler errors that don’t make any sense. They occurred in a collection of classes connected thru inheritance. Ever since, I’ve been unable to install this code on my ESP8266. I’ve gone thru all the suggestions about my build environment that I have found with no solution. I’m getting 180 errors on code that is clean. Here is some of the code that is offending. I checks fine on ChatGPT. I haven’t figured out how to compile if using C++ compiler from the command line, but all classes in the project have Clion green arrows in the upper right corner. I’m getting a little desperate now. Any further ideas? The project is private, but I have no problem sharing the entire thing here. Thanks.

#pragma once

#include "BumperDigitalState.h"
#include "BumperState.h"
#include "DetectModeState.h"
#include "EventPublisher.h"
#include "PinConfig.h"
#include "RailState.h"
#include "SharedState.h"
#include "SimpleUncouplerState.h"
#include "TrackPowerMonitor.h"
#include "TurnoutPositionState.h"
#include "TurnoutState.h"
#include "TurnoutTrackState.h"
#include "UncouplerState.h"
#include <cstdint>
#include <map>
#include <chrono>
using std::chrono::duration_cast;
using std::chrono::high_resolution_clock;
using std::chrono::microseconds;
using std::chrono::seconds;
using std::chrono::system_clock;
using std::chrono::time_point;

class AppState {

public:
    AppState();

    explicit AppState(PinConfig *analogPinConfig);

    virtual ~AppState();

    virtual void activate();

    virtual void adjust();

    virtual void addDigitalPinConfig(PinConfig *pinConfig);

    virtual void bumpServoCount();

    static AppState *createAppState(PinConfig *analogPinConfig);

    [[nodiscard]] uint16_t getOnWidth() const;

    void setDigitalPinConfig(PinConfig *pinConfig);

    virtual void processMessage(const char* string, const char* message);

    virtual void publishChanges(EventPublisher *publisher, TrackPowerMonitor *trackPowerMonitor);

    virtual void publishCurrentState(EventPublisher *publisher, TrackPowerMonitor *trackPowerMonitor);

    void setOnWidth(uint16_t onWidth);

    virtual void updateStatus(long long currentTime, SharedState *sharedState);

protected:
    enum TrackState {
        EMPTY,
        CAR_OCCUPIED,
        ENGINE_OCCUPIED
    };

    const char* emptyMessage = "EMPTY";
    const char* carMessage = "CAR";
    const char* engineMessage = "ENGINE";
    const char* activeMessage = "ACTIVE";
    const char* inactiveMessage = "INACTIVE";
    const char* unknownMessage = "UNKNOWN";
    const char* blockTopic = "trains/blockTopic";
    const char* sensorTopic = "trains/sensorTopic";
    const long long DEBOUNCE_TIME {5000};
    const long long PULSE_PERIOD {50000};

    TrackState trackState = EMPTY;
    bool trackStateChanged = true;
    long long stableTime {};
    bool pendingDebounce = false;

    PinConfig* analogPinConfig {};
    PinConfig* digitalPinConfig {};
    uint16_t servoCount {0};

    char id[10] = {0};
    char *actuatorId {};
    bool hasReported {false};

    const char* concatIdToTopic(char* buffer, const char* topic);

    static bool isCarPresent(SharedState *sharedState, uint16_t mask);

    static bool isEmpty(SharedState *sharedState, uint16_t mask);

    static bool isEnginePresent(SharedState *sharedState, uint16_t mask);

    void setTrackState(TrackState state, long long currentTime);

    void updateTrackStatus(long long currentTime, SharedState* sharedState, uint16_t mask);
};
#include "AppState.h"

AppState::AppState() = default;

AppState::AppState(PinConfig *analogPinConfig) :
        analogPinConfig{analogPinConfig} {
}

void AppState::activate() {
}

void AppState::adjust() {
}

void AppState::addDigitalPinConfig(PinConfig *pinConfig) {
}

AppState::~AppState() = default;

void AppState::bumpServoCount() {
}

const char *AppState::concatIdToTopic(char* messageBuffer, const char *topic) {
    strcat(messageBuffer, topic);
    strcat(messageBuffer, "/");
    strcat(messageBuffer, id);
    return messageBuffer;
}

AppState * AppState::createAppState(PinConfig *analogPinConfig) {
    switch (analogPinConfig->pinType) {
        case bumperAnalog:
            return new BumperState(analogPinConfig);

        case bumperDigital:
            return new BumperDigitalState(analogPinConfig);

        case detectModeDigital:
            return new DetectModeState(analogPinConfig);

        case railAnalog:
            return new RailState(analogPinConfig);

        case simpleUncouplerAnalog:
            return new SimpleUncouplerState(analogPinConfig);

        case simpleUncouplerDigital:
            return new SimpleUncouplerState(analogPinConfig);

        case turnoutAnalog:
            return new TurnoutState(analogPinConfig);

        case turnoutDigital:
            return new TurnoutState(analogPinConfig);

        case turnoutPosition:
            return new TurnoutPositionState(analogPinConfig);

        case turnoutTrack:
            return new TurnoutTrackState(analogPinConfig);

        case uncouplerAnalog:
            return new UncouplerState(analogPinConfig);

        case uncouplerDigital:
            return new UncouplerState(analogPinConfig);

        default:
            Serial.print("Error creating AppState object of type: ");
            Serial.println(analogPinConfig->pinType);
    }
    return nullptr;
}

uint16_t AppState::getOnWidth() const {
    return analogPinConfig->onWidth;
}

bool AppState::isCarPresent(SharedState *sharedState, uint16_t mask) {
    return sharedState->getLowAnalogValues(mask) != 0;
}

bool AppState::isEmpty(SharedState *sharedState, uint16_t mask) {
    return sharedState->getLowAnalogValues(mask) == 0 &&
           sharedState->getHighAnalogValues(mask) == 0;
}

bool AppState::isEnginePresent(SharedState *sharedState, uint16_t mask) {
    return sharedState->getHighAnalogValues(mask) != 0;
}

void AppState::processMessage(const char* string, const char* message) {
}

void AppState::setOnWidth(uint16_t value) {
    analogPinConfig->onWidth = value;
}

void AppState::publishChanges(EventPublisher *publisher, TrackPowerMonitor *trackPowerMonitor) {
    if (!hasReported || (trackStateChanged && !trackPowerMonitor->isShutdown())) {
        char messageBuffer[64] {0};
        switch (trackState) {
            case EMPTY:
                publisher->publishEvent(concatIdToTopic(messageBuffer, blockTopic), emptyMessage);
                break;

            case CAR_OCCUPIED:
                publisher->publishEvent(concatIdToTopic(messageBuffer, blockTopic), carMessage);
                break;

            case ENGINE_OCCUPIED:
                publisher->publishEvent(concatIdToTopic(messageBuffer, blockTopic), engineMessage);
                break;
        }
        trackStateChanged = false;
    }
    hasReported = true;
}

void AppState::publishCurrentState(EventPublisher *publisher, TrackPowerMonitor *trackPowerMonitor) {
    char messageBuffer[64] {0};
    switch (trackState) {
        case EMPTY:
            publisher->publishEvent(concatIdToTopic(messageBuffer, blockTopic), emptyMessage);
            break;

        case CAR_OCCUPIED:
            publisher->publishEvent(concatIdToTopic(messageBuffer, blockTopic), carMessage);
            break;

        case ENGINE_OCCUPIED:
            publisher->publishEvent(concatIdToTopic(messageBuffer, blockTopic), engineMessage);
            break;
    }
}

void AppState::setDigitalPinConfig(PinConfig *pinConfig) {
    digitalPinConfig = pinConfig;
}

void AppState::setTrackState(TrackState state, long long currentTime) {
    trackState = state;
    stableTime = currentTime;
    pendingDebounce = true;
}

void AppState::updateStatus(long long currentTime, SharedState *sharedState) {
}

void AppState::updateTrackStatus(long long currentTime, SharedState* sharedState, uint16_t mask) {
    if (sharedState->hasInputChanged(mask)) {
        switch (trackState) {
            case EMPTY:
                if (isEnginePresent(sharedState, mask)) {
                    setTrackState(ENGINE_OCCUPIED, currentTime);
                } else if (isCarPresent(sharedState, mask)) {
                    setTrackState(CAR_OCCUPIED, currentTime);
                }
                break;

            case CAR_OCCUPIED:
                if (isEnginePresent(sharedState, mask)) {
                    setTrackState(ENGINE_OCCUPIED, currentTime);
                } else if (isEmpty(sharedState, mask)) {
                    setTrackState(EMPTY, currentTime);
                }
                break;

            case ENGINE_OCCUPIED:
                if (!isEnginePresent(sharedState, mask)) {
                    if (isCarPresent(sharedState, mask)) {
                        setTrackState(CAR_OCCUPIED, currentTime);
                    } else {
                        setTrackState(EMPTY, currentTime);
                    }
                }
                break;
        }
    }

    if (pendingDebounce && (currentTime - stableTime) > DEBOUNCE_TIME.count()) {
        pendingDebounce = false;
        trackStateChanged = true;
    }
}
#pragma once

#include "AppState.h"

class BumperDigitalState final : public AppState {

public:
    explicit BumperDigitalState(PinConfig *analogPinConfig);

    void updateStatus(long long currentTime, SharedState *sharedState) override;

private:
    enum BumperState {
        UNKNOWN,
        EMPTY,
        OCCUPIED
    };
    BumperState currentState = UNKNOWN;

    bool isEmpty(SharedState *sharedState);

    bool isOccupied(SharedState *sharedState);

    void setCurrentState(BumperState newState);
};
#include "BumperState.h"

BumperState::BumperState(PinConfig *analogPinConfig) : AppState(analogPinConfig) {
}

void BumperState::updateStatus(long long currentTime, SharedState* sharedState) {
    uint16_t mask = 1 << analogPinConfig->firstPin;
    updateTrackStatus(currentTime, sharedState, mask);
}

Without knowing the errors and a MRE including your platformio.ini it is likely impossible to figure out what’s going on.

How can I get you what you need. I don’t know how to attach a zip file to this topic.

Thanks

A MRE (Minimal Reproducible Example) should consist only of a few small files. Just to reproduce the error. So a ZIP should not be necessary. The MRE and the platformio.ini can be posted as pre-formatted text to keep the formatting and thus the readability.

Okay, I think the four files I’ve included and the .ini file should do then.

[env:nodemcuv2]
platform = espressif8266
board = nodemcuv2
framework = arduino
board_build.filesystem = littlefs
monitor_speed = 115200
;upload_protocol = espota
;upload_port = 192.168.1.31
;upload_flags = --auth=if6Were9!
upload_port = /dev/cu.usbserial-0001

lib_deps =
bblanchon/ArduinoJson@~7.4.2
ottowinter/ESPAsyncWebServer-esphome@^3.4.0
knolleary/PubSubClient@~2.8
links2004/WebSockets@2.4.1

If you can’t reproduce the problem with these, give me a hint as to what else you might need.

Thanks for doing this.

Unfortunatley not, as the files are not named and also include a lot of other files which are not provided. Please provide a minimal (smallest possible) example that is able to build.

On second thought, I’ll give you main.cpp and one other class that links main to AppState. I could have paired each one down I’m sure, but I want to make sure that there is enough for you to reproduce the problem. If feel so weird that I’ve been working on this code for over 2 years and it just so quickly stopped compiling cleanly.

#include <Arduino.h>
#include <ArduinoOTA.h>
#include "MqttController.h"
#include "SystemStatus.h"
#include "WifiInitializer.h"
#include "WifiOtaHandler.h"
#include "StateSendMonitor.h"
#include "TrackPowerMonitor.h"

MqttController messageController;
TrackPowerMonitor trackPowerMonitor;
StateSendMonitor stateSendMonitor;
EventPublisher *publisher = new EventPublisher(&messageController);
SystemStatus *systemStatus = new SystemStatus(publisher, &trackPowerMonitor, &stateSendMonitor);
WifiInitializer *initializer = new WifiInitializer(systemStatus);

void callback(char* topic, const byte* payload, unsigned int length) {
    systemStatus->messageReceived(topic, payload, length);
}

void setup() {
    Serial.begin(115200);
    Serial.println();
    Serial.println("Starting application");

    // Initialize LittleFS
    if (!LittleFS.begin()) {
        Serial.println("An Error has occurred while mounting LittleFS");
        return;
    }

    WifiOtaHandler::onStart([]{
        String type;
        if (ArduinoOTA.getCommand() == U_FLASH) {
            type = "sketch";
        } else { // U_FS
            type = "filesystem";
        }

        // NOTE: if updating FS, this would be the place to unmount FS using FS.end()
        Serial.println("Start OTA updating " + type);
    });
    WifiOtaHandler::onEnd([]{
        Serial.print("Ending OTA");
    });
    WifiOtaHandler::onProgress([](unsigned int progress, unsigned int total) {
        Serial.printf("Progress: %u%%\r\n", (progress / (total / 100)));
    });
    WifiOtaHandler::onError([](ota_error_t error) {
        Serial.printf("Error[%u]: ", error);
        if (error == OTA_AUTH_ERROR) Serial.println("Auth Failed");
        else if (error == OTA_BEGIN_ERROR) Serial.println("Begin Failed");
        else if (error == OTA_CONNECT_ERROR) Serial.println("Connect Failed");
        else if (error == OTA_RECEIVE_ERROR) Serial.println("Receive Failed");
        else if (error == OTA_END_ERROR) Serial.println("End Failed");
    });

    initializer->begin();
    messageController.findServerIp();
    WifiOtaHandler::begin();
    systemStatus->begin();
    systemStatus->setCallback(callback);
}

void loop() {
    if (systemStatus->loop()) {
        messageController.loop();
        WifiOtaHandler::loop();
    }
#pragma once

#include "ArduinoJson.h"
#include "BoardStatus.h"
#include "EventPublisher.h"
#include "IoBoardController.h"
#include "LittleFS.h"
#include "SelfTestActivator.h"
#include "state/AppState.h"
#include "StateSendMonitor.h"
#include "TrackPowerMonitor.h"
#include "WebSocketsHandler.h"
#include <cstdlib>
#include <utility>
#include <vector>


const microseconds SYSTEM_SCAN_INTERVAL {10000};
const microseconds PUSH_DATA_DELAY {1000000};
const microseconds SELF_TEST_TIME {1000000};
const long long MINIMUM_PULSE_PERIOD {50};

struct Board {
    std::vector<PinConfig *> analog {};
    std::vector<PinConfig *> digital {};
};

class SystemStatus {

public:
    SystemStatus(EventPublisher *publisher, TrackPowerMonitor *trackPowerMonitor, StateSendMonitor *stateSendMonitor);

    void begin();

    void loadFromFile();

    bool loop();

    void messageReceived(char* topic, const byte* payload, unsigned int length);

    void once(String &result);

    void refresh(String &result);

    void saveToFile(String &result) const;

    void setCallback(MQTT_CALLBACK_SIGNATURE);

    void updateOnWidth(const char* id, uint16_t value, String &result);

    ~SystemStatus();

private:
    enum SystemUpdateState {
        READING_BOARDS,
        PROCESS_CHANGES,
        WRITING_BOARDS,
        SEND_BOARD_PULSES,
        PUBLISH_EVENTS,
        WAITING_TIMEOUT
    };
    EventPublisher *eventPublisher;
    TrackPowerMonitor *trackPowerMonitor;
    SelfTestActivator selfTestActivator {};
    StateSendMonitor *stateSendMonitor;
    WebSocketsHandler webSockets{};

    struct compare
    {
        bool operator()(char const *a, char const *b) const
        {
            return std::strcmp(a, b) < 0;
        }
    };

    Board systemBoards[4];
    std::map<uint8_t, BoardStatus*> boardStateMap {};
    std::map<uint8_t, BoardStatus*>::iterator currentBoard;
    SharedState* sharedStateMap{};
    std::map<const char*, AppState *, compare> idStates {};
    std::map<const char*, AppState *, compare> actuatorStates {};
    SystemUpdateState updateState = {WAITING_TIMEOUT};
    long long startTime{};
    long long lastScanTime {};
    long long lastCountTime {};
    long long lastDataPush {};
    uint8_t controllerId {0};
    uint16_t loopCount {0};
    uint16_t loopRate {0};
    uint16_t eventsReceived {0};
    char uncouplerId[10] = {0};
    unsigned short uncouplerOnWidth {0};
    String fileName = "controller.json";
    String version = "1.3.6";
    uint16_t selfTestPointer {0};
    long long selfTestTime {};

    void activateUncoupler(const char * id);

    static long long clockTime();

    void load(JsonDocument& doc);

    static String getUptime();

    void publishCurrentState();

    static bool isAnalogPin(PinConfig* pinConfig);

    static bool isDigitalPin(PinConfig* pinConfig);

    void pushData();

    void selfTest(long long currentTime);
};
#include "SystemStatus.h"

SystemStatus::SystemStatus(EventPublisher *publisher, TrackPowerMonitor *powerMonitor, StateSendMonitor *sendMonitor) :
        eventPublisher{publisher}, trackPowerMonitor{powerMonitor}, stateSendMonitor{sendMonitor} {
}

void SystemStatus::activateUncoupler(const char *id) {
    auto it = idStates.find(id);
    if (it != idStates.end()) {
        it->second->activate();
    }
}

void SystemStatus::begin() {
    loadFromFile();
    IoBoardController::begin();
    for (auto [fst, snd] : boardStateMap) {
        IoBoardController::setBoardStatus(snd);
        IoBoardController::initializePort();
    }
    Serial.print("Loaded config file for controller ");
    Serial.println(controllerId);
    startTime = clockTime();
    trackPowerMonitor->begin();
    eventPublisher->begin();
    webSockets.begin();
    auto clock = high_resolution_clock::now();

    currentBoard = boardStateMap.begin();
}

long long SystemStatus::clockTime() {
    auto clock = high_resolution_clock::now();
    auto duration = clock.time_since_epoch();
    return duration_cast<microseconds>(duration).count();
}

String SystemStatus::getUptime() {
    auto now = system_clock::now();
    auto duration = now.time_since_epoch();
    uint32_t secondsCount = duration_cast<seconds>(duration).count();
    uint32_t minutes = (secondsCount / 60) % 60;
    uint32_t hours = secondsCount / 3600;
    return String(hours) + ":" +
           ((minutes < 10) ? "0" : "") + String(minutes) + ":" +
           ((secondsCount % 60 < 10) ? "0" : "") + String(secondsCount % 60);
}

bool SystemStatus::isAnalogPin(PinConfig* pinConfig) {
    return pinConfig->pinType >= bumperAnalog && pinConfig->pinType <= uncouplerAnalog;
}

bool SystemStatus::isDigitalPin(PinConfig* pinConfig) {
    return pinConfig->pinType >= detectModeDigital && pinConfig->pinType <= uncouplerDigital;
}

void SystemStatus::load(JsonDocument& doc) {
    controllerId = doc["controller"];
    trackPowerMonitor->setId(doc["trackPowerMonitorId"]);
    stateSendMonitor->setId(doc["stateSendMonitorId"]);

    auto boards = doc["boards"].as<JsonArray>();
    uint8_t address;

    for (auto boardRef: boards)
    {
        JsonObjectConst board = boardRef["board"];
        address = board["address"];
        auto pins = board["digital"].as<JsonArrayConst>();
        auto* newStatus = new BoardStatus(address, new SharedState());

        for (auto pin: pins) {
            auto* newPinConfig = new PinConfig();
            newPinConfig->load(pin);
            systemBoards[address].digital.push_back(newPinConfig);

            if (!isDigitalPin(newPinConfig)) {
                break;
            }

            auto appState = AppState::createAppState(newPinConfig);
            appState->addDigitalPinConfig(newPinConfig);

            idStates.insert(std::pair(newPinConfig->id, appState));
            if (strlen(newPinConfig->actuatorId) > 0) {
                actuatorStates.insert(std::pair(newPinConfig->actuatorId, appState));
            }
        }

        pins = board["analog"].as<JsonArrayConst>();

        for (auto pin: pins) {
            auto* newPinConfig = new PinConfig();
            newPinConfig->load(pin);
            systemBoards[address].analog.push_back(newPinConfig);

            if (!isAnalogPin(newPinConfig)) {
                break;
            }
            auto it = idStates.find(newPinConfig->id);
            if (it != idStates.end()) {
                auto appState = it->second;
                appState->setDigitalPinConfig(newPinConfig);
                if (strlen(newPinConfig->actuatorId) > 0) {
                     actuatorStates.insert(std::pair(newPinConfig->actuatorId, appState));
                }
            } else {
                auto appState = AppState::createAppState(newPinConfig);
                appState->setDigitalPinConfig(newPinConfig);
                idStates.insert(std::pair(newPinConfig->id, appState));
                if (strlen(newPinConfig->actuatorId) > 0) {
                    actuatorStates.insert(std::pair(newPinConfig->actuatorId, appState));
                }
            }
        }
        boardStateMap.insert(std::pair(address, newStatus));
    }

    currentBoard = boardStateMap.begin();
    updateState = READING_BOARDS;
}

void SystemStatus:: loadFromFile() {
    if (LittleFS.exists(fileName)){
        File file = LittleFS.open(fileName, "r");
        JsonDocument doc;
        DeserializationError err = deserializeJson(doc, file);
        if (err) {
            Serial.print(("deserializeJson() failed with code "));
            Serial.println(err.c_str());
        } else {
            doc.shrinkToFit();
            load(doc);
        }
    } else {
        Serial.print("Could not find file: ");
        Serial.println(fileName);
    }
}

bool SystemStatus::loop() {
    auto currentTime = clockTime();
    loopCount++;

    bool result = false;
    if (currentTime >= lastCountTime ) {
        lastCountTime += MINIMUM_PULSE_PERIOD;
        auto board= currentBoard->second;
        switch (updateState) {
            case READING_BOARDS:
                selfTest(currentTime);
                updateState = PROCESS_CHANGES;
                IoBoardController::setBoardStatus(board);
                IoBoardController::readBoardState();
                break;

            case PROCESS_CHANGES:
                for (auto [fst, snd]: idStates) {
                    snd->bumpServoCount();
                    snd->updateStatus(currentTime, sharedStateMap);
                }
                updateState = WRITING_BOARDS;
                break;

            case WRITING_BOARDS:
                IoBoardController::writeBoardState();
                updateState = SEND_BOARD_PULSES;
                break;

            case SEND_BOARD_PULSES:
                updateState = READING_BOARDS;
                currentBoard++;
                if (currentBoard == boardStateMap.end()) {
                    currentBoard = boardStateMap.begin();
                    updateState = PUBLISH_EVENTS;
                }
                break;

            case PUBLISH_EVENTS:
                for (auto appState: idStates) {
                    appState.second->publishChanges(eventPublisher, trackPowerMonitor);
                }
                trackPowerMonitor->publishEvents(eventPublisher);
                stateSendMonitor->publishEvents(eventPublisher);
                updateState = WAITING_TIMEOUT;
                break;

            case WAITING_TIMEOUT:
                if (currentTime >= lastScanTime) {
                    while (currentTime >= lastScanTime ) {
                        lastScanTime += SYSTEM_SCAN_INTERVAL.count();
                    }
                    currentBoard = boardStateMap.begin();
                    updateState = READING_BOARDS;
                    trackPowerMonitor->loop();
                    webSockets.loop();
                    if (currentTime >= lastDataPush) {
                        while (currentTime >= lastDataPush ) {
                            lastDataPush += PUSH_DATA_DELAY.count();
                        }
                        loopRate = loopCount;
                        loopCount = 0;
                        pushData();
                    }
                }
                result = true;
                break;
        }
    }

    return result;
}

void SystemStatus::messageReceived(char* topic, const byte* payload, unsigned int length) {
    eventsReceived++;
    char *sensorId = &topic[19];
    char message[20];
    unsigned int i = 0;
    for (i = 0; i < length; i++) {
        message[i] = (char) payload[i];
    }
    message[i] = 0;

    auto appState = actuatorStates.find(sensorId);

    if (appState != actuatorStates.end()) {
         appState->second->processMessage(sensorId, message);
    }

    if (stateSendMonitor->isSensorId(sensorId)) {
        if (stateSendMonitor->processMessage(message)) {
            publishCurrentState();
        }
    }

    if (strcmp(selfTestActivator.getSensorId(), sensorId) == 0) {
        selfTestPointer = 0;
    }
}

void SystemStatus::once(String &result) {
    JsonDocument doc;
    JsonObject once = doc["once"].to<JsonObject>();
    once["controllerId"] = controllerId;
    once["ipAddress"] = WiFi.localIP().toString();
    once["swVersion"] = version;
    for (const auto& idState : idStates) {
        if (const char* foundPtr = strstr(idState.first, "U"); foundPtr != nullptr) {
            auto uncoupler = doc["uncoupler"].to<JsonObject>();
            uncoupler["id"] = idState.first;
            uncoupler["onWidth"] = idState.second->getOnWidth();
        }
    }
    serializeJson(once, result);
}

void SystemStatus::publishCurrentState() {
    for (auto appState: idStates) {
        appState.second->publishCurrentState(eventPublisher, trackPowerMonitor);
    }
    stateSendMonitor->publishCurrentState(eventPublisher);
    selfTestActivator.publishCurrentState(eventPublisher);
}

void SystemStatus::pushData() {
    String result;
    refresh(result);
    webSockets.pushData(result);
}

void SystemStatus::refresh(String &result) {
    JsonDocument doc;
    JsonObject refresh = doc["refresh"].to<JsonObject>();
    refresh["ipAddress"] = WiFi.localIP().toString();
    refresh["signalStrength"] = WiFi.RSSI();
    refresh["swVersion"] = version;
    refresh["freeHeap"] = EspClass::getFreeHeap();
    refresh["upTime"] = getUptime();
    refresh["loopRate"] = loopRate;
    refresh["eventsSent"] = eventPublisher->getEventsSent();
    refresh["eventsReceived"] = eventsReceived;
    refresh["commFailures"] = IoBoardController::getCommFailures();
    refresh["uncouplerId"] = uncouplerId;
    refresh["uncouplerOnWidth"] = uncouplerOnWidth;
    serializeJson(refresh, result);
}

void SystemStatus::saveToFile(String &result) const {
    JsonDocument doc;
    JsonObject saveToFile = doc["saveToFile"].to<JsonObject>();
    saveToFile["controllerId"] = controllerId;
    saveToFile["trackPowerMonitorId"] = trackPowerMonitor->getId();
    saveToFile["stateSendMonitorId"] = stateSendMonitor->getId();
    JsonArray boards = saveToFile["boards"].to<JsonArray>();

    for (unsigned int address = 0; address < 4; address++) {
        auto board = boards.add<JsonObject>();
        board["address"] = address;
        JsonArray analog = board["analog"].to<JsonArray>();
        JsonArray digital = board["digital"].to<JsonArray>();

        for (auto pinConfig : systemBoards[address].analog) {
            auto board_pinConfig = analog.add<JsonObject>();
            board_pinConfig["firstPin"] = pinConfig->firstPin;
            auto it = pinStringTable.find(pinConfig->pinType);
            if (it != pinStringTable.end()) {
                board_pinConfig["type"] = it->second;
            }
            board_pinConfig["id"] = pinConfig->id;
            if (strlen(pinConfig->actuatorId) > 0) {
                board_pinConfig["actuatorId"] = pinConfig->actuatorId;
            }
            if (pinConfig->onWidth) {
                board_pinConfig["onWidth"] = pinConfig->onWidth;
            }
        }

        for (auto pinConfig : systemBoards[address].digital) {
            auto board_pinConfig = digital.add<JsonObject>();
            board_pinConfig["firstPin"] = pinConfig->firstPin;
            auto it = pinStringTable.find(pinConfig->pinType);
            if (it != pinStringTable.end()) {
                board_pinConfig["type"] = it->second;
            }
            board_pinConfig["id"] = pinConfig->id;
        }
    }
    serializeJson(saveToFile, result);
}

void SystemStatus::selfTest(long long currentTime) {
    if (selfTestTime <= currentTime && selfTestPointer < 16) {
        selfTestTime += SELF_TEST_TIME.count();
        auto i {0};
        for(auto idState: idStates) {
            const char* U = "U";
            const char* foundPtr = strstr(idState.first, U);
            if (nullptr != foundPtr) {
                if (i == selfTestPointer) {
                    idState.second->activate();
                    selfTestPointer += 1;
                    break;
                }
                i++;
            }
        }
    }
}

void SystemStatus::setCallback(std::function<void(char*, uint8_t*, unsigned int)> callback) {
    eventPublisher->setCallback(std::move(callback));
}

void SystemStatus::updateOnWidth(const char* id, uint16_t value, String &result) {
    auto it = idStates.find(id);
    if (it != idStates.end()) {
        auto appState = it->second;
        appState->setOnWidth(value);
        appState->adjust();
        JsonDocument doc;
        JsonObject uncoupler = doc["uncoupler"].to<JsonObject>();
        uncoupler["id"] = id;
        auto width = it->second->getOnWidth();
        uncoupler["onWidth"] = width;
        strcpy(uncouplerId, id);
        uncouplerOnWidth = width;
        serializeJson(uncoupler, result);
        activateUncoupler(id);
    }
}

SystemStatus::~SystemStatus() {
    for (auto pair: boardStateMap) {
        delete pair.second;
    }
    boardStateMap.clear();

    for (auto pair: idStates) {
        delete pair.second;
    }
    idStates.clear();
}

Your code snippets here are still not named. Also a lot of other files are missing!
It still seems quite big for a MRE.

Maybe you should provide your full project via github.

Boy, it could take me a long time to really pair it down. If you give me your email, I can give you a link to the project in gitHub. That’s the only way I know you have the complete project to test with.

If it is a public repository, share the linke here.
If it is a private repository you can invite me via github. I’m using the same name: sivar2311
Alternatively you can send me a private message here via the forum.

Here is the URL: https://github.com/jbasiago/RailIOController. I’ve never invited anyone before.

It’s a private repo (ends up in a 404 error).
If you want to “invite” / add other users to your private repo, go to the settings tab and then choose “colaborators” on the left side.

Okay, I got it. You should be good to go.

Yes, but it seems to be a complete different project. The platformio.ini is about a atmelsam project, not esp8266 !?

I sent the text of the platform.ini a few messages back. Does the project not match that?

The platformio.ini in the github repository is:

[env:adafruit_trinket_m0]
platform = atmelsam
board = adafruit_trinket_m0
framework = arduino
upload_port = /dev/cu.usbmodem1421
lib_deps = adafruit/Adafruit DotStar@1.1.4

Sorry, wrong repository. You should now have access to the URL I sent you.

1 Like

I’m guessing you see the problem. It’s getting late for you. I’m leaving for dinner shortly. I’ll get back to this in the morning. Thanks again.

Yeah I’m still looking.
What I have noticed so far is that you marked a lot of member functions as “override” but they do not override. But there are still some error’s I did not understand yet fully… Still searching for the cause(s)

It’s a circular dependency problem!

AppState defines the base class for your child classes (BumberState, DetectModeState etc.)
The header files of the child classes includes “AppState.h”.
But at the same time “AppState.h” also includes all the header files of the child classes! → Circular Dependency!