Проблема с кодом

beliy.av
Offline
Зарегистрирован: 11.07.2021

Всем привет. Опыта в С++ у меня нет совсем. Не могу понять, что происходит не так в моем коде.

Цель - написать менеджер состояний. Регистрируем состояние и callback функцию для этого состояния. в loop, при каждой итерации вызываем tick(), который должен смотреть на текущее состояния и запускать callback, который ему соответсвует.

state.h

#ifndef _STATE_CPP_
#define _STATE_CPP_

enum SystemStates
{
    INITIALIZE = 0, // инициализация при запуске
    INIT_FAILED = 1, //  когда предполетная проверка провалилась
    READY = 2, // готовность к старту
    FLY = 3, // полет. Определяется по растущей высоте
    LANDING = 4, // снижение
    LANDED = 5 // произошла посадка определяется по неподвижности
};

typedef void (*state_tick_clb)();

class StateManager {
    public:
        StateManager();
        void register_state(int state,  state_tick_clb clb);
        void set_state(int state);
        void tick();

    private:
        int internal_states[3];
        state_tick_clb clb[];

        int states_count;
        int active_state;
};

#endif

state.cpp

#include <Arduino.h>
#include "state.h"


StateManager::StateManager() {
    states_count = 0;
}

void StateManager::register_state(int state,  state_tick_clb c) {
    internal_states[states_count] = state;
    clb[states_count] = c;

    Serial.print("Register state ");
    Serial.print(state);
    Serial.print(" postion ");
    Serial.println(states_count);

    states_count += 1;
}


void StateManager::set_state(int state) {
    Serial.print("states_count = ");
    Serial.println(states_count);
    for (int i=0; i < states_count; ++i) {
        Serial.print("Check state ");
        Serial.println(internal_states[i]);
        
        if (internal_states[i] == state) {
            active_state = internal_states[i];
            Serial.print("SET STATE ");
            Serial.println(internal_states[i]);
            return;
        }
    }

    Serial.print("STATE NOT FOUND ");
    Serial.println(state);
}

void StateManager::tick() {
    Serial.print("TICK WITH STATE ");
    Serial.println(active_state);
}

 

main.cpp

#include <Arduino.h>
#include <state.h>


StateManager sm;

void state1() {
  Serial.println("state 1");
}

void state2() {
  Serial.println("state 2");
}

void state3() {
  Serial.println("state 3");
}


void setup() {
  Serial.begin(9600);
  sm.register_state(INITIALIZE, &state1);
  sm.register_state(READY, &state2);
}

bool c1 = false;
bool c2 = false;

void loop() {
  sm.tick();
  delay(1000);
  if (millis() > 5 * 1000 && !c1) {
    sm.set_state(READY);
    c1 = true;
  }
  if (millis() > 10 * 1000 && !c2) {
    sm.set_state(INITIALIZE);
    c2 = true;
  }
}

 

 

Проблемы:Даже при первом вызове register_state, states_count почему-то не 0. В логе записи

Register state 0 postion 2294
Register state 2 postion 2295
 
 
Ну и дальше начинаются какие-то приколы, такое ощущение что в массив internal_state записывается мусор, но я не могу понять где я не прав. Полный лог:
 
