OberonCore

Библиотека  Wiki  Форум  BlackBox  Компоненты  Проекты
Текущее время: Вторник, 16 Апрель, 2024 09:51

Часовой пояс: UTC + 3 часа




Начать новую тему Ответить на тему  [ Сообщений: 54 ]  На страницу 1, 2, 3  След.
Автор Сообщение
 Заголовок сообщения: Случаи из жизни/практики.
СообщениеДобавлено: Четверг, 12 Сентябрь, 2019 17:58 

Зарегистрирован: Воскресенье, 28 Май, 2006 22:12
Сообщения: 1693
По опыту последних нескольких месяцев пришло осознание, что всё может закончится, прямо по словам Воланда у Булгакова.

Конечно, может быть, мои здешние записи и не понадобятся никому. Но, а - вдруг?

История первая. Переношу из Телеги.

Иногда - таки - встречается проект, где ещё применяются - ну совсем крохи-микроконтроллеры.
В одном проекте у меня была ОЧЕНЬ маленькая Мега. И получилось, что я никак не мог протестировать несколько случаев их "эмуляцией".
А ошибки случались. Причём, где-то " в недрах вложенных вызовов" (там была неординарная работа с файловой системой на флэшке).
Как быть?
Всё решило введение своей "трассы распространения ошибки". На устройстве были четыре семисегментных индикатора. И несколько кнопок. В том числе и "кнопки управления курсором"/выбранным разрядом. Можно было войти нажатием комбинации кнопок в "режим редактирования". Один из индикаторов начинал мигать. "Кнопками курсора" можно было выбирать какой из индикаторов был "вводным" и выбрать там нужный символ или цифру. И - код команды и параметр для неё.

"Трасса" состояла в следующем. В статической области данных был объявлен массив кодов ошибок. Ошибки были объявлены глобально для всей системы (и для каждого потенциально ошибочного места) и имели уникальные для всей системы коды. И - да - их было МНОГО. :)
При критической ошибке, массив превращался в стек ошибок, куда заносился код ошибки каждой из функций, при возвратах из ошибочных функций. Потом, в main происходил "сброс"-запись этого массива в EEPROM микроконтроллера. И код самой "глубокой" ошибки выводился на индикатор, например "E5AF". Причём, памяти хватало на несколько таких записей (с кодом даты и времени сбоя).
Конечные потребители видели только "самый глубокий" код. А мы могли, нажав некоторую комбинацию кнопок, перейти в режим просмотра "массива сохранённых стеков", выбрать, по коду высвечиваемой даты нужный стек и начать "прокручивать"-просматривать конкретные "трассы" вызова. Очень помогало сопоставление кодов ошибок к местам, где они фиксировались.
Однажды был случай, когда описание ситуации ничего не дало, а мы как раз должны были поехать к заказчику в командировку. По приезду попросили принести тот прибор, на котором случился сбой. Минут за пять было всё выяснено на месте и доказано, что сбой произошёл не по нашей вине. :) Это помогло заказчику на своей стороне выявить уже ИХ ошибку проектирования в их части системы. Чистая магия! :)


Вернуться к началу
 Профиль  
 
 Заголовок сообщения: Re: Случаи из жизни/практики.
СообщениеДобавлено: Четверг, 12 Сентябрь, 2019 18:38 

Зарегистрирован: Воскресенье, 28 Май, 2006 22:12
Сообщения: 1693
Историй много. Сейчас будет чаще. То, что вспомнится быстрее или помнится лучше.
Жаль, что в своё время не записывал. Были довольно забавные или поучительные эпизоды.

История вторая.

На "морде" одного из разрабатывавшихся устройств были только четыре "информационных" светодиода. Плюс парочка - для индикации включения внешних запитанных от нашего блока подсистем.

Опять возникла ситуация показа сбоя.
Но здесь нужно просто показать, какая из внешних подсистем перестала исправно работать (с возможным кодом причины сбоя).
Простым включением комбинации удаётся показывать 16 кодов ошибки (2^4)
Но простые состояния "светит/погашен" применять нельзя - такой режим использовался в штатной работе для этапов и инициализации подсистем. То есть, они просто показывали активности и готовности блоков.

Значит, остаётся мигание.

Решил, что и мигание можно "растиповать". По частоте. Оптимально получилось две частоты. Если больше, испытуемые в качестве наблюдателей терялись в оценке. Да и до эпилепсии можно было отдельных индивидов довести, невзначай... :)

Подходящим оказались частоты мигания 1 и 2 герца.

