Oberon space

General Category => Общий раздел => Тема начата: Wlad от Октябрь 30, 2013, 06:14:27 am

Название: Может кому пригодится. Подобие протопотоков-автоматов
Отправлено: Wlad от Октябрь 30, 2013, 06:14:27 am
Ниже - заголовочник для использования с 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]
Название: Re: Может кому пригодится. Подобие протопотоков-автомат
Отправлено: Geniepro от Октябрь 30, 2013, 06:44:20 am
Оригинально, не знал что так можно:
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
Название: Re: Может кому пригодится. Подобие протопотоков-автомат
Отправлено: Geniepro от Октябрь 30, 2013, 06:54:59 am
Было бы неплохо увидеть авторский пример использования такого конечного автомата...
Название: Re: Может кому пригодится. Подобие протопотоков-автомат
Отправлено: valexey_u от Октябрь 30, 2013, 08:50:34 am
Это не си, это расширизм: http://gcc.gnu.org/onlinedocs/gcc-3.4.1/gcc/Labels-as-Values.html
Название: Re: Может кому пригодится. Подобие протопотоков-автомат
Отправлено: Wlad от Октябрь 30, 2013, 10:44:40 am
Оригинально, не знал что так можно:
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 )
    // ...
  }
}
Название: Re: Может кому пригодится. Подобие протопотоков-автомат
Отправлено: vlad от Октябрь 30, 2013, 03:04:57 pm
По сути реалиован "размазанный" конечный автомат.

Не, не зачет. Сюда нужно еще добавить как можно больше шаблонов :)
Название: Re: Может кому пригодится. Подобие протопотоков-автомат
Отправлено: Wlad от Октябрь 30, 2013, 03:13:20 pm
По сути реалиован "размазанный" конечный автомат.

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

А потом народ чистосердечно полагает, что "эмбеддед" это - тоже самое, что и "мобайл". Или - просто всё то, что на ладони помещается... :)
Название: Re: Может кому пригодится. Подобие протопотоков-автомат
Отправлено: vlad от Октябрь 30, 2013, 03:17:45 pm
"А ваша Галя - балована..."(с)
Где на единицах-десятках килобайт будет система поддержки времени исполнения крестов располагаться?

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

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

Тут valexey недавно писал об успехах компиляции чего-то плюсового в 512 микроконтроллерных байт.
Название: Re: Может кому пригодится. Подобие протопотоков-автомат
Отправлено: valexey_u от Октябрь 30, 2013, 03:19:39 pm
По сути реалиован "размазанный" конечный автомат.

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

А потом народ чистосердечно полагает, что "эмбеддед" это - тоже самое, что и "мобайл". Или - просто всё то, что на ладони помещается... :)
Не-е. Мобайл современный - это то же самое что ноутбук :-) Не, реально, очень похоже - и по вычислительной мощи и по заморочкам с энергопотреблениями да и сенсоры схожи.
Название: Re: Может кому пригодится. Подобие протопотоков-автомат
Отправлено: Wlad от Октябрь 30, 2013, 03:20:55 pm
Это не си, это расширизм: 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
ЧТо-то - вроде тёплого туалета с мягкой бумажкой... Можно, конечно же, продолжать и на веющую снизу сквозняком дырку ходить в тридцатиградусный мороз и подтираться газеткой, но лучше-таки первый вариант. :)
Название: Re: Может кому пригодится. Подобие протопотоков-автомат
Отправлено: Wlad от Октябрь 30, 2013, 03:23:14 pm
Нигде. Кресты отличненько живут без рантайма. Я пущал плюсовую прогу с лямбда-функциями и всякими иными С++11 извращениями на микроконтроллере с 512 БАЙТАМИ ОЗУ (msp430).
Вы чего-то не договариваете... 8)

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

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

Не-е. Мобайл современный - это то же самое что ноутбук :-) Не, реально, очень похоже - и по вычислительной мощи и по заморочкам с энергопотреблениями да и сенсоры схожи.
А мне об этом зачем рассказываете? ???
А это другим, для расширения кругозора :-) Я просто пишу под вот это все, и, так сказать, делюсь опытом. Кстати, привычки которые приобретаешь при программировании под смартфоны современные позволяют существенно лучше писать проги под ноуты - это здорово когда приложение не сжирает батарейку за полчаса.
Название: Re: Может кому пригодится. Подобие протопотоков-автомат
Отправлено: Geniepro от Октябрь 30, 2013, 04:03:33 pm
Это не си, это расширизм: 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
Название: Re: Может кому пригодится. Подобие протопотоков-автомат
Отправлено: Peter Almazov от Октябрь 30, 2013, 04:11:28 pm
Пример (очень сокращённый за счёт выбрасывания чисто линых участков кода и не относящихся к исзменению состояния КА мест) примерно такой: ...
Я мало что понял из примера, не в силах продраться сквозь сишные прелести, но понял, что было бы интересно записать образцово-показательное решение этого примера. На идеальном языке, если угодно.

