Перейти к содержанию
    

Реализация конечного автомата на 8битном контроллере.

Всем привет!

Сейчас сделано как-то так.

Прекрасно работает, расширяется. Всем доволен, но хотелось бы сравнить с тру 8ми битным подходом. Собственно какую-нибудь хорошую реализацию конечного автомата и хотелось бы где-то посмотреть.

enum DeviceEvents
{
    DEVEV_HEARTBEAT,            //this event occures every ~100ms
    DEVEV_STARTBTN_PRESSED,
    //etc...
    DEVEV_NO_EVENT = 0xff,
}

enum DeviceState_enum
{
    DEVSTATE_OFF,               
    DEVSTATE_LOCKED,
    //etc....
    DEVSTATE_INVALID = 0xff,
}

//state interface class
struct DeviceStateImplementation
{
    virtual void EnterThisStateFrom( const DeviceState_enum &prevState ) = 0;
    //Handles event and returns new device state in response of event
    virtual DeviceState_enum HandleEvent( const DeviceEvents &event ) = 0;
};

//Implementation of DEVSTATE_OFF state
class StateImpl_OFF: public DeviceStateImplementation
{
    timestamp_t MillisecondsCounter;
    uint8_t MinutesCounter;
    bool ReactOnStartBTNRelease;

    void ResetMillisecondsCounter();
public:
    virtual void EnterThisStateFrom( const DeviceState_enum &prevState );
    virtual DeviceState_enum HandleEvent( const DeviceEvents &event );
};

//Implementation of DEVSTATE_OFF state
void StateImpl_OFF::EnterThisStateFrom( const DeviceState_enum &prevState )
{
    TurnOffAllOutputs();
    DisableRPMMeasure();
    G_SettingsStateSelector.ResetPressCounter();
    ReactOnStartBTNRelease = false;
    ResetMillisecondsCounter();
}

void StateImpl_OFF::ResetMillisecondsCounter()
{
    MillisecondsCounter = GetTickCount();
    MinutesCounter = 0;
}

DeviceState_enum StateImpl_OFF::HandleEvent( const DeviceEvents &event )
{
    DeviceState_enum retval = DEVSTATE_OFF;

    switch(event)
    {
    case DEVEV_HEARTBEAT:
        ACC_LEDBlinker.DoTheJob();

        if( G_SettingsStateSelector.GetSelectedState() != DEVSTATE_INVALID )
        {
            ACC_LEDBlinker.StartEndlessBlinkSequence(100, 100);//fast blinking indicating some settings mode was selected
        }
        break;

    case DEVEV_STARTBTN_PRESSED:
        ReactOnStartBTNRelease = true;
        break;

    case DEVEV_STARTBTN_RELEASED:
        //react on release only if press also was made in this state
        if( ReactOnStartBTNRelease )
        {
            ResetMillisecondsCounter();
            if( GlobalVarsRef.BrakePedal.GetButtonState() == GPIOBTNSTATE_PUSHED )
            {
                DeviceState_enum SelectedSettingsModeState = G_SettingsStateSelector.GetSelectedState();
                if( SelectedSettingsModeState != DEVSTATE_INVALID )
                    retval = SelectedSettingsModeState;
                else
                    retval = DEVSTATE_CRANKING;
            }
            else
            {
                retval = DEVSTATE_IGNON;
            }
        }
        break;

    case DEVEV_STARTBTN_LONGPRESS:
        if( GlobalVarsRef.BrakePedal.GetButtonState() == GPIOBTNSTATE_PUSHED )
            retval = DEVSTATE_FORCEDCRANKING;
        else
            retval = DEVSTATE_ACCON;
        break;

    case DEVEV_BREAKPEDAL_PRESSED:
        ResetMillisecondsCounter();
        G_SettingsStateSelector.SelectorWasPressed();

        ACC_LED::Clear();
        ACC_LEDBlinker.StartBlinkSequence(2, 50, 100);
        break;

    case DEVEV_BREAKPEDAL_RELEASED:
        ACC_LED::Clear();
        ACC_LEDBlinker.AbortBlinkSequence();
        break;

    case DEVEV_ENGINE_STARTED:
        retval = DEVSTATE_RUNNING;
        break;

    case DEVEV_ENGINE_STALLED:
        break;
    }

    return retval;
}