Получалось, что признаком высвечивания ошибки было наличие хотя бы одного (их четырёх )мигающего светодиода. Получается, что можно отображать уже не 16, а 128 кодов ошибок при сбое. Уже жить можно!
Откуда 128? Один светодиод мигает с одной из частот - 2 состояния. Остальные 3 светодиода могут находиться в одном из 4 состояний: 1 - светит, 2 - погашен, 3 - мигает с частотой 1 герц, 4 - мигает с частотой 2 герца (2*4*4*4 = 128).

Как реализовать?

Завёл перечисление режимов и массив массивов "состояний светимости" светодиода.

enum LED_Mode { LED_OFF = 0, LED_ON, LED_1HZ, LED_2HZ, Led_Mode_COUNT };

#define LED_TICK_COUNT 4
#define LED_TICK_MASK 3

uint8_t led_modes[ Led_Mode_COUNT ][ LED_TICK_COUNT ] = {
{ 0, 0, 0, 0 },
{ 1, 1, 1, 1 },
{ 1, 1, 0, 0 },
{ 1, 0, 1, 0 }
};

Дальше, по таймеру (естественно, после делителя), каждые 0.25 сек (4 герца), для каждого из светодиодов, происходила "смена активности":
...
for( Led_t* led = leds; led < leds + LEDS_COUNT; ++led ) {
PORT_WRITE( led->_port, led_modes[ led->_mode ][ led_tick ] );
}
if( ++led_tick == Led_Mode_COUNT ) led_tick = 0; // можно и led_tick = (led_tick + 1) % Led_Mode_COUNT, но техника была уж очень слабовастенькая и с делением там было - на уровне очень длинных подпрограмм, что в обработчике прерываний использовать - неразумно. А можно и просто: led_tick = (led_tick + 1) & LED_TICK_MASK;

...

в дальнейшем, даже, в результате болезненной тяги к оптимизированию по быстродействию и сокращению времени пребывания в обработчике прерывания от "светодиодного" таймера, был даже вариант:

for( Led_t* led = leds; led < leds + LEDS_COUNT; ++led ) {
if( (uint8_t)led->_mode >> 1 ) PORT_WRITE( led->_port, led_modes[ led->_mode ][ led_tick ] );
}

а выставление в порт "светимости" для случая "светит" и "погашен" производить только в местах, где на них переключаются, но потом от этого отказался. Здесь всё - в одном месте, а там - в куче мест будет разбросано. Некрасиво. Да и - происходит смешивания логических уровней системы.

Можно и массив режимов/светимости свести к битам, но там, всё же, операций больше получается (сдвиги, маскирования...).

До следующих встреч. :)


Вернуться к началу
 Профиль  
 
 Заголовок сообщения: Re: Случаи из жизни/практики.
СообщениеДобавлено: Четверг, 12 Сентябрь, 2019 19:36 

Зарегистрирован: Воскресенье, 28 Май, 2006 22:12
Сообщения: 1693
На сегодня - наверное последняя история.
Даже - не история, а - рекомендация.
Даже на уровне железа старайтесь оперировать с, как можно, более высокоуровневыми понятиями и логикой.

Например, никогда не оперируйте с уровнями сигнала, описанными для входных или выходных интерфейсов/портов!
Всегда заменяйте их понятиями "активен" и "пассивен". Тут даже слова "включён" и выключен" как-то не особо подходят, хотя - по обстоятельствам описания предметной области, конечно.

