Автор Тема: Может кому пригодится. Подобие протопотоков-автоматов  (Прочитано 11418 раз)

Wlad

  • Jr. Member
  • **
  • Сообщений: 91
    • Просмотр профиля
Ниже - заголовочник для использования с gcc.
Я его включаю в проекты на микроконтроллерах, где не особо хочется или есть возможность использовать прерывания.
По сути реалиован "размазанный" конечный автомат.
Что непонятно - спрашивайте.

#ifndef __STATES_H__
#define __STATES_H__

#include "91x_type.h"

#include "errors.h"
#include "rtc.h"

#define STATES_BEGIN                                \
static void*   state_label = &&_L_state_START_; \
static TResult state_res;                       \
static vu32    state_finishMSec;                \
goto *state_label;                              \
_L_state_START_: {

#define STATES_END  } STATES_RESET;


#define STATES_STATE                     \
do{                                  \
__label__ _L_state_label_;       \
state_label = &&_L_state_label_; \
_L_state_label_: ;                       \
}while(0)


#define STATES_RESET                     \
do{                                  \
state_label = &&_L_state_START_; \
}while(0)


#define STATES_WAIT(condition)           \
do{                                  \
__label__ _L_state_label_;       \
state_label = &&_L_state_label_; \
_L_state_label_:                         \
if( ! (condition) ) return 1;    \
}while(0)


#define STATES_WAIT_TIMED(condition,ticks,timedout_label)           \
do{                                                             \
__label__ _L_state_label_;                                  \
state_finishMSec = RTC_msec + (ticks);                      \
state_label = &&_L_state_label_;                            \
_L_state_label_:                                                    \
if( ! (condition) ) {                                       \
if( RTC_msec >= state_finishMSec ) goto timedout_label; \
return 1;                                               \
}                                                           \
}while(0)


#define STATES_TIMER(ticks)                            \
do{                                                \
state_finishMSec = RTC_msec + (ticks);         \
STATES_WAIT( (RTC_msec >= state_finishMSec) ); \
}while(0)

#define STATES_DELAY(ticks)                   \
do{                                       \
vu32 finishMSec = RTC_msec + (ticks); \
while( RTC_msec < finishMSec );       \
}while(0)



#define STATES_OP(op,error_label) \
do{ \
__label__ _L_state_label_; \
state_label = &&_L_state_label_; \
_L_state_label_: \
if( (state_res = (op)) > 0 ) return state_res; \
if(  state_res         < 0 ) goto error_label; \
}while(0)
 
 
#endif
[/font]

Geniepro

  • Hero Member
  • *****
  • Сообщений: 1955
  • Знайте- истина в том, что повторено трижды подряд!
    • Просмотр профиля
Оригинально, не знал что так можно:
void* state_label = &&_L_state_START_;
...
goto *state_label;

Это вообще по стандарту на язык возможно? Или это расширение какого-то компилятора?
TinyCC скомпилировал нормально:
#include <stdio.h>

int main(int argc, char *argv[])
{
    void *state_label = &&_some_label_;

    goto *state_label;

    printf("Hello, world 1\n");

    _some_label_:
    printf("Hello, world 2\n");

    return 0;
}
Hello, world 2
to iterate is human, to recurse, divine

Салат «рекурсия»: помидоры, огурцы, салат…

Geniepro

  • Hero Member
  • *****
  • Сообщений: 1955
  • Знайте- истина в том, что повторено трижды подряд!
    • Просмотр профиля
Было бы неплохо увидеть авторский пример использования такого конечного автомата...
to iterate is human, to recurse, divine

Салат «рекурсия»: помидоры, огурцы, салат…

valexey_u

  • Hero Member
  • *****
  • Сообщений: 3013
    • Просмотр профиля
Y = λf.(λx.f (x x)) (λx.f (x x))

Wlad

  • Jr. Member
  • **
  • Сообщений: 91
    • Просмотр профиля
Оригинально, не знал что так можно:
void* state_label = &&_L_state_START_;
...
goto *state_label;
Это вообще по стандарту на язык возможно? Или это расширение какого-то компилятора?
Раньше (как я понимаю и помню) было расширением именно в gcc. По-моему, теперь это как часть стандарта C99 идёт. Могу ошибаться.

Пример (очень сокращённый за счёт выбрасывания чисто линых участков кода и не относящихся к исзменению состояния КА мест) примерно такой:
(взято из моей системы записи видео-, звуковой- и параметрической информации)

//////////////////////////////////////////////////////////////////////////////
static
TResult
FS_Init( void )
{
  //...
 
  STATES_BEGIN
   
    //...
   
    // HDD HEADER --------------------------------------------------------
    //...
    STATES_WAIT( tw2700Buff_busy == 0 );
    tw2700Buff_busy = &FS_Init;
   
    STATES_OP( IDE_ReadBuff( 0 ), _E_TW2700_FS_INIT_READ_HEADER_ );

    // организация заголовка на IDE устройстве
    //...
    OSD_DrawStringXY( 16, 32, "IDE header written" );
    // -------------------------------------------------------- HDD HEADER
 
    //...
   
    // last FLIGHT -------------------------------------------------------
    // поиск зписи о последнем полёте
    for( lba = FRAMES_LBA-1; lba > 0; --lba ) {
      STATES_OP( IDE_ReadBuff( lba ), _E_TW2700_FS_INIT_READ_FLIGHT_I_1_ );
      //...
      // собственно условие нахождения заголовока плёта
      //...
    }
    // ------------------------------------------------------- last FLIGHT

   
    // new FLIGHT && FIRST_FRAME -----------------------------------------
    if( flightLBA ) { // != 0 - был запсиан хотя бы один полёт / если несколько - имеем индекс последнего по времени записи
      // ... находим его первый кадр
_L_check_firstFrameLBA_:
      STATES_OP( IDE_ReadBuff( frameLBA ), _E_TW2700_FS_INIT_READ_FIRSTFRAME_ );
      // ...
      if( ! IsFlightFrame() ) {
        // ...
        while( flightLBA != lba ) {
          STATES_OP( IDE_ReadBuff( flightLBA ), _E_TW2700_FS_INIT_READ_FLIGHT_I_2_ );
          // ...
          if( /* некое условие "нехорошести" кадра */)
            goto _L_check_firstFrameLBA_;
          // ...
        }
        // ...
      }
      else {
        // ...
        // подготовка к операции поиска последнего кадра полёта
        // ...
        STATES_OP( SearchLastFrameLBA(), _E_TW2700_FS_INIT_SEARCH_LASTFRAME_ );

        // вывод номера сектора с заголовком последнего кадра полёта
        U32ToHexStr( frameLBA, static_str,4 );
        OSD_DrawStringXY( 16+(6+9+9)*OSD_FONT_WIDTH, 200+OSD_FONT_HEIGHT*0, (const char*)static_str );

        STATES_OP( IDE_ReadBuff( frameLBA ), _E_TW2700_FS_INIT_SEARCH_FRAMEHEADER_0_ );
       
        // ...
       
        // проверка на сбой питания и заполнение IDE устройства
        if( deltaTime > 60*1000 ) frameLBA = FRAMES_LBA;
        else {
          // disk is FULL ?
          if( (frameLBA += pFrameDesc->_LBAs+pFrameDesc->_extLBAs) > IDE_maxLBA )
          { state_res = COMPLETTED; goto _L_end_; }
        }
      }
    }
    // ----------------------------------------- new FLIGHT && FIRST_FRAME

    // ...

    // init new FLIGHT on HDD --------------------------------------------
    // подготовка буфера для записи о новом полёте
    // ...

  STATES_OP( IDE_WriteBuff( flightLBA ), _E_TW2700_FS_INIT_WRITE_NEW_FLIGHT_ );

    OSD_DrawStringXY( 16, 32, "New flight header written" );
    // -------------------------------------------- init new FLIGHT on HDD

    // ...
    // ...
    // ...
    // ...
   
    FS_ready = TRUE;
    state_res = 0;
    goto _L_end_;

_E_TW2700_FS_INIT_READ_HEADER_:           state_res = E_TW2700_FS_INIT_READ_HEADER;           goto _E_timedout_;
_E_TW2700_FS_INIT_WRITE_FLIGHT_I_:        state_res = E_TW2700_FS_INIT_WRITE_FLIGHT_I;        goto _E_timedout_;
_E_TW2700_FS_INIT_WRITE_FLIGHT_0_:        state_res = E_TW2700_FS_INIT_WRITE_FLIGHT_0;        goto _E_timedout_;

_E_TW2700_FS_INIT_SEARCH_LASTFRAME_:      state_res = E_TW2700_FS_INIT_SEARCH_LASTFRAME;      goto _E_timedout_;
_E_TW2700_FS_INIT_READ_FLIGHT_I_2_:       state_res = E_TW2700_FS_INIT_READ_FLIGHT_I_2;       goto _E_timedout_;
_E_TW2700_FS_INIT_READ_FIRSTFRAME_:       state_res = E_TW2700_FS_INIT_READ_FIRSTFRAME;       goto _E_timedout_;
_E_TW2700_FS_INIT_READ_FLIGHT_I_1_:       state_res = E_TW2700_FS_INIT_READ_FLIGHT_I_1;       goto _E_timedout_;

_E_TW2700_FS_INIT_SEARCH_FRAMEHEADER_0_:  state_res = E_TW2700_FS_INIT_SEARCH_FRAMEHEADER_0;  goto _E_timedout_;

_E_TW2700_FS_INIT_WRITE_NEW_FLIGHT_:      state_res = E_TW2700_FS_INIT_WRITE_NEW_FLIGHT;      goto _E_timedout_;

_E_timedout_: IDE_ready = FALSE;
              FS_ready = FALSE;
              state_res = -1;
_L_end_:      if( tw2700Buff_busy == &FS_Init ) tw2700Buff_busy = 0;

  STATES_END
 
  return state_res;
}   

// ...
 
//////////////////////////////////////////////////////////////////////////////
static
TResult
WriteFramesToIDE( void )
{
  // ...

  if( ! KEYS_record ) goto _E_record_Stopped_;

  STATES_BEGIN
    if( frameLBA > IDE_maxLBA ) { goto _E_record_Stopped_; }

    // ...
    // проверка на готовность нового кадра 
    // ...

    u16 new_ftrn = TW2700_GetReg( FTRN_RESULT_REG );
    if( /* нет нового кадра */ ) return 1;
    // ...
    if( /* кадр не корректен */ ) return 2;

    // логика формирования адресов в ОЗУ видеоконтроллера и в IDE

  STATES_WAIT( tw2700Buff_busy == 0 );
    tw2700Buff_busy = &WriteFramesToIDE;

    // ...

    // вписывание своей информации в заголовок кадра -------------------------
    // ...
    // ------------------------- вписывание своей информации в заголовок кадра
   
    // ...

_L_write_:
    // ...

    // ожидание окончания операции записи на IDE предыдущего кадра
  STATES_WAIT_TIMED( ((TW2700_GetReg(CODEC_STATUS_REG) & FSTATUS_IDE_BUSY) == 0), RTC_SEC(5), _E_timedout_ );
    // ...
    // инициализация и начало записи нового кадра на IDE
    // ...
   
    // ...
    // ...
    // ...

_E_timedout_:       IDE_ready = FALSE;
_E_record_Stopped_: OSD_DrawCharXY( OSD_CAM_RECORD_SIGN_X, OSD_CAM_STR_Y, ' ' );
                    FS_ready = FALSE;
                    state_res = -1;
_L_end_:            if( tw2700Buff_busy == &WriteFramesToIDE ) tw2700Buff_busy = 0;
             
  STATES_END

  return state_res;
}

// ...

//////////////////////////////////////////////////////////////////////////////
void
FS_Process( void )
{
  if( FS_ready )
    WriteFramesToIDE();
  else
    if( IDE_ready && KEYS_record )
      FS_Init();
}

// ...

//////////////////////////////////////////////////////////////////////////////
int main()
{
  // ...
 
  while(1) {
    // ...
    FS_Process( void )
    // ...
  }
}

vlad

  • Hero Member
  • *****
  • Сообщений: 1391
    • Просмотр профиля
По сути реалиован "размазанный" конечный автомат.

Не, не зачет. Сюда нужно еще добавить как можно больше шаблонов :)