/////main state machine implementation
class MainStateMachine
{
public:
    void EnterStateForced( const DeviceState_enum &state );
    void ProcessEvent( const DeviceEvents &evnt );

private:
    DeviceStateImplementation *CurrentDevStateImplementation; //<----pointer to state interface class
    DeviceState_enum CurrentDevState;

    void SetNewDeviceState( const DeviceState_enum &newDevState );
};

void MainStateMachine::ProcessEvent( const DeviceEvents &evnt )
{
    DeviceState_enum newDevState = CurrentDevStateImplementation->HandleEvent( evnt );
    if( newDevState != CurrentDevState )
        SetNewDeviceState( newDevState );
}

void MainStateMachine::SetNewDeviceState( const DeviceState_enum &newDevState )
{
    switch( newDevState )
    {

    case DEVSTATE_OFF:
        CurrentDevStateImplementation = &OFFState;
        break;
    case DEVSTATE_LOCKED:
        CurrentDevStateImplementation = &LockedState;
        break;
    }
    CurrentDevStateImplementation->EnterThisStateFrom( CurrentDevState );
    CurrentDevState = newDevState;
}


//main loop simplifiyed
int main()
{
    while(1)
    {
        event = DEVEV_HEARTBEAT;
        while( event != DEVEV_NO_EVENT )
        {
            MainStateMachine.ProcessEvent( event );
            event = DetectOneMoreEvents();
        }
    }
}

 

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Всем доволен, но хотелось бы сравнить с тру 8ми битным подходом. Собственно какую-нибудь хорошую реализацию конечного автомата и хотелось бы где-то посмотреть.

В ИТМО есть Шалыто А.А. И у них есть сайт со статьями по "switch-тенологиям"...

is.ifmo.ru

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

iosifk, спасибо, кажется нашел пдфку с которой стоит начать http://is.ifmo.ru/books/_book.pdf

Еще в КиТ, в архиве статей 2006-11 и до 2007-8 статьи, автор Татарчевский...

 

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Всем доволен, но хотелось бы сравнить с тру 8ми битным подходом. Собственно какую-нибудь хорошую реализацию конечного автомата и хотелось бы где-то посмотреть.

Биты то при чем?

 

Реализация автомата - дело интимное. При реализации UI как автомата параметры такие:

- состояний - около сотни

- событий - два десятка (кнопки и таймеры)

- новое состояние определяется внутри обработки конкретного состояния (т.к. не все, что происходит и изменяет состояния - это события)

- изменение состояния - тоже событие (удобно для единообразия)

- Х-макросы для перечисления имен функций, названий состояний, текста в первой строке, особенностей поддержки каждого состояния (например, чистить или нет экран)

- механизм возврата в предыдущее состояние

Очень важная для меня цель была - прозрачность понимания, т.к. приходится корректировать проекты после большого перерыва.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Биты при том, что при моей нынешней реализации(которую я вкратце привел) У меня при всём удобстве в редактировании и расширении маленько так сожрало и флэша и памяти.

Труды Шалыто А.А. я конечно изучу, полезно будет по любому, но думал может ещё народ скинет разных исходников "на посмотреть".

 

Может есть что-то готовое и красиво реализованное, например как protothreads, где switch красиво обыгран макросами или я не знаю... Реализацию табличного какого-нибудь подхода глянуть.

И именно 8ми битный контроллер был обозначен для того, чтоб не приводили полномасштабных вариантов с UI

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Биты при том, что при моей нынешней реализации(которую я вкратце привел) У меня при всём удобстве в редактировании и расширении маленько так сожрало и флэша и памяти.

И именно 8ми битный контроллер был обозначен для того, чтоб не приводили полномасштабных вариантов с UI

UI - это не GUI, это всего лишь дисплей 2х16, 4 кнопки и STM8.

Давайте адрес почты, пришлю файлов, но не весь проект.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

iosifk, спасибо, кажется нашел пдфку с которой стоит начать http://is.ifmo.ru/books/_book.pdf
Хм. Читать осторожно - у неподготовленного читателя может вызвать взрыв мозга. :)

 