Register state 0 postion 2294
Register state 2 postion 2295
TICK WITH STATE 0
TICK WITH STATE 0
TICK WITH STATE 0
TICK WITH STATE 0
TICK WITH STATE 0
states_count = 2296
Check state 0
Check state 0
Check state 0
Check state 2296
Check state 0
Check state 0
Check state 0
Check state 439
Check state 0
Check state 2573
Check state 2573
Check state 2573
Check state 2573
Check state 2573
Check state 2573
Check state 2573
Check state 2573
Check state 2573
Check state 2573
Check state 2573
Check state 2573
Check state 2573
Check state 2573
Check state 2573
Check state 0
Check state 0
Check state -1
Check state 10
Check state 10
Check state 650
Check state 2561
Check state 513
Check state 258
Check state -5632
Check state -9609
Check state -6194
Check state -1027
Check state -15390
Check state 21994
Check state -1554
Check state -25228
Check state 29563
Check state -25878
Check state -6227
Check state 27135
Check state -24610
Check state 31195
Check state -8517
Check state -358
Check state -6675
Check state 4349
Check state 3502
Check state -20554
Check state -17457
Check state -25758
Check state -24645
Check state -18179
Check state -4216
Check state -74
Check state -26773
Check state -8211
Check state -8449
Check state -129
Check state -20625
Check state -2594
Check state -10657
Check state -20558
Check state -2338
Check state 32729
Check state -1753
Check state -21562
Check state -24675
Check state -2097
Check state -3590
Check state -17508
Check state 26614
Check state -51
Check state -12739
Check state 32244
Check state 32641
Check state -2699
Check state -3981
Check state -26753
Check state 13749
Check state 11455
Check state 13726
Check state -4375
Check state 16055
Check state -513
Check state 15273
Check state -533
Check state -11524
Check state -4521
Check state -3587
Check state 16327
Check state 16054
Check state -24837
Check state -24846
Check state -8531
Check state -18035
Check state 10391
Check state -10241
Check state -5155
Check state -10291
Check state 13861
Check state -833
Check state 30693
Check state -11590
Check state -5192
Check state -906
Check state 12287
Check state -23649
Check state 28297
Check state 20433
Check state -5329
Check state 24183
Check state -1041
Check state 31690
Check state -4689
Check state 15193
Check state 15695
Check state 28069
Check state -16953
Check state -69
Check state -9
Check state 31739
Check state -4125
Check state 23757
Check state 14282
Check state -13844
Check state -1223
Check state -18571
Check state 10520
Check state -9
Check state -4197
Check state 32765
Check state -24597
Check state 24535
Check state -12435
Check state -459
Check state 32477
Check state -16386
Check state -6936
Check state -201
Check state -1353
Check state 12408
Check state -26113
Check state -3083
Check state -2050
Check state -25729
Check state -2012
Check state -173
Check state 27439
Check state -22027
Check state -6183
Check state 23486
Check state 31085
Check state -23813
Check state -2191
Check state 16127
Check state -9993
Check state -10562
Check state 15597
Check state -18562
Check state 30587
Check state 2139
Check state -1610
Check state -269
Check state -4935
Check state 3710
Check state 29918
Check state 31561
Check state 24562
Check state 28143
Check state -16666
Check state 17982
Check state -4129
Check state 21471
Check state -16463
Check state -7251
Check state -2253
Check state -22089
Check state 3321
Check state 13883
Check state -21513
Check state -16645
Check state -16985
Check state -30523
Check state 15231
Check state 28652
Check state 32254
Check state 14653
Check state -47
Check state 18189
Check state -24648
Check state -24581
Check state -3468
Check state -24833
Check state -28683
Check state -17243
Check state -5961
Check state -4594
Check state -8260
Check state 32763
Check state 27632
Check state -3012
Check state -17797
Check state -6219
Check state -28948
Check state 29674
Check state -1028
Check state 32435
Check state -10538
Check state -9
Check state 32486
Check state 9227
Check state 31900
Check state 23288
Check state 28670
Check state -3347
Check state -7538
Check state -29200
Check state -1060
Check state -11866
Check state -24755
Check state 11455
Check state -2689
Check state 29411
Check state -22022
Check state -16673
Check state -26634
Check state 19324
Check state -5129
Check state -147
Check state 7816
Check state -17549
Check state 31166
Check state -10369
Check state -18867
Check state 12975
Check state 23258
Check state -23178
Check state -323
Check state -18130
Check state -9356
Check state -2714
Check state -16782
Check state 2
SET STATE 2
TICK WITH STATE 2
states_count = 2296
Check state 0
SET STATE 0
TICK WITH STATE 0
TICK WITH STATE 0
TICK WITH STATE 0
TICK WITH STATE 0
TICK WITH STATE 0
TICK WITH STATE 0
TICK WITH STATE 0
TICK WITH STATE 0
 