У меня есть конкретный вопрос.
Какой смысл в присваивании 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;
Вообще, хорошо бы описать решаемую задачу простым текстом.
Название: Re: Может кому пригодится. Подобие протопотоков-автомат
Отправлено: Geniepro от Октябрь 30, 2013, 04:22:56 pm
У меня есть конкретный вопрос.
Какой смысл в присваивании 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;" должно было быть логирование причины таймаута или что-то в этом духе...
Название: Re: Может кому пригодится. Подобие протопотоков-автомат
Отправлено: Geniepro от Октябрь 30, 2013, 04:27:27 pm
Вообще, хорошо бы описать решаемую задачу простым текстом.

Ага, вот где нужен ДРАКОН! )))
http://forum.oberoncore.ru/viewtopic.php?f=78&t=4284&sid=8c14d8769c57628b9f266f355391e26d
Название: Re: Может кому пригодится. Подобие протопотоков-автомат
Отправлено: vlad от Октябрь 30, 2013, 04:33:35 pm
Ага, вот где нужен ДРАКОН! )))

Ага, Дракон здесь бы хорошо подошел.
Название: Re: Может кому пригодится. Подобие протопотоков-автомат
Отправлено: valexey_u от Октябрь 30, 2013, 04:39:49 pm
Ага, вот где нужен ДРАКОН! )))

Ага, Дракон здесь бы хорошо подошел.
Зачем? Это же конечные автоматы! Там есть вполне устоявшаяся методика и нотация графического описания конечных автоматов: http://en.wikipedia.org/wiki/State_diagram

Ну и еще картинок (в статье): http://www.rsdn.ru/article/alg/nka.xml

Ну и вообще, см. тему: http://oberspace.dyndns.org/index.php?topic=60.0

Там как раз Илья Ермаков советовал http://jflap.org/ - и это ровно то что нужно! Никакой дракон в подметки тут не годится!
Название: Re: Может кому пригодится. Подобие протопотоков-автомат
Отправлено: Madzi от Октябрь 30, 2013, 05:44:09 pm
А ещё помню, конечные автоматы (конечные) хорошо описывались таблицами переходов...

...так ДРАКОН лишился ещё одного возможного направления развития :)
Название: Re: Может кому пригодится. Подобие протопотоков-автомат
Отправлено: Wlad от Октябрь 30, 2013, 08:15:17 pm
Упс. Ну, ок. Не будет работать new/delete (рантайм выкинули - никакого менеджера памяти, равно как и никаких malloc/free), не будет исключений и rtti. Все остальное - будет.
Как на встроенные системы "пересел", не припомню, что бы хоть раз malloc/free использовал... :)
Даже если попадается что-то переделывать из чьих-то готовых исходников изгоняю эту дьявольщину, переделывая структуры и алгоритмы! Чтение про ядро Миникс3 у Таненбаума и сами ея исходники - очень пользительны в плане корректировки мировозрения и оценок, что к чему в реальности и при жёстких ограничениях.

"Всё остальное" - это просто "несколько иной" компилятор на уровне конструкций и типов.
Хотя, "объектоподобность" я могу и "вручную" на Си(без крестов) организовывать и получается по затратам на память всё равно меньше. Вместо поддержки таблиц виртуальных функций больше подходит подход из первого Оберона с указателями на функции. Но чаще Обходишься чем-то вроде Queue_Add( TQueue* this, void* pItem ) и void* Queue_Get( TQueue* this ) :)
Сами же, например, буферы, помещаемые и удаляемые из очереди - элементы массива буферов

uint8_t buffers[N][BUFFER_SIZE];
uint8_t* freeBuffers[N];
uint8_t* buffersToTX[N];
uint8_t* RXedBuffer, *TXedBuffer;

и т.д.

А это другим, для расширения кругозора :-) Я просто пишу под вот это все, и, так сказать, делюсь опытом. Кстати, привычки которые приобретаешь при программировании под смартфоны современные позволяют существенно лучше писать проги под ноуты - это здорово когда приложение не сжирает батарейку за полчаса.
Ну, у меня в изделиях проблем с энергией нет. Хотя потребление стараемся минимизировать. Больше стараемся скорострельность выжать при минимизации самой тактовой. Плюс температурный диапазон и вибро- и удароустойчивость. Ну и что бы "свистело" потише по цепям питания... :)
Название: Re: Может кому пригодится. Подобие протопотоков-автомат
Отправлено: Wlad от Октябрь 30, 2013, 08:18:12 pm
У меня есть конкретный вопрос.
Какой смысл в присваивании 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;
Потому, что не все комментарии вписал.
Вы наверное заметили, что куча кода выкинута?
Задача была показать применение конкретного подхода и конструкций.

Вообще, хорошо бы описать решаемую задачу простым текстом.
Оно вам надо? :)
Название: Re: Может кому пригодится. Подобие протопотоков-автомат
Отправлено: Wlad от Октябрь 30, 2013, 08:23:03 pm
Подозреваю, что между "_E_timedout_:" и "state_res = -1;" должно было быть логирование причины таймаута или что-то в этом духе...
Там много чего ещё есть.
Просто предоставлена иллюстрация использования макросов учёта "состояния автомата".
Оставлен только "скелет" типового использования.
Не буду же я весь тысячестрочный модуль низкоуровневой работы с IDE флеш-диском и тасования в памяти видеоконтроллера информации выкладывать! Во-первых, оно не для того писАлось, во-вторых, завуалировало бы применение "макросов состояния" лишней инфой.