Что касается автоматов на МК с минимумум ресурсов (будем так называть '8ми битные контролеры') то тут явно напрашивается нечто на голом С либо в виде большого switch, либо таблицей переходов (в зависимости от количества состояний, переходов и архитектуры самого МК). А что бы не было 'мучительно больно' это все поддерживать (как минимум модифицировать) напрашивается какой нибудь генератор (либо из готовых, что были упомянуты в статье, либо что нибудь самописное на каком нибудь Perl'е или Python'е)

 

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Что касается автоматов на МК с минимумум ресурсов (будем так называть '8ми битные контролеры') то тут явно напрашивается нечто на голом С либо в виде большого switch, либо таблицей переходов
Вот на исходнички чего-нибудь такого и было бы интересно посмотреть. В частности интересно реализовать одинаковые автоматы двумя разными способами и сравнить их по быстродействию/занимаемой памяти....

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

либо в виде большого switch, либо таблицей переходов

 

уже десять лет назад IAR AVR делал таблицу из большого свича на высоких уровнях оптимизации.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Вот дойдут как-нибудь руки до сравнений и будет интересно посмотреть на результаты.

 

Так то в моей текущей реализации вызов обработчика событий идет через указатель CurrentDevStateImplementation, который является указателем на интерфейс класса, хотя записан туда адрес конкретной реализации. Что при вызове метода через этот указатель ВНЕЗАПНО :biggrin: приводит к использованию vtable https://ru.wikipedia.org/wiki/%D0%A2%D0%B0%...%B4%D0%BE%D0%B2

 

В связи с чем и становится интересно, а будет ли реальная экономия хоть чего-нибудь если все эти состояния положить в огромный switch, который потом IAR доблестно превратит в таблицу с адресами функций... Что в итоге будет снова ооочень напоминать vtable )

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

. . .

В связи с чем и становится интересно, а будет ли реальная экономия хоть чего-нибудь если все эти состояния положить в огромный switch, который потом IAR доблестно превратит в таблицу с адресами функций... Что в итоге будет снова ооочень напоминать vtable )

Смотря как компилятором реализуется работа vtable и какая "вложенность".

Если использовать правильный switch (опятьже зависит от комилятора) который генерирует "вычисляемые" переходы.

"правильный" - это в IAR конструкция

switch ( __even_in_range(TBIV, 14)  )
{ ...

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Dog Pawlowa, можно тоже исходники глянуть? [email protected]

 

А то как не крути вечно такой колхоз получается

(Передача пакета данных по usart)

void Sendpackage(void){
static uint8_t mode;
static uint16_t counter;
uint8_t* Data;
switch(mode){
	case 0:{
		//---------------------------------------------
		//--------Ожидание команды на отправку---------
		//---------------------------------------------
		if(TransmitDataStart==Transmit_START){
			TransmitDataStart=Transmit_STOP;
			Data=&Protocol;
			mode=1;
		}
		break;
	}
	//-------------------------------------------------
	case 1:{
		if(counter<sizeof(ProtocolExchange_t)){
			if(USART3->SR & USART_SR_TC){
				USART3->DR =(uint8_t)Data[counter];
				counter++;
			}
		}else{
			mode=0;
		}
		break;
	}
	//-------------------------------------------------
}
}

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Смотря как компилятором реализуется работа vtable и какая "вложенность".
Ну "вложенность" получается 1. Указатель на абстрактный класс указывает на реализацию класса.

 

Про __even_in_range() не знал, протестируем

 

Add:

Последний IAR STM8

Error[Pe020]: identifier "__even_in_range" is undefined main.cpp 140

:(

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Присоединяйтесь к обсуждению

Вы можете написать сейчас и зарегистрироваться позже. Если у вас есть аккаунт, авторизуйтесь, чтобы опубликовать от имени своего аккаунта.

Гость
Ответить в этой теме...

×   Вставлено с форматированием.   Вставить как обычный текст

  Разрешено использовать не более 75 эмодзи.

×   Ваша ссылка была автоматически встроена.   Отображать как обычную ссылку

×   Ваш предыдущий контент был восстановлен.   Очистить редактор

×   Вы не можете вставлять изображения напрямую. Загружайте или вставляйте изображения по ссылке.

×
×
  • Создать...