Очень надеюсь, что вы поможете понять, что я сделал не так, у меня уже нет идей (
rkit
Offline
Зарегистрирован: 23.11.2016

У тебя память под массив clb не выделена. Соответственно, когда ты в него пишешь, затираются следующие за ним переменные.

А вообще, в таком стиле под малопроизводительные МК не пишут.

beliy.av
Offline
Зарегистрирован: 11.07.2021

Спасибо, попробовал убрать clb в самый низ и все стало ОК. Тогда надо либо выделять заранее, через new, либо делать realloc перед каждым добавлением?

Насчет стиля, я не очень понял что именно не так, то что не бьют на классы, или то что такую задачу решают просто переменной и switch?

rkit
Offline
Зарегистрирован: 23.11.2016

Не делают стопок коллбеков.

beliy.av
Offline
Зарегистрирован: 11.07.2021

Эм, а в чем разница? Все равно надо писать эти функции, все равно их запускать, пожертвовать немного памяти на то что бы хранить указатели на эти функции - что тут страшного?

Если это чисто стиллистически не верно, то тема холиварная, конечно

rkit
Offline
Зарегистрирован: 23.11.2016

Статический анализ расхода ресурсов, отладка.

Logik
Offline
Зарегистрирован: 05.08.2014

rkit пишет:

Не делают стопок коллбеков.

От если бы ты написал не делают динамических стопок коллбеков, то это  было бы и правда и понятно. Смыслу их регистрировать... А статически - да сколько угодно.

typedef struct
{
  const char* name;
  bool (*Cmd) (void);
} WebCommand;


WebCommand ArrWebCommand[]={

 "GET /AUTO",[](){SendCmd=0xe1;return false;},
 "GET /RESET",[](){SendCmd=0xb4;AddLog("RESET");return true;},
 "GET /STOP",[](){SendCmd=0xa5;return true;},
};

....
            for(uint8_t i=0;i<sizeof(ArrWebCommand)/sizeof(WebCommand);i++)
            {
             if (header.indexOf(ArrWebCommand[i].name) >= 0) 
             {

               if(ArrWebCommand[i].Cmd)
                  FlSendHTML=ArrWebCommand[i].Cmd();
               break;
             }
            }



И если хош действительно нумеровать состояния - так смыслу в internal_states? считай номер состояния индексом для clb. Но память под clb выдели.

rkit
Offline
Зарегистрирован: 23.11.2016

И так не делают. Тупо лишние буквы.

wdrakula
wdrakula аватар
Offline
Зарегистрирован: 15.03.2016

Даже для "малопроизводительных МК" пишут в первую очередь ЧИТАЕМЫЙ и сопровождаемый код. Поскольку эмбеддинг отличается от программирования ПК, в первую очередь тем, что сэкономленные ресурсы "на привозе" не продашь. Твой код их ни  с кем не делит. Если ресурсов достаточно, нужно писать классический, читаемый код. Начинать изгаляться с экономией нужно исключительно тогда, когда ресурсы на пределе. Если "охранник с пистолетом" не стоит за спиной, то лучше взять другой МК, чем поганить код. Стоимость МК сегодня не является определяющей даже в крупносерийном производстве.

Иначе получаются те, карикатурные "эмбеддеры" из статьи на Хабре. Логик знает - из какой. Я ссылку сейчас не найду.

=====================

Логик. Абсолютно нормальный пример. Мне остается только гадать, с манерой коллеги Ркита НЕ ПОЯСНЯТЬ свои тезисы. Думаю, что он на лямбду возбудился. Которая добавит пару тактов при исполнении кода.

Но если убрать лямбду и перенести код обработчиков прямо в свитч, то потеряется читаемость. Я выберу читаемость против пары тактов.

Пояснять он все равно ничего не станет. ;)))

rkit
Offline
Зарегистрирован: 23.11.2016
FlSendHTML = false;
switch(parse_header_line()) {
	case {HTTP_GET, "/AUTO"}:
		SendCmd = 0xe1;
		break;
	case {HTTP_GET, "/RESET"}:
		SendCmd = 0xb4;
		AddLog("RESET");
		FlSendHTML = true;
		break;
	case {HTTP_GET, "/STOP"}:
		SendCmd = 0xa5;
		FlSendHTML = true;
		break;
	default:
		break;
}



Вот так пишут, если на С++;

За три инструкции в одну строчку, или за >= в любой серьезной компании вставят такого пенделя, что мало не покажется.

wdrakula
wdrakula аватар
Offline
Зарегистрирован: 15.03.2016

Ну я же так и сказал. На лямбду возбудился. ;))

А если еще есть вызовы, то в 10 местах будем эту "одну строчку" писать... и править, при изменении?

Логик же просто иллюстрацию привел. Если бы в коде было ТОЛЬКО то, что он написал, то вариант Ркит-а, конечно рулит.

Ну и парсер тоже отдельная тема. Он есть? А если нет? Не все пишется на ESP32, ты же понимаешь это?

--------------------------------

Ты написал, что вообще не стоит применять стопки колбэков в эмбедде? И Логик и я - не согласны. Как любое обобщение - высказывание ложно. Или я тебя не правильно понял, что возможно.

Если есть хоть 10% вероятности повторного использования кода в проекте, его нужно выделять в отдельное место. Объект, метод, функцию, лямбду - похеру, но отдельно. В примере Логика не было кода действий, поэтому твой вариант рулит. Не так?

Думаю у всех есть опыт анализа чужого "говнокода", где одна и та же последовательность действий повторена в коде в 20+ местах? Особенно этим всратые pHp-шники грешат! Поубивал бы гадов! ;)))))))

wdrakula
wdrakula аватар
Offline
Зарегистрирован: 15.03.2016

Сорри, не заметил про "три инструкции"  - ну это ж смешно. Автоформатер расставит их по отдельным строчкам. Это ж пример был просто. ">="  ? Серьезно? Ну и как тогда пользоваться indexof, если ">=" как раз и означает вхождение? Это уж сродни МИСРА, не к ночи её поминать.

Logik
Offline
Зарегистрирован: 05.08.2014