Wlad

  • Jr. Member
  • **
  • Сообщений: 91
    • Просмотр профиля
По сути реалиован "размазанный" конечный автомат.

Не, не зачет. Сюда нужно еще добавить как можно больше шаблонов :)
"А ваша Галя - балована..."(с)
Где на единицах-десятках килобайт (к тому же - часто - на 8-миразрядном кристалле) будет система поддержки времени исполнения крестов располагаться?

А потом народ чистосердечно полагает, что "эмбеддед" это - тоже самое, что и "мобайл". Или - просто всё то, что на ладони помещается... :)
« Последнее редактирование: Октябрь 30, 2013, 03:17:06 pm от Wlad »

vlad

  • Hero Member
  • *****
  • Сообщений: 1391
    • Просмотр профиля
"А ваша Галя - балована..."(с)
Где на единицах-десятках килобайт будет система поддержки времени исполнения крестов располагаться?

Ну конкретно шаблонам RTL не нужна.

А потом народ чистосердечно полагает, что "эмбеддед" это - тоже самое, что и "мобайл". Или - просто всё то, что на ладони помещается... :)

Тут valexey недавно писал об успехах компиляции чего-то плюсового в 512 микроконтроллерных байт.

valexey_u

  • Hero Member
  • *****
  • Сообщений: 3013
    • Просмотр профиля
