Oberon space
General Category => Общий раздел => Тема начата: 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]
-
Оригинально, не знал что так можно:
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
-
Было бы неплохо увидеть авторский пример использования такого конечного автомата...
-
Это не си, это расширизм: http://gcc.gnu.org/onlinedocs/gcc-3.4.1/gcc/Labels-as-Values.html
-
Оригинально, не знал что так можно:
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 )
// ...
}
}
-
По сути реалиован "размазанный" конечный автомат.
Не, не зачет. Сюда нужно еще добавить как можно больше шаблонов :)
-
По сути реалиован "размазанный" конечный автомат.
Не, не зачет. Сюда нужно еще добавить как можно больше шаблонов :)
"А ваша Галя - балована..."(с)
Где на единицах-десятках килобайт (к тому же - часто - на 8-миразрядном кристалле) будет система поддержки времени исполнения крестов располагаться?
А потом народ чистосердечно полагает, что "эмбеддед" это - тоже самое, что и "мобайл". Или - просто всё то, что на ладони помещается... :)
-
"А ваша Галя - балована..."(с)
Где на единицах-десятках килобайт будет система поддержки времени исполнения крестов располагаться?
Ну конкретно шаблонам RTL не нужна.
А потом народ чистосердечно полагает, что "эмбеддед" это - тоже самое, что и "мобайл". Или - просто всё то, что на ладони помещается... :)
Тут valexey недавно писал об успехах компиляции чего-то плюсового в 512 микроконтроллерных байт.
-
По сути реалиован "размазанный" конечный автомат.
Не, не зачет. Сюда нужно еще добавить как можно больше шаблонов :)
"А ваша Галя - балована..."(с)
Где на единицах-десятках килобайт (к тому же - часто - на 8-миразрядном кристалле) будет система поддержки времени исполнения крестов располагаться?
Нигде. Кресты отличненько живут без рантайма. Я пущал плюсовую прогу с лямбда-функциями и всякими иными С++11 извращениями на микроконтроллере с 512 БАЙТАМИ ОЗУ (msp430).
А потом народ чистосердечно полагает, что "эмбеддед" это - тоже самое, что и "мобайл". Или - просто всё то, что на ладони помещается... :)
Не-е. Мобайл современный - это то же самое что ноутбук :-) Не, реально, очень похоже - и по вычислительной мощи и по заморочкам с энергопотреблениями да и сенсоры схожи.
-
Это не си, это расширизм: 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
ЧТо-то - вроде тёплого туалета с мягкой бумажкой... Можно, конечно же, продолжать и на веющую снизу сквозняком дырку ходить в тридцатиградусный мороз и подтираться газеткой, но лучше-таки первый вариант. :)
-
Нигде. Кресты отличненько живут без рантайма. Я пущал плюсовую прогу с лямбда-функциями и всякими иными С++11 извращениями на микроконтроллере с 512 БАЙТАМИ ОЗУ (msp430).
Вы чего-то не договариваете... 8)
Не-е. Мобайл современный - это то же самое что ноутбук :-) Не, реально, очень похоже - и по вычислительной мощи и по заморочкам с энергопотреблениями да и сенсоры схожи.
А мне об этом зачем рассказываете? ???
-
Нигде. Кресты отличненько живут без рантайма. Я пущал плюсовую прогу с лямбда-функциями и всякими иными С++11 извращениями на микроконтроллере с 512 БАЙТАМИ ОЗУ (msp430).
Вы чего-то не договариваете... 8)
Упс. Ну, ок. Не будет работать new/delete (рантайм выкинули - никакого менеджера памяти, равно как и никаких malloc/free), не будет исключений и rtti. Все остальное - будет.
В плюсах на микроконтроллере без всего этого не то что можно, а нужно обходиться. Ибо куча на 512 байтах ОЗУ - это даже не смешно, и за такое надо бить канделябром.
Не-е. Мобайл современный - это то же самое что ноутбук :-) Не, реально, очень похоже - и по вычислительной мощи и по заморочкам с энергопотреблениями да и сенсоры схожи.
А мне об этом зачем рассказываете? ???
А это другим, для расширения кругозора :-) Я просто пишу под вот это все, и, так сказать, делюсь опытом. Кстати, привычки которые приобретаешь при программировании под смартфоны современные позволяют существенно лучше писать проги под ноуты - это здорово когда приложение не сжирает батарейку за полчаса.
-
Это не си, это расширизм: 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
-
Пример (очень сокращённый за счёт выбрасывания чисто линых участков кода и не относящихся к исзменению состояния КА мест) примерно такой: ...
Я мало что понял из примера, не в силах продраться сквозь сишные прелести, но понял, что было бы интересно записать образцово-показательное решение этого примера. На идеальном языке, если угодно.
У меня есть конкретный вопрос.
Какой смысл в присваивании 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;
Вообще, хорошо бы описать решаемую задачу простым текстом.
-
У меня есть конкретный вопрос.
Какой смысл в присваивании 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;" должно было быть логирование причины таймаута или что-то в этом духе...
-
Вообще, хорошо бы описать решаемую задачу простым текстом.
Ага, вот где нужен ДРАКОН! )))
http://forum.oberoncore.ru/viewtopic.php?f=78&t=4284&sid=8c14d8769c57628b9f266f355391e26d
-
Ага, вот где нужен ДРАКОН! )))
Ага, Дракон здесь бы хорошо подошел.
-
Ага, вот где нужен ДРАКОН! )))
Ага, Дракон здесь бы хорошо подошел.
Зачем? Это же конечные автоматы! Там есть вполне устоявшаяся методика и нотация графического описания конечных автоматов: 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/ - и это ровно то что нужно! Никакой дракон в подметки тут не годится!
-
А ещё помню, конечные автоматы (конечные) хорошо описывались таблицами переходов...
...так ДРАКОН лишился ещё одного возможного направления развития :)
-
Упс. Ну, ок. Не будет работать 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;
и т.д.
А это другим, для расширения кругозора :-) Я просто пишу под вот это все, и, так сказать, делюсь опытом. Кстати, привычки которые приобретаешь при программировании под смартфоны современные позволяют существенно лучше писать проги под ноуты - это здорово когда приложение не сжирает батарейку за полчаса.
Ну, у меня в изделиях проблем с энергией нет. Хотя потребление стараемся минимизировать. Больше стараемся скорострельность выжать при минимизации самой тактовой. Плюс температурный диапазон и вибро- и удароустойчивость. Ну и что бы "свистело" потише по цепям питания... :)
-
У меня есть конкретный вопрос.
Какой смысл в присваивании 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;" должно было быть логирование причины таймаута или что-то в этом духе...
Там много чего ещё есть.
Просто предоставлена иллюстрация использования макросов учёта "состояния автомата".
Оставлен только "скелет" типового использования.
Не буду же я весь тысячестрочный модуль низкоуровневой работы с IDE флеш-диском и тасования в памяти видеоконтроллера информации выкладывать! Во-первых, оно не для того писАлось, во-вторых, завуалировало бы применение "макросов состояния" лишней инфой.