ВСЕГДА вводите "перекодировщики" состояний в виде макросов или даже функций из вот этих "активен"/"пассивен" (и обратно) для конкретного порта/линии ввода/вывода.
Бывают ситуации, когда активность описана низким уровнем сигнала или "0", а "пассивность" - единица.
Бывает даже, что у одного и того же порта, разные линии/выводы имеют несовпадающие логики активности или присутствия сигнала (либо внешние исполнители на этих линиях требуют разной полярности выходных сигналов для включения. А уж когда величины этих входных сигналов пойдут обрабатываться в логических выражениях и битовых операциях (сгруппированными в одном байте/слове) - непоняток, ошибок и "затыков" в осмыслении ситуации - наверняка - не избежать.

Вообще, лучше не привлекать понятия из "железячного" уровня представления системы, как можно дольше (и - "ниже").
Тогда часть "самого низкоуровневого" кода будет минимизирована. Там ошибки (особенно в логике) - всего дороже. И там, чаще, труднее всего разбираться с ошибками.


Вернуться к началу
 Профиль  
 
 Заголовок сообщения: Re: Случаи из жизни/практики.
СообщениеДобавлено: Пятница, 20 Сентябрь, 2019 17:24 

Зарегистрирован: Воскресенье, 28 Май, 2006 22:12
Сообщения: 1693
Сегодня во время беседы в телеге с Ильёй вспомнились два правила, касающиеся работы с конечными автоматами.

1. НИКОГДА и НИГДЕ (кроме мест, где собраны состояния, типично - в некоем switch-е), код коллбэка НЕ МОЖЕТ обращаться к переменной состояния.

2. Если в коде вы начинаете активно работать с переменными, имеющими имена типа prev_state и/или next_state, значит нужно СРОЧНО и ОБЯЗАТЕЛЬНО перепроектировать архитектуру.


Вернуться к началу
 Профиль  
 
 Заголовок сообщения: Re: Случаи из жизни/практики.
СообщениеДобавлено: Суббота, 21 Сентябрь, 2019 09:01 

Зарегистрирован: Суббота, 07 Март, 2009 15:39
Сообщения: 3261
Откуда: Астрахань
Я тоже есть в Телеге
@WLaptew
А у вас какой там ник. А у Ильи?


Вернуться к началу
 Профиль  
 
 Заголовок сообщения: Re: Случаи из жизни/практики.
СообщениеДобавлено: Суббота, 21 Сентябрь, 2019 11:05 
Модератор
Аватара пользователя

Зарегистрирован: Понедельник, 14 Ноябрь, 2005 18:39
Сообщения: 9459
Откуда: Россия, Орёл
Моё @exupery14


Вернуться к началу
 Профиль  
 
 Заголовок сообщения: Re: Случаи из жизни/практики.
СообщениеДобавлено: Суббота, 21 Сентябрь, 2019 12:53 

Зарегистрирован: Суббота, 07 Март, 2009 15:39
Сообщения: 3261
Откуда: Астрахань
Состыковался.
У меня телега только дома на моем ноуте. Так что в свободное от работы время можно обсудить все вопросы.
Предположительно приеду в Орел 24-го вечером, как в прошлый раз.
А уезжать - вечером в субботу 26-го, чтобы в воскресенье на самолет.


Вернуться к началу
 Профиль  
 
 Заголовок сообщения: Re: Случаи из жизни/практики.
СообщениеДобавлено: Среда, 25 Сентябрь, 2019 21:29 
Аватара пользователя

Зарегистрирован: Вторник, 19 Сентябрь, 2006 21:54
Сообщения: 2449
Откуда: Россия, Томск
Wlad писал(а):
Сегодня во время беседы в телеге с Ильёй вспомнились два правила, касающиеся работы с конечными автоматами.

1. НИКОГДА и НИГДЕ (кроме мест, где собраны состояния, типично - в некоем switch-е), код коллбэка НЕ МОЖЕТ обращаться к переменной состояния.

2. Если в коде вы начинаете активно работать с переменными, имеющими имена типа prev_state и/или next_state, значит нужно СРОЧНО и ОБЯЗАТЕЛЬНО перепроектировать архитектуру.

Интересное замечание. Решил поделиться своим подходом. Я в последнее время работаю с конечными автоматами, но вместо case/switch делаю массив функций. Например, есть состояния Старт, Ждать, Делать. Объявляю тип-перечисление, чтобы всё было типобезопасно на уровне компилятора:
Код:
type TState = (stInit, stWait, stDo);

Естественно, есть переменная состояния, которая обычно является скрытым полем класса:
Код:
private FState: TState;

Для каждого состояния объявляется отдельная функция-обработчик:
Код:
function DoStart: TState;
function DoWait: TState;
function DoSomething: TState;
Эти обработчики возвращают следующее состояние, в которое должен будет перейти автомат. Иногда это константа, но чаще какой-то результат обработки текущего состояния.

Поскольку все обработчики имеют одинаковую сигнатуру, их можно запихнуть вот в такой массив:
Код:
type
  TStateHandler = function: TState;
var
  Handlers: array[TState] of TStateHandler;

Далее, шаг конечного автомата безо всяких case/switch имеет следующую реализацию:
Код:
procedure Step;
begin
  FState := Handlers[FState]();
end;

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


Вернуться к началу
 Профиль  
 
 Заголовок сообщения: Re: Случаи из жизни/практики.
СообщениеДобавлено: Четверг, 26 Сентябрь, 2019 00:57 

Зарегистрирован: Четверг, 08 Май, 2008 19:13
Сообщения: 1449
Откуда: Киев
Есть причина, почему Вы не совмещаете TState и TStateHandler? Численные операции с состоянием или для порядка?


Вернуться к началу
 Профиль  
 
 Заголовок сообщения: Re: Случаи из жизни/практики.
СообщениеДобавлено: Четверг, 26 Сентябрь, 2019 09:21 
Аватара пользователя

Зарегистрирован: Пятница, 11 Май, 2007 21:57
Сообщения: 1488
Откуда: Украина, Киев
А Dataflow архитектуру никто не прорабатывал, в ключе темы конечных автоматов?


Вернуться к началу
 Профиль  
 
 Заголовок сообщения: Re: Случаи из жизни/практики.
СообщениеДобавлено: Четверг, 26 Сентябрь, 2019 11:14 

Зарегистрирован: Суббота, 07 Март, 2009 15:39
Сообщения: 3261
Откуда: Астрахань
Александр Ильин писал(а):
То есть, новое значение переменной состояния равно результату выполнения функции-обработчика текущего состояния. При этом сами функции-обработчики не имеют прямого доступа к этой переменной, они только косвенно знают её текущее значение и могут повлиять на следующее значение только вернув какой-то результат.

Если кто хочет подробностей - можно прочитать про такой подход у Герба Саттера в его книжках про сложные задачи.
Сейчас под рукой нет - дома поищу, скажу номер задачи.


Вернуться к началу
 Профиль  
 
 Заголовок сообщения: Re: Случаи из жизни/практики.
СообщениеДобавлено: Четверг, 26 Сентябрь, 2019 12:09 

Зарегистрирован: Пятница, 13 Март, 2009 16:36
Сообщения: 987
Откуда: Казань
Ярослав Романченко писал(а):
А Dataflow архитектуру никто не прорабатывал, в ключе темы конечных автоматов?

Думаю, что Dataflow можно свести к циклу Дейкстры, который также недетерминированный.


Вернуться к началу
 Профиль  
 
 Заголовок сообщения: Re: Случаи из жизни/практики.
СообщениеДобавлено: Четверг, 26 Сентябрь, 2019 12:17 

Зарегистрирован: Четверг, 08 Май, 2008 19:13
Сообщения: 1449
Откуда: Киев
Dataflow не обязательно недетерминированный


Вернуться к началу
 Профиль  
 
 Заголовок сообщения: Re: Случаи из жизни/практики.
СообщениеДобавлено: Четверг, 26 Сентябрь, 2019 12:26 

Зарегистрирован: Пятница, 13 Март, 2009 16:36
Сообщения: 987
Откуда: Казань
Comdiv писал(а):
Dataflow не обязательно недетерминированный

Я основывался на описании из Википедии https://en.wikipedia.org/wiki/Dataflow_architecture
Цитата:
...so that the order of instruction execution is unpredictable, i.e. behavior is nondeterministic...

Цикл Дейкстры тоже может быть детерминированным. Детерминированность - это частный случай недетерминированности.


Вернуться к началу
 Профиль  
 
 Заголовок сообщения: Re: Случаи из жизни/практики.
СообщениеДобавлено: Четверг, 26 Сентябрь, 2019 12:46 
Аватара пользователя

Зарегистрирован: Пятница, 11 Май, 2007 21:57
Сообщения: 1488
Откуда: Украина, Киев
Rifat писал(а):
Я основывался на описании из Википедии https://en.wikipedia.org/wiki/Dataflow_architecture
Да, по-сути, порядок выполнения не важен. Любая инструкция готова к исполнению, если готовы её операнды. И Dataflow процессор выбирает любую готовую к исполнению инструкцию.


Вернуться к началу
 Профиль  
 
 Заголовок сообщения: Re: Случаи из жизни/практики.
СообщениеДобавлено: Четверг, 26 Сентябрь, 2019 12:59 

Зарегистрирован: Пятница, 13 Март, 2009 16:36
Сообщения: 987
Откуда: Казань
Как у dataflow processor обстоят дела с fairness? Не может ли быть такого, что у нескольких инструкций операнды готовы, но выбирается всегда одна, а одна постоянно откладывается.


Вернуться к началу
 Профиль  
 
 Заголовок сообщения: Re: Случаи из жизни/практики.
СообщениеДобавлено: Четверг, 26 Сентябрь, 2019 13:09 
Аватара пользователя

Зарегистрирован: Вторник, 19 Сентябрь, 2006 21:54
Сообщения: 2449
Откуда: Россия, Томск
Comdiv писал(а):
Есть причина, почему Вы не совмещаете TState и TStateHandler? Численные операции с состоянием или для порядка?

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

В настоящее время описанный мной подход является рефакторингом предыдущего кода. Возможно, стоит сделать и предложенный вами следующий шаг (если я вас правильно понял), но надо подумать над сопутствующим кодом. Например, сейчас у меня не прямое присваивание в FState, а через сеттер, который пишет изменение состояния в журнал. Сами состояния поименованы в array[TState] of string, а если TState = TStateHandler, то такой массив задать статически невозможно. Хотя, в наверняка в Delphi через RTTI можно получить имя функции-обработчика и сохранять в журнал это имя. Надо подумать!


Вернуться к началу
 Профиль  
 
 Заголовок сообщения: Re: Случаи из жизни/практики.
СообщениеДобавлено: Четверг, 26 Сентябрь, 2019 15:37 

Зарегистрирован: Четверг, 08 Май, 2008 19:13
Сообщения: 1449
Откуда: Киев
Александр Ильин писал(а):
если я вас правильно понял
Вы правильно меня поняли.
Александр Ильин писал(а):
Например, сейчас у меня не прямое присваивание в FState, а через сеттер, который пишет изменение состояния в журнал. Сами состояния поименованы в array[TState] of string, а если TState = TStateHandler, то такой массив задать статически невозможно. Хотя, в наверняка в Delphi через RTTI можно получить имя функции-обработчика и сохранять в журнал это имя.
Раз нужны имена, то я бы уже сделал объекты, у которых и имя, и обработчик, и мало ли что ещё захочется добавить. Для добавления нового состояния получится единое место внесения изменений вместо 3-х(в Делфи, возможно, 2 места). С RTTI связывался бы только в крайнем случае.


Вернуться к началу
 Профиль  
 
 Заголовок сообщения: Re: Случаи из жизни/практики.
СообщениеДобавлено: Четверг, 26 Сентябрь, 2019 16:54 
Аватара пользователя

Зарегистрирован: Вторник, 19 Сентябрь, 2006 21:54
Сообщения: 2449
Откуда: Россия, Томск
Comdiv писал(а):
Раз нужны имена, то я бы уже сделал объекты, у которых и имя, и обработчик, и мало ли что ещё захочется добавить. Для добавления нового состояния получится единое место внесения изменений вместо 3-х(в Делфи, возможно, 2 места). С RTTI связывался бы только в крайнем случае.
Я тоже не люблю трогать RTTI без нужды, но в вашем предложении получается, что каждое состояние - это объект в "куче", а в текущей реализации состояния - это методы одного объекта. Соответственно, для трекинга общих параметров между этими методами есть естественное место - сам класс-контейнер. Если же каждое состояние - отдельный объект, то для разделяемых данных нужен дополнительный класс. Получается довольно много шаблонного текста и есть риск за деревьями потерять лес.

Для более сложных автоматов это может быть оправдано. Например, если хочется наследовать реализацию и иметь несколько вариантов обработки некоторого состояния.


Вернуться к началу
 Профиль  
 
 Заголовок сообщения: Re: Случаи из жизни/практики.
СообщениеДобавлено: Пятница, 27 Сентябрь, 2019 09:28 
Аватара пользователя

Зарегистрирован: Пятница, 11 Май, 2007 21:57
Сообщения: 1488
Откуда: Украина, Киев
Rifat писал(а):
Как у dataflow processor обстоят дела с fairness? Не может ли быть такого, что у нескольких инструкций операнды готовы, но выбирается всегда одна, а одна постоянно откладывается.
В этой архитектуре вообще инструкции могут выбираться параллельно. Скомпилированная программа представляется в виде графа. Т.е. новые инструкции не возникают по ходу выполнения.
Вот, на украинской википедии, почему-то самое адекватное описание, а русской странички вообще нет
Архитектура потоков данных


Вернуться к началу
 Профиль  
 
Показать сообщения за:  Поле сортировки  
Начать новую тему Ответить на тему  [ Сообщений: 54 ]  На страницу 1, 2, 3  След.

Часовой пояс: UTC + 3 часа


Кто сейчас на конференции

Сейчас этот форум просматривают: нет зарегистрированных пользователей и гости: 1


Вы не можете начинать темы
Вы не можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете добавлять вложения

Найти:
Вся информация, размещаемая участниками на конференции (тексты сообщений, вложения и пр.) © 2005-2024, участники конференции «OberonCore», если специально не оговорено иное.
Администрация не несет ответственности за мнения, стиль и достоверность высказываний участников, равно как и за безопасность материалов, предоставляемых участниками во вложениях.
Без разрешения участников и ссылки на конференцию «OberonCore» любое воспроизведение и/или копирование высказываний полностью и/или по частям запрещено.
Powered by phpBB® Forum Software © phpBB Group
Русская поддержка phpBB