По сути реалиован "размазанный" конечный автомат.

Не, не зачет. Сюда нужно еще добавить как можно больше шаблонов :)
"А ваша Галя - балована..."(с)
Где на единицах-десятках килобайт (к тому же - часто - на 8-миразрядном кристалле) будет система поддержки времени исполнения крестов располагаться?
Нигде. Кресты отличненько живут без рантайма. Я пущал плюсовую прогу с лямбда-функциями и всякими иными С++11 извращениями на микроконтроллере с 512 БАЙТАМИ ОЗУ (msp430).

А потом народ чистосердечно полагает, что "эмбеддед" это - тоже самое, что и "мобайл". Или - просто всё то, что на ладони помещается... :)
Не-е. Мобайл современный - это то же самое что ноутбук :-) Не, реально, очень похоже - и по вычислительной мощи и по заморочкам с энергопотреблениями да и сенсоры схожи.
Y = λf.(λx.f (x x)) (λx.f (x x))

Wlad

  • Jr. Member
  • **
  • Сообщений: 91
    • Просмотр профиля
Это не си, это расширизм: http://gcc.gnu.org/onlinedocs/gcc-3.4.1/gcc/Labels-as-Values.html
Лучше отсюда начинать смотреть: http://gcc.gnu.org/onlinedocs/gcc-3.4.1/gcc/C-Extensions.html#C%20Extensions
ЧТо-то - вроде тёплого туалета с мягкой бумажкой... Можно, конечно же, продолжать и на веющую снизу сквозняком дырку ходить в тридцатиградусный мороз и подтираться газеткой, но лучше-таки первый вариант. :)