rkit пишет:

За три инструкции в одну строчку, или за >= в любой серьезной компании вставят такого пенделя, что мало не покажется.

В любой серьёзной компании, обративший внимание на такое сразу бы получил дружеское предупреждение от ПМ-а за токсичность. Если бы не унялся - не очень дружеский разговор о причинах желания потратить человекодни на задачу, не дающую фирме прибыли, возможно с предложением лично заняться этой задачей в время свободное от основных оплачиваемых. И не дай бог при этом отламать чего )))) При дальнейшем непонимании к общению подключились бы HR-ы, ответственные за психологический климат команды и начал бы задавать дурные вопросы. Вот дальше этого ни один известный мне не прошёл, возможно и отстранили бы, перевели куда.. Но айтишники обычно соображают что оно того не стоит.

То, о чем ты написал, тоже наблюдается, как правило в остатках НИИ, шарагах и старых фирм, где есть некий "аксакал" который уже глубоко в маразме, в коде и задаче шарит слабо, но его авторитет большой. Что ему остаётся? Проверяет отступы, ищет ошибки в именах идентификаторов, проверяет не боле ли 80 символов в строке, иногда пробелы вставляет, потом удаляет... Работает как может)))) Но разрабы то понимают ситуацию, так что не обижаются даже))) А вот если кто молодой такое отчубучит - очень плохо, сразу подозрение в отсутствии знания и умения, т.к. из всего что нужно делать видит только херню.

Я смотрю, rkit, ты из аксакалов. То, что поиск идёт перебором тебя никак не смутило. В алгоритм не лезеш. Зато три инструкции- проблема!

Green
Offline
Зарегистрирован: 01.10.2015

Но ты же обычный текст пишешь правильно? Начало предложения с заглавной, запятые там где надо, отступы, пустые строки... Так почему же ты в программе так не делаешь? Почему кто то должен голову ломать что бы понять что ты там хотел сказать? На кой это надо, заниматься раскодированием написанного! И вот это как раз и есть культура, иначе это пох*изм или разпи*дяйство писателя.

Logik
Offline
Зарегистрирован: 05.08.2014

//пишеш правильно...

не. Не всегда. Главное смысл а не форма. И если у чела сложности из за перечисленных проблем, то на понимание смысла можно и не рассчитывать. Ну серьёзно, поймёт ли глубину философской идеи некой книги человек, у которого сложности вызывает строчная буква на месте заглавной?

//На кой это надо, занимается раскодированием...

Вот. Не надо. Если три инструкции у читающего вызывают необходимость раскодирования, то можно считать, что код написан не для его уровня, внутри ещё сложней все и не надо туда лезть. Для того кто осилит суть три инструкции в строке не должны быть проблемой. Ослиный мостик называется.

b707
Offline
Зарегистрирован: 26.05.2017

Logik пишет:

не. Не всегда. Главное смысл а не форма. И если у чела сложности из за перечисленных проблем, то на понимание смысла можно и не рассчитывать.

ерунду ты пишешь. Сам для себя ты можешь писать как угодно (хотя тоже непонятно, зачем писать криво?)

Но если ты работаешь в команде - форма зачастую важнее смысла. Твой коллега. который работает с этим же кодом - не должен тратить время на вникание в смысл твоего кода, замусоренный кривой формой. это непроизводительная трата ресурса компании.

Рассказы про неких HR, обращающих внимание на "качество" кода и закрывающих глаза на  оформление - это разве что в мелкой шараге , где все по свойски. В крупных конторах все формализовано - ФОРМАлизовано - форма главное.  Программиста. который плюет на стандарты оформления кода. принятые в компании - никто держать не будет даже если по смыслу его код гениален. Он просто не успеет проявить свою "гениальность" - его выгонят раньше.

DetSimen
DetSimen аватар
Offline
Зарегистрирован: 25.01.2017

b707 пишет:

Программиста. который плюет на стандарты оформления кода. принятые в компании - никто держать не будет даже если по смыслу его код гениален.

Истинно так, меня с моим дедостилем выгоняют еще на стадии тестового задания, обычно. :) 

Я уже смирился и никуда не лезу. :) 

ua6em
ua6em аватар
Offline
Зарегистрирован: 17.08.2016

пора открывать тему - пишем и оформляем код по фэншую...

BOOM
BOOM аватар
Offline
Зарегистрирован: 14.11.2018

ua6em пишет:

пора открывать тему - пишем и оформляем код по фэншую...

Только с разъяснениями почему так "по феншую", а вот так вот уже "не по феншю". Очень даже интересно (мне).

rkit
Offline
Зарегистрирован: 23.11.2016

Откровенного бага с >= ни один феншуй и не заметил.