Wlad

  • Jr. Member
  • **
  • Сообщений: 91
    • Просмотр профиля
Нигде. Кресты отличненько живут без рантайма. Я пущал плюсовую прогу с лямбда-функциями и всякими иными С++11 извращениями на микроконтроллере с 512 БАЙТАМИ ОЗУ (msp430).
Вы чего-то не договариваете... 8)

Не-е. Мобайл современный - это то же самое что ноутбук :-) Не, реально, очень похоже - и по вычислительной мощи и по заморочкам с энергопотреблениями да и сенсоры схожи.
А мне об этом зачем рассказываете? ???

valexey_u

  • Hero Member
  • *****
  • Сообщений: 3013
    • Просмотр профиля
Нигде. Кресты отличненько живут без рантайма. Я пущал плюсовую прогу с лямбда-функциями и всякими иными С++11 извращениями на микроконтроллере с 512 БАЙТАМИ ОЗУ (msp430).
Вы чего-то не договариваете... 8)
Упс. Ну, ок. Не будет работать new/delete (рантайм выкинули - никакого менеджера памяти, равно как и никаких malloc/free), не будет исключений и rtti. Все остальное - будет.

В плюсах на микроконтроллере без всего этого не то что можно, а нужно обходиться. Ибо куча на 512 байтах ОЗУ - это даже не смешно, и за такое надо бить канделябром.

Не-е. Мобайл современный - это то же самое что ноутбук :-) Не, реально, очень похоже - и по вычислительной мощи и по заморочкам с энергопотреблениями да и сенсоры схожи.
А мне об этом зачем рассказываете? ???
А это другим, для расширения кругозора :-) Я просто пишу под вот это все, и, так сказать, делюсь опытом. Кстати, привычки которые приобретаешь при программировании под смартфоны современные позволяют существенно лучше писать проги под ноуты - это здорово когда приложение не сжирает батарейку за полчаса.
Y = λf.(λx.f (x x)) (λx.f (x x))

Geniepro

  • Hero Member
  • *****
  • Сообщений: 1955
  • Знайте- истина в том, что повторено трижды подряд!
    • Просмотр профиля
Это не си, это расширизм: http://gcc.gnu.org/onlinedocs/gcc-3.4.1/gcc/Labels-as-Values.html

Лучше отсюда начинать смотреть: http://gcc.gnu.org/onlinedocs/gcc-3.4.1/gcc/C-Extensions.html#C%20Extensions
ЧТо-то - вроде тёплого туалета с мягкой бумажкой... Можно, конечно же, продолжать и на веющую снизу сквозняком дырку ходить в тридцатиградусный мороз и подтираться газеткой, но лучше-таки первый вариант. :)

Переносимость? Не, не слышал...  ;D
to iterate is human, to recurse, divine

Салат «рекурсия»: помидоры, огурцы, салат…

Peter Almazov

  • Sr. Member
  • ****
  • Сообщений: 482
    • Просмотр профиля
Пример (очень сокращённый за счёт выбрасывания чисто линых участков кода и не относящихся к исзменению состояния КА мест) примерно такой: ...
Я мало что понял из примера, не в силах продраться сквозь сишные прелести, но понял, что было бы интересно записать образцово-показательное решение этого примера. На идеальном языке, если угодно.

У меня есть конкретный вопрос.
Какой смысл в присваивании state_res = E_TW2700_FS_INIT_READ_HEADER, если за этим сразу идет state_res = -1?
_E_TW2700_FS_INIT_READ_HEADER_: 
    state_res = E_TW2700_FS_INIT_READ_HEADER;  goto _E_timedout_;
_E_timedout_:
    IDE_ready = FALSE;
    FS_ready = FALSE;
    state_res = -1;
Вообще, хорошо бы описать решаемую задачу простым текстом.

Geniepro

  • Hero Member
  • *****
  • Сообщений: 1955
  • Знайте- истина в том, что повторено трижды подряд!
    • Просмотр профиля
У меня есть конкретный вопрос.
Какой смысл в присваивании state_res = E_TW2700_FS_INIT_READ_HEADER, если за этим сразу идет state_res = -1?
_E_TW2700_FS_INIT_READ_HEADER_: 
    state_res = E_TW2700_FS_INIT_READ_HEADER;  goto _E_timedout_;
_E_timedout_:
    IDE_ready = FALSE;
    FS_ready = FALSE;
    state_res = -1;

Подозреваю, что между "_E_timedout_:" и "state_res = -1;" должно было быть логирование причины таймаута или что-то в этом духе...
to iterate is human, to recurse, divine

Салат «рекурсия»: помидоры, огурцы, салат…