10.5
Karma
74.7
Rating
Юрий Фрадкин @Jef239

Высокоточная спутниковая навигация, АСУТП и embed

За продажу смартфонов без российского ПО — штраф до 200 тыс. руб

0
Думаю, что все сложнее. При ввозе импортер выбирает, к какому коду продукции относится товар. То есть одни и те же мобильники можно ввести с разными кодами. Это используется для занижения таможенных платежей. Так что при покупке есть смысл смотреть, что вы такое покупаете.

Остальное (опубликование и дезавуирование) — борьба импортеров с таможенниками.

А как бы вы назвали детские часы с мобильником, GPS и шагомером? «Игрушка радиоэлектронная», «часы электронные», «радиостанция носимая», «телефон сотовой связи», «охранный датчик персональный», «спортивный аксессуар»?

Лет 20 назад я купил таз на 25 литров. И очень удивился, увидев на его дне надпись «Для пищевых продуктов». Оказалось, официально — это «салатница». Угу, на 25 литров.

Ну в общем как выгодней — так и назовут.

Статическое распределение объектов FreeRTOS

0
ежу понятно, что он не соответствует современным понятиям о хорошем коде
Про ежа не знаю, а коту понятно, что это эталонный код от самой ST и с данными битами нужно работать именно так. Ну как минимум по семантике эталонный.

Точно также я мог бы предложить подебажиться в табличном автомате имени yacc'а.
По мне там так все довольно просто. В yytranslate я бы добавил комментариями символы ASCII, а состояния именовал бы не кодами, а сделал бы enum. Но там чуть дальше (397-441 и ниже) — приличный механизм распечатки.

Но это я писал лексические анализаторы и понимаю, как они устроены.

Что в линейном код, что в конечном автомате, если мы уже очутились в точке «все плохо», то даже имея значения регистров не всегда ясно что именно привело систему в такое состояние.
А для этого конечный автомат может хранить или печатать историю состояний.

Более того, если в функции 5 выходов то расставить бряки на всех можно быстро понять в какой именно ветке проблема
Да, но скорее всего в точке выхода уже будет не посмотреть значения из-за оптимизации. А неоптимизированный код — будет работать иначе.

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

Я о немного о другом. О том, что внешние устройства (ну и внутренние, вообще-то тоже) изначально имеют разные состояния. И конечный автомат естественным путем ложится на эти состояния. Точно так же, как на БНФ естественно ложится рекурсивный спуск.

За продажу смартфонов без российского ПО — штраф до 200 тыс. руб

Что случилось с GALILEO — версия программиста GNSS

0
А вот тут странно, что нет желающих поставить на сотовые вышки бесплатно свои приемники. Это же сеть станций по всей стране. Ионосфера, высокоточные поправки, геодезическая сеть…

Ещё странней, что никто не сделал из этих приемников контроль вертикальности вышки.

P.S. Но вышек немного — порядка миллиона в мире. По сравнению с числом смартфонов и навигаторов — капля в море.

Что случилось с GALILEO — версия программиста GNSS

+1
А можно полный список, кому нужно время спутниковое время и с какой точностью? Я-то сам только про АИС знаю.

Мне казалось, что это капля в море по сравнению с трекерами, навигаторами и мобильниками.

Что случилось с GALILEO — версия программиста GNSS

+1
1e-14 в секунду? Это нормально, уход на 0.8-0.9 нс в сутки. Довольно типичные характеристики. А вторая производная какая? Её хоть померяли или она болтается и измерению не подлежит? Ну и потом, это же наверняка до старта. То есть без учета стартового скачка частоты и релятивистских эффектов.

Что случилось с GALILEO — версия программиста GNSS

+2
Ага, то есть претензия в том, что до ката — непонятно о чем статья. А вовсе не о том, что надо вставить ссылку на другую статью, в которой нет никакой дополнительной информации.

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

А вы зря не прочли список хабов: «Глобальные системы позиционирования,
Геоинформационные сервисы, Космонавтика». Мне кажется, что он вполне дает представление о том, к чему относится статья. Мне вот «Почему я ненавижу virtualenv и pip» тоже ничего не говорит, но я вижу хаб Python и понимаю, что это не тот PIP, что был в RSX-11М.

Поэтому вопрос — почему не хватает списка хабов и ссылки?

Что случилось с GALILEO — версия программиста GNSS

+5
Отличные вопросы.

Берем приемник, геодезическими методами устанавливаем точное расположение антенны. Далее измеряем принятую псевдодальность и псведофазу. Путем измерений на нескольких частотах устраняем ионосферную задержку. Тропосферную задержку устраняем, исходя из метеоданных (температура, влажность, давление). Твердотельные приливы, неравномерность вращения Земли, дрейф материков — это все устраняется. Что остается? Сдвиг часов спутника, задержка в передающем и приемном тракте и эфемеридные ошибки.

Проще всего с задержкой. Приемный тракт калибруется имитатором, а задержки в передающем меряют относительно — одна частота относительно другой. Далее большая часть того, что радиально (от спутника к приемнику) — это сдвиг часов, остальное — эфемеридная ошибка.

Чтобы разобраться, используют не один приемник — а большую сеть по всему миру. Помните историю, как амерканцы не дали у себя поставить станцию ГЛОНАСС? Ну вот ровно для определения эфемеридных ошибок она и нужна. Самая большая сеть — это IGS Вот карта станций. Обрабатывая 2 недели данные, можно восстановить орбиту спутника с точностью до 2.5 см, а часов — до 20 пикосекунд.

С подвижных систем это не делается.

Как это связывается с временем получаемым со спутников.
Очень странный вопрос, возможно я не понял смысл. Время и координаты — это почти одно и тоже, мы меряем время в метрах, а расстояния — в секундах.

Дело в том, что измеряется разница в задержке сигналов с разных спутников. То есть в какой-то момент всем каналам идет приказ — а выдай текущее положение псевдослучайной последовательности. Один говорит 153 мкс, другой — 815 мкс и так далее. Чуть иным способом считаются миллисекунды.И из сигналов минимум 4х спутников мы получаем расхождение момента приказа со временем спутниковой системы и 3 координаты относительно центра Земли. Понятно, что для этого нам нужно знать положение спутников — оно считается по эфемеридам. Грубо говоря — это трилатерация в четырехмерном пространстве-времени.

Так что для нас точность времени — это точность измеренной высоты. Точнее — усредненного вектора на все спутники (боюсь, это непонятно будет).

Уход времени на командном центре означает неверный расчет эфемерид. И, или закладка на спутники неверных эфемерид или отказ от закладки. Вполне разумно, что выбрали второе, ибо первое могло бы дать некоторое количество ДТП.

Насколько отличаются методы контроля у разных систем (Глонасс, GPS, Gallileo, Baudu)
Не знаю. Может быть что-то знает Korogodin

Что случилось с GALILEO — версия программиста GNSS

+2
Собственно Блуберг ссылается вот на эту статью, а она — на анонимный источник.

А чем эта версия отличается от моей? Я просто написал «отказ часов» без подробностей. Ибо не специалист в атомных часах и не имею информации, что именно отказало. Но дополнил статью ссылкой на Inside GNSS и своими соображениями.

Что случилось с GALILEO — версия программиста GNSS

+1
А на это у GALILEO есть коммерческий сервис. То есть по идее — тоже шифрованный и со сменой кодов.

Китайские чипы я вообще не рассматриваю. Кто, кроме китайцев, их в военную технику поставит?

Это, конечно, конспирология, но страна, владеющая своей GNSS, вполне может передать сигнал «отключить все гражданские приемники». Или все на такой-то территории. Свободных битов для этого хватает.

Что случилось с GALILEO — версия программиста GNSS

+2
Так у ГЛОНАСС тоже был отказ. И у GPS был сбой. Могу ссылки поискать. От кривых рук в ЦУП защиты нету. У GALILEO хоть не кривые руки виноваты.

Единая точка в эталоне времени отказа возникает из-за природы времени. Наносекунда — это 30 см, пикосекунда — 0.3 мм. Хороший приемник может и шум в 0.1 мм давать. То есть пикосекундная точность — вполне нужна. Но это, простите — уже террагерцы.

Очень интересно было бы почитать специалистов — как устроены эталоны времени, возможно ли в них дублирование и почему отличия между тремя эталонами болтаются в пределах 5-10 нс.

Преимущество военной системы — она рассчитана на работу без центра управления. На уровне форматов данных рассчитана. То есть не выдает отказ, а информирует «точность снижена настолько». А в GALILEO заложились, что ЦУП всегда живой и на связи со спутниками.

Что случилось с GALILEO — версия программиста GNSS

+1
Скажем так, российский приемник двойного назначения (выпускается с 5ой и 9ой приемкой), работающий по GPS+ГЛОНАСС+GALILEO у меня лежит. Сделать автоопределение, какая система работоспособна, а какая нет — легко. Ещё легче определение неработоспособных спутников. Это вообще стандартное требовании FAA, подсистема называется RAIM.

Что у американцев в военных приемниках — не знаю, по тому, что я видел — вроде как раз они используют только GPS.

Так что при атаке на РФ глушить, скорее всего, придется все системы. На все остальные страны, кроме США — думаю что то же. Ну разве что Китай может быть обходится одной Beidou.

Интересней не глушение, а спуфинг. То есть передача ложного сигнала. Но тут тоже нет разницы — гражданская система или нет.

Что случилось с GALILEO — версия программиста GNSS

0
Ну комменты на хабре читают больше, а возмутил именно коммент. Ну и хаброэффект никто не отменял.

Что случилось с GALILEO — версия программиста GNSS

+3
Глушение идет по частоте, то есть глушатся все системы, работающие в данном диапазоне. Поскольку и GPS и GALILEO и куча других систем имеют одну и ту же L1 — 1574 Мгц, то глушатся они скопом. А без L1 — очень трудно сделать прием по L2 и L5. В выигрыше тут как ГЛОНАСС — и из-за выбора иного диапазона и из-за частотного разделения сигналов (вместо кодового на иных системах).

Но думаю лет через 10 появятся приемники с прямым захватом сигнала по L5. Там просто частота следования питов в 10 раз больше, и корреляцию надо искать не среди 1023 питов, а среди 10230 питов.

Что случилось с GALILEO — версия программиста GNSS

0
Ну вот система «ПОЛЕ-21Э», а вот свеженький (25 июня 2019 года) пресс-релиз про «Сапсан-Бекас» с подсистемой «Луч». «Луч» воздействует на каналы навигации, управления и передачи информации беспилотника, излучая помехи одновременно в 11 диапазонах

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

Если ещё точнее — системы уничтожения спутников тоже разрабатываются, просто про них известно меньше. Ну вот, например ИС — истребитель спутников стоял на вооружении до 1993 года.

Что случилось с GALILEO — версия программиста GNSS

+3
Ну для журналистов, что навигатор, что GPS-приемник — все едино. Иногда даже продавцы обзывают навигатор "навигационным приемником".

Но вы правы — позиционирование лишь часть навигации.

Что случилось с GALILEO — версия программиста GNSS

+1
Да, вы правы, я просто начал отвечать в комментарии, а потом понял, что слишком длинно и лучше постом. Проверил — и не нашел аналогов. Собственно ссылка на то, что меня возмутило, есть в первой же строке.

Добавил.

Ну что за привычка начинать книгу со второй, третьей, etc главы?
Ой, это великое искусство, я так не умею. Всех документов у него было справка об освобождении. И все — эпоха и герой очерчены и пара вводных страниц отправлены в мусорную корзину. Веллер в какой-то из книг немного рассказывал, как это делалось. Но повторить за ним — очень сложно.

Что случилось с GALILEO — версия программиста GNSS

+7
Военная система рассчитывается на работу после уничтожения наземного сегмента. В этом её плюс — она не отказывает, а плавно деградирует. Кроме того, военные системы лучше финансируются. Защита от подмены сигнала — опять-таки плюс военной системы. У GALILEO есть много плюсов, но какие из них вытекают из того, что она сугубо гражданская — не понимаю. Расскажите?

ГЛОНАСС вывели в гражданские системы американцы (!!!), рассекретив вместе со своим P-кодом ещё и наш ВТ-код. После чего появились гражданские приемники с ВТ-кодом. Да, они не бытовые, но вполне гражданские.

А какой плюс вы видите в выводе ГЛОНАСС в гражданские системы? Я только уменьшение финансирования вижу.

Что случилось с GALILEO — версия программиста GNSS

+38
Неожиданно GPS — это NAVSTAR, BEIDOU — это COMPASS, а ЦИКАДА — это ЦИКЛОН?? Увы, TRANSIT, ЦИКЛОН/ЦИКАДА/ПАРУС, ГЛОНАСС, GALILEO, BEIDOU/COMPASS, QZSS, IRNIS — это не GPS.

GPS — это абсолютно конкретная система со своим ICD (интерфейсно-контрольным документом), своим наземным сегментом и своими спутниками. Максимум к GPS можно отнести WAAS, к ГЛОНАССС - СДКМ, а к GALILEO — EGNOS. Тут хотя бы центр управления общие близкородственнные. Ну и по смыслу — функциональное дополнение.

А класс устройств называется GNSS — Global Navigation Satellite System, иногда пишут и как ГНСС, благо расшифровка та же.

Касается Navstar GPS, то с ней произошло то же, что «The Beatles». Первое слово просто отпало. Но не везде. Официально в ICD до сих пор стоит "NAVSTAR GPS Space Segment/Navigation User Segment".

P.S. Впрочем, в быту у журналистов любая навигация — это GPS. Что по ультразвуковым маякам, что по блютусу… Так что не мудрено, что вы ошиблись.

Впрочем, ГЛОНАСС — Глобальная Навигационная Система. Так что можете считать, что GALILEO — это тоже ГЛОНАСС. Кстати, в какой-то статье видел и такое.

Что случилось с GALILEO — версия программиста GNSS

+1
По ссылке написано ytest. Судя по URL — www.gsc-europa.eu/news/ytest — это «новость». Кстати, она есть на главной странице в разделе «Latest news».

Теорий можно выдумать много, от попытки секретарши главного начальника проверить, есть ли права на написание новостей, то послания суровых сибирских марсианских хакеров. :-)

Скорее всего PR-отдел отбивается от журналистов в режиме 24/7, поэтому просто нет времени удалить, но кто мешает пофантазировать о целенаправленном взломе инопланетянами? :-)

P.S. Ещё тут эта «новость» видна.

Охота на космические инспекторы

Встраиваем Lua интерпретатор в проект для микроконтроллера (stm32)

0
Ну что вы! Это просто микро-микро контроллер. :-) У нас 15 лет назад ещё хуже было. Контроллер ICPDAS I-7188 — это MS-DOS compatible, 80188, 40Мгц, 256 или 512К ОЗУ. На это чудо было сделаны функциональные блоки (задвижки и так далее), собственный недо-язык программирования и компилятор для него.

Фото этого чуда
image

Как видите по размеру разъемов — у типичной STM32 возможностей (GPIO, АЦП, ЦАП) побольше.

На таких вот «мыльницах» и их старших братьях (80 МГЦ) делалась автоматизация котельной на НорНикеле и автоматизации для цементных заводов. Типичная трехзвенная SCADA — нижний уровень (то, что должно работать 24*7*365) на контролерах, средний — на сервере, верхний — на персоналке (визуализация графиков и пуль оператора).

Теперь самое главное — почему не на Си. Собственный язык — это не только для того, чтобы технологи на нем писали. Любой заводской цех — живой, в смысле состава оборудования. Что-то сломалось — значит наживую, заводскими инженерами в течение 5-10 правится код управления, чтобы работать в обход сломавшейся части. Потом, примерно раз в месяц — ППР (планово-предупредительный ремонт) и возврат к штатному варианту.

Ещё хуже — ползучая модернизация. Это когда через 5-10 лет выясняется, что замены отказавшего датчика больше не выпускается. И заменяется на аналог, работающий немного не так. Или купили новое оборудование, и надо его встроить.

Заводские инженеры не могут менять сишный паскалевский код. Но — у них есть право менять «настройки». А собственный язык программирования — относится к «настройкам» системы.

Аналогично надо относится и к системам «умного дома». Там тоже — раз в 5-10 лет — ремонт, меняется состав семьи, ставятся новые розетки и выключатели. И тоже есть смысл не зашивать все в код, а дать возможность допрограммировать алгоритмы верхнего уровня.

Статическое распределение объектов FreeRTOS

-1
Возможно и путаю, не спорю. Можете определить эти термины четче?

Если мне надо изменить заголовок по таймеру — я просто встрою компонент «Таймер» в форму. Если мне надо обновить заголовок их другого треда — пошлю сообщение (или своё или системное). А тут цель была — показать, как работает Synchronize.

И к сожалению, куча джунов воспринимают такие примеры как правильный метод работы. То есть в лучшем случае пишется тред, при ошибках в нем говориться «дельфи — гавно, там баги» и смысловая часть треда упихивается в synchronize. В худшем — так пишется изначально, ибо так в учебнике, а «учебник всегда прав».

Ровно поэтому я за то, чтобы примеры в учебниках и статьях не учили заведомо неверному написанию кода. Кто уже умеет работать с тредами — тому подобные статьи не нужны. А кто не умеет — берет дурной пример за образец.

В качестве примера для synchronize я бы написал тяжелый математический расчет (нахождение простых чисел больше миллиона?), который раз в несколько секунд выводит очередной результат в TMemo через synchronize.

А в качестве примера на треды — высокоскоростной PID-регулятор и прием уставок для него с консоли.

Статическое распределение объектов FreeRTOS

-1
Обращаю Ваше внимание, что все 4 примера из одной области — парсинга входных данных.
Ну и что? Это ровно ответ на ваш вопрос

Но тут уже возникает вопрос: как это будет выглядеть в коде? Стейт машина? Вы точно уверенны, что это удобнее для чтения чем просто линейный алгоритм с циклом"

Да, это удобнее, чем линейный алгоритм с циклами. Да, мы можем каждый конечный автомат попытаться превратить в линейный алгоритм, просто в куче мест вставив прием с порта с ожиданием. Ваше Сделать А -> (Сделать B -> Сделать C) * 5 раз -> Сделать D — это и есть приема пакета, где А — заголовок, B и С — четный и нечетный байты тела, D — хвост.

И ровно то же самое — при приеме длинных команд по SPI. Тоже проще с конечным автоматом.

Ну вот вам жуткий линейный код из HAL STM32H7

HAL_RCC_OscConfig
__weak HAL_StatusTypeDef HAL_RCC_OscConfig(RCC_OscInitTypeDef  *RCC_OscInitStruct)
{
  uint32_t tickstart = 0;

  /* Check the parameters */
  assert_param(IS_RCC_OSCILLATORTYPE(RCC_OscInitStruct->OscillatorType));
  /*------------------------------- HSE Configuration ------------------------*/
  if(((RCC_OscInitStruct->OscillatorType) & RCC_OSCILLATORTYPE_HSE) == RCC_OSCILLATORTYPE_HSE)
  {
    /* Check the parameters */
    assert_param(IS_RCC_HSE(RCC_OscInitStruct->HSEState));
    /* When the HSE is used as system clock or clock source for PLL in these cases HSE will not disabled */
    if((__HAL_RCC_GET_SYSCLK_SOURCE() == RCC_CFGR_SWS_HSE) || ((__HAL_RCC_GET_SYSCLK_SOURCE() == RCC_CFGR_SWS_PLL1) && ((RCC->PLLCKSELR & RCC_PLLCKSELR_PLLSRC) == RCC_PLLCKSELR_PLLSRC_HSE)))
    {
      if((__HAL_RCC_GET_FLAG(RCC_FLAG_HSERDY) != RESET) && (RCC_OscInitStruct->HSEState == RCC_HSE_OFF))
      {
        return HAL_ERROR;
      }
    }
    else
    {
      /* Set the new HSE configuration ---------------------------------------*/
      __HAL_RCC_HSE_CONFIG(RCC_OscInitStruct->HSEState);

      /* Check the HSE State */
      if(RCC_OscInitStruct->HSEState != RCC_HSE_OFF)
      {
        /* Get Start Tick*/
        tickstart = HAL_GetTick();

        /* Wait till HSE is ready */
        while(__HAL_RCC_GET_FLAG(RCC_FLAG_HSERDY) == RESET)
        {
          if((int32_t) (HAL_GetTick() - tickstart ) > HSE_TIMEOUT_VALUE)
          {
            return HAL_TIMEOUT;
          }
        }
      }
      else
      {
        /* Get Start Tick*/
        tickstart = HAL_GetTick();

        /* Wait till HSE is bypassed or disabled */
        while(__HAL_RCC_GET_FLAG(RCC_FLAG_HSERDY) != RESET)
        {
          if((int32_t) (HAL_GetTick() - tickstart ) > HSE_TIMEOUT_VALUE)
          {
            return HAL_TIMEOUT;
          }
        }
      }
    }
  }
  /*----------------------------- HSI Configuration --------------------------*/
  if(((RCC_OscInitStruct->OscillatorType) & RCC_OSCILLATORTYPE_HSI) == RCC_OSCILLATORTYPE_HSI)
  {
    /* Check the parameters */
    assert_param(IS_RCC_HSI(RCC_OscInitStruct->HSIState));
    assert_param(IS_RCC_CALIBRATION_VALUE(RCC_OscInitStruct->HSICalibrationValue));

    /* When the HSI is used as system clock it will not disabled */
    if((__HAL_RCC_GET_SYSCLK_SOURCE() == RCC_CFGR_SWS_HSI) || ((__HAL_RCC_GET_SYSCLK_SOURCE() == RCC_CFGR_SWS_PLL1) && ((RCC->PLLCKSELR & RCC_PLLCKSELR_PLLSRC) == RCC_PLLCKSELR_PLLSRC_HSI)))
    {
      /* When HSI is used as system clock it will not disabled */
      if((__HAL_RCC_GET_FLAG(RCC_FLAG_HSIRDY) != RESET) && (RCC_OscInitStruct->HSIState == RCC_HSI_OFF))
      {
        return HAL_ERROR;
      }
      /* Otherwise, just the calibration is allowed */
      else
      {
      /* Enable the Internal High Speed oscillator (HSI, HSIDIV2,HSIDIV4, or HSIDIV8) */
        __HAL_RCC_HSI_CONFIG(RCC_OscInitStruct->HSIState);

        /* Get Start Tick*/
        tickstart = HAL_GetTick();

        /* Wait till HSI is ready */
        while(__HAL_RCC_GET_FLAG(RCC_FLAG_HSIRDY) == RESET)
        {
          if((int32_t) (HAL_GetTick() - tickstart ) > HSI_TIMEOUT_VALUE)
          {
            return HAL_TIMEOUT;
          }
        }
        /* Adjusts the Internal High Speed oscillator (HSI) calibration value.*/
        __HAL_RCC_HSI_CALIBRATIONVALUE_ADJUST(RCC_OscInitStruct->HSICalibrationValue);
      }
    }
    
    else
    {
      /* Check the HSI State */
      if((RCC_OscInitStruct->HSIState)!= RCC_HSI_OFF)
      {
     /* Enable the Internal High Speed oscillator (HSI, HSIDIV2,HSIDIV4, or HSIDIV8) */
        __HAL_RCC_HSI_CONFIG(RCC_OscInitStruct->HSIState);

        /* Get Start Tick*/
        tickstart = HAL_GetTick();

        /* Wait till HSI is ready */
        while(__HAL_RCC_GET_FLAG(RCC_FLAG_HSIRDY) == RESET)
        {
          if((int32_t) (HAL_GetTick() - tickstart ) > HSI_TIMEOUT_VALUE)
          {
            return HAL_TIMEOUT;
          }
        }

        /* Adjusts the Internal High Speed oscillator (HSI) calibration value.*/
        __HAL_RCC_HSI_CALIBRATIONVALUE_ADJUST(RCC_OscInitStruct->HSICalibrationValue);
      }
      else
      {
        /* Disable the Internal High Speed oscillator (HSI). */
        __HAL_RCC_HSI_DISABLE();

        /* Get Start Tick*/
        tickstart = HAL_GetTick();

        /* Wait till HSI is ready */
        while(__HAL_RCC_GET_FLAG(RCC_FLAG_HSIRDY) != RESET)
        {
          if((int32_t) (HAL_GetTick() - tickstart ) > HSI_TIMEOUT_VALUE)
          {
            return HAL_TIMEOUT;
          }
        }
      }
    }
  }
  /*----------------------------- CSI Configuration --------------------------*/
  if(((RCC_OscInitStruct->OscillatorType) & RCC_OSCILLATORTYPE_CSI) == RCC_OSCILLATORTYPE_CSI)
  {
    /* Check the parameters */
    assert_param(IS_RCC_CSI(RCC_OscInitStruct->CSIState));
    assert_param(IS_RCC_CALIBRATION_VALUE(RCC_OscInitStruct->CSICalibrationValue));

    /* When the CSI is used as system clock it will not disabled */
    if((__HAL_RCC_GET_SYSCLK_SOURCE() == RCC_CFGR_SWS_CSI) || ((__HAL_RCC_GET_SYSCLK_SOURCE() == RCC_CFGR_SWS_PLL1) && ((RCC->PLLCKSELR & RCC_PLLCKSELR_PLLSRC) == RCC_PLLCKSELR_PLLSRC_CSI)))
    {
      /* When CSI is used as system clock it will not disabled */
      if((__HAL_RCC_GET_FLAG(RCC_FLAG_CSIRDY) != RESET) && (RCC_OscInitStruct->CSIState != RCC_CSI_ON))
      {
        return HAL_ERROR;
      }
      /* Otherwise, just the calibration is allowed */
      else
      {
        /* Adjusts the Internal High Speed oscillator (CSI) calibration value.*/
        __HAL_RCC_CSI_CALIBRATIONVALUE_ADJUST(RCC_OscInitStruct->CSICalibrationValue);
      }
    }
    else
    {
      /* Check the CSI State */
      if((RCC_OscInitStruct->CSIState)!= RCC_CSI_OFF)
      {
        /* Enable the Internal High Speed oscillator (CSI). */
        __HAL_RCC_CSI_ENABLE();

        /* Get Start Tick*/
        tickstart = HAL_GetTick();

        /* Wait till CSI is ready */
        while(__HAL_RCC_GET_FLAG(RCC_FLAG_CSIRDY) == RESET)
        {
          if((int32_t) (HAL_GetTick() - tickstart ) > CSI_TIMEOUT_VALUE)
          {
            return HAL_TIMEOUT;
          }
        }

        /* Adjusts the Internal High Speed oscillator (CSI) calibration value.*/
        __HAL_RCC_CSI_CALIBRATIONVALUE_ADJUST(RCC_OscInitStruct->CSICalibrationValue);
      }
      else
      {
        /* Disable the Internal High Speed oscillator (CSI). */
        __HAL_RCC_CSI_DISABLE();

        /* Get Start Tick*/
        tickstart = HAL_GetTick();

        /* Wait till CSI is ready */
        while(__HAL_RCC_GET_FLAG(RCC_FLAG_CSIRDY) != RESET)
        {
          if((int32_t) (HAL_GetTick() - tickstart ) > CSI_TIMEOUT_VALUE)
          {
            return HAL_TIMEOUT;
          }
        }
      }
    }
  }
  /*------------------------------ LSI Configuration -------------------------*/
  if(((RCC_OscInitStruct->OscillatorType) & RCC_OSCILLATORTYPE_LSI) == RCC_OSCILLATORTYPE_LSI)
  {
    /* Check the parameters */
    assert_param(IS_RCC_LSI(RCC_OscInitStruct->LSIState));

    /* Check the LSI State */
    if((RCC_OscInitStruct->LSIState)!= RCC_LSI_OFF)
    {
      /* Enable the Internal Low Speed oscillator (LSI). */
      __HAL_RCC_LSI_ENABLE();

      /* Get Start Tick*/
      tickstart = HAL_GetTick();

      /* Wait till LSI is ready */
      while(__HAL_RCC_GET_FLAG(RCC_FLAG_LSIRDY) == RESET)
      {
        if((int32_t) (HAL_GetTick() - tickstart ) > LSI_TIMEOUT_VALUE)
        {
          return HAL_TIMEOUT;
        }
      }
    }
    else
    {
      /* Disable the Internal Low Speed oscillator (LSI). */
      __HAL_RCC_LSI_DISABLE();

      /* Get Start Tick*/
      tickstart = HAL_GetTick();

      /* Wait till LSI is ready */
      while(__HAL_RCC_GET_FLAG(RCC_FLAG_LSIRDY) != RESET)
      {
        if((int32_t) (HAL_GetTick() - tickstart ) > LSI_TIMEOUT_VALUE)
        {
          return HAL_TIMEOUT;
        }
      }
    }
  }

  /*------------------------------ HSI48 Configuration -------------------------*/ 
  if(((RCC_OscInitStruct->OscillatorType) & RCC_OSCILLATORTYPE_HSI48) == RCC_OSCILLATORTYPE_HSI48)
  {
    /* Check the parameters */
    assert_param(IS_RCC_HSI48(RCC_OscInitStruct->HSI48State));
    
    /* Check the HSI48 State */
    if((RCC_OscInitStruct->HSI48State)!= RCC_HSI48_OFF)
    {
      /* Enable the Internal Low Speed oscillator (HSI48). */
      __HAL_RCC_HSI48_ENABLE();
      
      /* Get time-out */
      tickstart = HAL_GetTick();
      
      /* Wait till HSI48 is ready */  
      while(__HAL_RCC_GET_FLAG(RCC_FLAG_HSI48RDY) == RESET)
      {
        if((HAL_GetTick() - tickstart ) > HSI48_TIMEOUT_VALUE)
        {
          return HAL_TIMEOUT;
        }      
      } 
    }
    else
    {
      /* Disable the Internal Low Speed oscillator (HSI48). */
      __HAL_RCC_HSI48_DISABLE();
      
      /* Get time-out */
      tickstart = HAL_GetTick();
      
      /* Wait till HSI48 is ready */  
      while(__HAL_RCC_GET_FLAG(RCC_FLAG_HSI48RDY) != RESET)
      {
        if((HAL_GetTick() - tickstart ) > HSI48_TIMEOUT_VALUE)
        {
          return HAL_TIMEOUT;
        }      
      } 
    }
  }
  /*------------------------------ LSE Configuration -------------------------*/
  if(((RCC_OscInitStruct->OscillatorType) & RCC_OSCILLATORTYPE_LSE) == RCC_OSCILLATORTYPE_LSE)
  {
    /* Check the parameters */
    assert_param(IS_RCC_LSE(RCC_OscInitStruct->LSEState));

    /* Enable write access to Backup domain */
    PWR->CR1 |= PWR_CR1_DBP;

    /* Wait for Backup domain Write protection disable */
    tickstart = HAL_GetTick();

    while((PWR->CR1 & PWR_CR1_DBP) == RESET)
    {
      if((int32_t) (HAL_GetTick() - tickstart ) > RCC_DBP_TIMEOUT_VALUE)
      {
        return HAL_TIMEOUT;
      }
    }

    /* Set the new LSE configuration -----------------------------------------*/
    __HAL_RCC_LSE_CONFIG(RCC_OscInitStruct->LSEState);
    /* Check the LSE State */
    if((RCC_OscInitStruct->LSEState) != RCC_LSE_OFF)
    {
      /* Get Start Tick*/
      tickstart = HAL_GetTick();

      /* Wait till LSE is ready */
      while(__HAL_RCC_GET_FLAG(RCC_FLAG_LSERDY) == RESET)
      {
        if((int32_t) (HAL_GetTick() - tickstart ) > RCC_LSE_TIMEOUT_VALUE)
        {
          return HAL_TIMEOUT;
        }
      }
    }
    else
    {
      /* Get Start Tick*/
      tickstart = HAL_GetTick();

      /* Wait till LSE is ready */
      while(__HAL_RCC_GET_FLAG(RCC_FLAG_LSERDY) != RESET)
      {
        if((int32_t) (HAL_GetTick() - tickstart ) > RCC_LSE_TIMEOUT_VALUE)
        {
          return HAL_TIMEOUT;
        }
      }
    }
  }
  /*-------------------------------- PLL Configuration -----------------------*/
  /* Check the parameters */
  assert_param(IS_RCC_PLL(RCC_OscInitStruct->PLL.PLLState));
  if ((RCC_OscInitStruct->PLL.PLLState) != RCC_PLL_NONE)
  {
    /* Check if the PLL is used as system clock or not */
    if(__HAL_RCC_GET_SYSCLK_SOURCE() != RCC_CFGR_SWS_PLL1)
    {
      if((RCC_OscInitStruct->PLL.PLLState) == RCC_PLL_ON)
      {
        /* Check the parameters */
        assert_param(IS_RCC_PLLSOURCE(RCC_OscInitStruct->PLL.PLLSource));
        assert_param(IS_RCC_PLLM_VALUE(RCC_OscInitStruct->PLL.PLLM));
        assert_param(IS_RCC_PLLN_VALUE(RCC_OscInitStruct->PLL.PLLN));
        assert_param(IS_RCC_PLLP_VALUE(RCC_OscInitStruct->PLL.PLLP));
        assert_param(IS_RCC_PLLQ_VALUE(RCC_OscInitStruct->PLL.PLLQ));
        assert_param(IS_RCC_PLLQ_VALUE(RCC_OscInitStruct->PLL.PLLR));

        /* Disable the main PLL. */
        __HAL_RCC_PLL_DISABLE();

        /* Get Start Tick*/
        tickstart = HAL_GetTick();

        /* Wait till PLL is ready */
        while(__HAL_RCC_GET_FLAG(RCC_FLAG_PLLRDY) != RESET)
        {
          if((int32_t) (HAL_GetTick() - tickstart ) > PLL_TIMEOUT_VALUE)
          {
            return HAL_TIMEOUT;
          }
        }

        /* Configure the main PLL clock source, multiplication and division factors. */
        __HAL_RCC_PLL_CONFIG(RCC_OscInitStruct->PLL.PLLSource,
                             RCC_OscInitStruct->PLL.PLLM,
                             RCC_OscInitStruct->PLL.PLLN,
                             RCC_OscInitStruct->PLL.PLLP,
                             RCC_OscInitStruct->PLL.PLLQ,
                             RCC_OscInitStruct->PLL.PLLR);

         /* Configure PLL  PLL1FRACN */
         __HAL_RCC_PLLFRACN_CONFIG(RCC_OscInitStruct->PLL.PLLFRACN);

        /* Select PLL1 input reference frequency range: VCI */ 
        __HAL_RCC_PLL_VCIRANGE(RCC_OscInitStruct->PLL.PLLRGE) ;

        /* Select PLL1 output frequency range : VCO */
        __HAL_RCC_PLL_VCORANGE(RCC_OscInitStruct->PLL.PLLVCOSEL) ;

        /* Enable PLL System Clock output. */
         __HAL_RCC_PLLCLKOUT_ENABLE(RCC_PLL1_DIVP);

        /* Enable PLL1Q Clock output. */
         __HAL_RCC_PLLCLKOUT_ENABLE(RCC_PLL1_DIVQ);
 
        /* Enable PLL1R  Clock output. */
         __HAL_RCC_PLLCLKOUT_ENABLE(RCC_PLL1_DIVR);

        /* Enable PLL1FRACN . */
         __HAL_RCC_PLLFRACN_ENABLE();

        /* Enable the main PLL. */
        __HAL_RCC_PLL_ENABLE();

        /* Get Start Tick*/
        tickstart = HAL_GetTick();

        /* Wait till PLL is ready */
        while(__HAL_RCC_GET_FLAG(RCC_FLAG_PLLRDY) == RESET)
        {
          if((int32_t) (HAL_GetTick() - tickstart ) > PLL_TIMEOUT_VALUE)
          {
            return HAL_TIMEOUT;
          }
        }
      }
      else
      {
        /* Disable the main PLL. */
        __HAL_RCC_PLL_DISABLE();

        /* Get Start Tick*/
        tickstart = HAL_GetTick();

        /* Wait till PLL is ready */
        while(__HAL_RCC_GET_FLAG(RCC_FLAG_PLLRDY) != RESET)
        {
          if((int32_t) (HAL_GetTick() - tickstart ) > PLL_TIMEOUT_VALUE)
          {
            return HAL_TIMEOUT;
          }
        }
      }
    }
    else
    {
      return HAL_ERROR;
    }
  }
  return HAL_OK;
}


Как вы будете отлаживать, если он выдаст HAL_TIMEOUT? Ну только кучу точек останова выставит. А точки останова — меняют тайминг и код работает иначе. В худшем случае — имеем гейзенбаг. А у конечного автомата, помимо простой структуры кода, всегда будет последнее состояние, до которого дошли. И узнать место ошибки — это не 2 часа возни с точками останова, а 5 минут.

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

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

Вряд ли кто нибудь в здравом уме будет писать поток, чьей основной обязанностью будет захват критической секции.
Почему??? В учебниках по дельфи есть такое. Полюбуйтесь. Synchronize — это аналог захвата критической секции.

Вот вам код из учебника
procedure TMyThread.Execute;
begin
while True do
  begin
    Synchronize(UpdateCaption);
    sleep(100);
  end;
end;



Еще разок, этот пример НЕ призван показывать преимущества многопоточности. Это просто код, где есть ее использование.
Беда в том, что джуны потом так и пишут — ровно как в учебниках и статьях. И им сложно объяснить, что в учебнике — лажа.

А то, что все они, например, пишут в лог или в консоль (захватывая по пути критическую секцию) — это вторично, это не основная задача. В большинстве случаев с такими накладными расходами можно смириться.
А вы проверяли?:-) Компилятор Pascal-fast (Паскаль-Москаль) при компиляции выдавал количество откомпилированных строк. Сделав выдачу номера каждой сотой строки (вместо каждой) егоускорили в два раза. Это я к тому, что всегда просчитывать надо. А ещё лучше — мерять.

Гораздо сложнее когда оно то работает, то не работает, то опять работает после таймаута
Согласен.

Главное не повредить пользовательские данные.
Обычно считается, что при любом access violation все данные в куче могут быть запорчены и сохранять нечего. Например, так ведет себя MS word. С другой стороны, мой опыт показывает, что при некоторой дисциплине написания, глобальная порча кучи — это дикая редкость, а access violation происходит от локальных причин. То есть можно проверить структуру кучи и сохранить, если она не нарушена. Или вообще всегда сохранять, но предупредить пользователя, что данным могут быть попорчены.

Статическое распределение объектов FreeRTOS

-1
Признаю, датчик с медленным чтением это я как пример придумал, хотя уверен такие существуют
Ваши примеры — это как раз быстрые устройства с большим обменом данных. Под медленным я понимал выполнение одной машинной команды за огромное время. То есть что-то вроде виртуальной памяти на магнитной ленте. Читаешь ячейку и упс — десяток секунд ожидания. Теоретически на процессорах с отображением регистров в память так можно сделать. Практически — не думаю, что такие устройства есть.

Но тут уже возникает вопрос: как это будет выглядеть в коде? Стейт машина? Вы точно уверенны, что это удобнее для чтения чем просто линейный алгоритм с циклом"?
Конечно! Несколько реальных примеров.

Битовый протокол RTCM 104 2.2, он же ГОСТ Р 53612-2009. Протокол битовый, но от радиоприемника получаем 6-битные байты. С какого бита начинать расшифровку — непонятно. Чтобы быть уверенным в синхронизации — нужно прочесть пяток 30 битных слов. Одно из решений — параллельно запускаем 30 конечных автоматов, со сдвигом на бит. Какой первый прочтет 5 слов подряд — тот читает с нужной точки.

Другой пример. GNSS-приемник одновременно общается по трем протоколам на одном COM-порту. Ну все три нам не надо, но два — обязательно. Ибо информация там разная. Транспортные конверты — само собой, разные. Некую уверенность в распознавании протокола дает прием 6-8 байт. Но не полную — а вдург какие-то байты пропали или исказились? Так что пока CRC не сошлось — работают два конечных автомата.

Ну и давайте совсем простой пример. Обычный транспортный протокол переменной длины. Заголовок, номер пакета, длина, тело и CRC. Вроде все просто, можно линейно. Но… представьте, что исказилось поле длины. Было 4 байта, стало 260 (0x104). Сколько пакетов вы потеряете, пока не поймете, что CRC не сошлось? А конечный автомат легко запускается как на принятые из порта байты, так и на те, что мы записали в буфер, считая телом пакета. CRC не сошлось — делаем второй проход.

Ну и последнее. Глядя на наши некоторые конечные автоматы, я представляю себе, какая «каракатица» получится в «линейном» коде. То есть жуть со многими goto, не иначе. Ну как пример — протокол с данными неопределенной длины (не путать с переменной). Это означает, что конец пакета маркируется специальным символом, а в теле пакета этот символ ескейпится. В итоге из многих состояний есть два перехода — в начало, на обнаружение нового заголовка, и в конец, на обработку конца пакета.

Вы точно этот трехслойный (на деле больше слоев) механизм, который пишут 3 разные команды хотите на машину состояний разобрать? Как по мне пускай уже будет в одном потоке, прерывается где нужно.
Я бы сделал классически, как в RSX-11. Слой прерываний, слой отложенной обработки (через тот же диспетчер) и слой библиотеки.

Тред тут полезен, но совсем для другого. Библиотека по своей природе однопоточная, так что если надо работать с картой из нескольких потоков, лучше не делать критсекции, а выделить работу с картой в отдельный поток. Тогда пять потоков, пишущий на карту, не будут ждать, а просто запишут свои задания в очередь к одному, пишущему потоку.

Цель задачи чисто синтетическая: чтобы просто присутствовали все примитивы синхронизации.
Это философский вопрос — можно ли показать преимущества многопоточности там, где более всего видны её недостатки.

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

Нет огромной глобальной машины состояния в стиле «если мы ждем ответа по сети, а пользователь еще не нажал кнопку, но при этом уже не дорисовалась картинка на экране, то делаем то тогда поговорим с датчиком».
Так её нигде нет. Ни в однотредной модели, ни в многотредной, ни в асинхронной модели с диспетчером. Есть много мелких конечных lock-free кусочков. Если времена ожидания примерно одинаковы — можно их в тесный цикл запихать. Если разные — в диспетчер. Если кто-то из приоритетный, а другой — жадный до CPU, то в разные нити. Это кирпичики, как ни компануй — они будут работать.

А кому критические секции это все еще долго, то тогда добро пожаловать в lock-free алгоритмы.
Самый важный момент, ибо для меня наоборот. Пишите все в неблокирующем стиле с нулевым ожиданием. А уж если библиотека не позволяет — ну тогда, как исключение, можно и многопоточность.

Пожалуйста, мысленно замените в моих постах слово «железобетонный» на «очень надежный».
В крайнем случае приложение перезапустят.
Что в лоб — что по лбу. Если упадет 31 декабря — будет висеть 2 недели до перезапуска. То есть опять — «губящее при падении все живое вокруг». :-)

Тут речь уже про десктопное и серверное приложение (2 варианта одного кода).
Ну так и у меня тоже — сервис. Только питание ненадежно — поэтому UPS. Сервера ненадежны — поэтому их два. Диски ненадежны — поэтому пишут оба сервера. Сети ненадежны — поэтому их две. Код ненадежен, поэтому устроен как многослойный ванька-встанька. И на последнем уровне — программный wahchdog и перезапуск винды. Зато — никаких «перезапустят». Где бы и как бы не сломалось — поднимется. 30% цены проекта ушло на это.

Тем не менее креши и зависания прямо влияют на поток говна на пользовательских форумах, а те в свою очередь на продажи приложения. Так что такие штуки отлавливаются и чинятся в первую очередь.
Ну то есть они все-таки есть? :-)

Упавшие (закрешившиеся) треды не восстанавливаются. Возникает глобальное исключение, программа пытается сохранить пользовательские данные и максимально корректно завершиться. Повисшие треды отлавливаем таймаутами. Но как я уже сказал выше у нас задача написать такой пуленепробиваемый код, чтобы пользователь никогда с этим не столкнулся.
А у меня была другая задача. Пуленепробиваемый код — это удорожание цены проекта в разы. А у меня было 2 часа на отладку в месяц. В смысле на комплексную — на живом стане. Поэтому обошелся вылизыванием до уровня 1 ошибка на 500 строк. А дальше — ванька-встанька. Exception сначала пытаемся исправить в рамках процедуры, потом — пересозданием объектов, потом — перезапуском тредом, потом — рестартом сервиса, потом — ребутом винды с передачей управления резервному серверу. И все это — с контролем попыток. Пару раз сделали, не помогло — значит эскалируем дальше.

В каждом потоке так или иначе есть вечный цикл с условием выхода по флажку или conditional variable.
АГА! Теперь чувствуете, почему xSemaphoreTake(xSemaphore, portMAX_DELAY); — это костыль? Он несовместим с выходом по флажку из-за portMAX_DELAY. Чтобы было совместимо — надо хитрее. Прочли состояние — и пошли дальше. И ожидание мелкими квантами.

Повисшие треды отлавливаем таймаутами.
Кто будет сторожить сторожей? Если не трудно, расскажите, кто отлавливает и как вы боретесь с тем, чтобы ловец таймаутов сам не завис. У меня-то это было довольно тупо устроено — все потихонечку следили за соседями по функциональности.

А у вас небось TDD? У меня-то был мой собственный bug driven development, это когда каждый баг закрывается трижды-четырежды. Сначала — проверка всех аналогичных мест в коде. Потом — корректная диагностика в лог. Потом — восстановление без исправления ошибки. А уж потом — исправление.

Ну и понятно, что 10% кода — это assert. Так что основные падения — на них. Упал — отжался и побежал дальше.

А идеал — идеал, это пластичный код, деградирующий при наличии ошибок. От царапин и ушибов вы же не умираете? Вот и код не должен умирать, а должен мягко деградировать.

Главное отличие в идеалогии — я считаю себя дураком, считаю, что в коде всегда будут ошибки. Поэтому упор — на робастность, то есть возможность работы несмотря на ошибки.

P.S. Глянул вашу статью про SD-карту — мы там уже переписывались. Кстати, упомянутый коллега — тот же.

P.P.S. Ещё одна идеологическая фишка — нужны регрессионные тесты. А это значит, что мы должны уметь работать по файлам. То есть отделить конечный автоматы дешифровки от конечных автоматов приема данных. В линейном коде с этим хуже. Сейчас 99% GNSS-кода одинаково работают в Windows, linux и FreeRTOS. Только оставшийся 1% отлаживается на железе.

Почему сериал «Чернобыль» настолько плохо описал ядерную энергию

-1
Приветствую брата стрекозоида! Скажите, а кальций (для костей), железо (для гемоглобина) и т.д. как в человеческий плод попадают? Ну у стрекозоидов трансмутация, у рептилоидов — телепортация, а у людей как? :=)

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

Как жаль, что люди не стрекозоиоды… :-)

Ну а вот и оригинал. Василий Игнатенко «получил тысячу шестьсот рентген». Так что фонил очень прилично. В плод перешло немало — «В печени – двадцать восемь рентген»

P.S. Чтоб два раза не вставать, Zolgрентген — очень старая единица, в советское время использовалась именно она. Правильнее, конечно, говорить бэр, но все (кроме радиологов и им подобных), говорили «рентген». В действовавших в то время НРБ-76 допустимая норма для персонала АЭС была 5 бэр (кроме отдельных органов), но все говорили «5 рентген», «400 рентген».

из НРБ-76
image

Вместо пруфа — личные воспоминания, что в 80ые сотрудники курчатника говорили именно «рентген», иногда уточняя, что биологических. Ну и мемуары Легасова: в интервале от 25 до 75 рентген или опасность получить 25 биологических рентген

Почему сериал «Чернобыль» настолько плохо описал ядерную энергию

+2
Дело не в облучении. Для случая облучения автор прав — облученные не становятся сильно радиоактивными. Но есть другой фактор — вдыхание радиоактивного аэрозоля. В этом случае радиоактивные частицы остаются в легких. А когда речь идет о пожарных и конкретно о Василии Игнатенко, то этот фактор вылезает на первое место.

Что касается «перехода радиации на плод», то году в 1987ом я это читал как факт. Может это и неверно с точки зрения современной науки, но в те годы считалось истинным. Кровь протекает через плод и плод может работать как фильтр, поглощая радиоактивные частицы и пораженные клетки. Тут больше вопрос в том, были ли радиоактивные частицы в том, что выдыхал Правик. Но судя по тому, что Людмила Игнатено облучилась — были.

Грязные уловки вендоров CRM: а вы бы купили автомобиль без колёс?

-4
В общем случае — спорно. Вот пример легального отката от Сбербанка. Кто тут терпит убытки? Всякие скидки — тоже можно рассматривать как откаты.

Интересная система откатов у Citilink — при продаже юрлицу бонусы идут на личный счет работника, оформлявшего сделку.

Распространены откаты у риэлторов — я имею ввиду ситуацию, когда риэлторы делятся друг с другом своей комиссией или снижают цену квартиры за счет своей комиссии. В условиях инфляции это выгодно и продавцу и покупателю. Например, агенство недвижимости Итака закладывало в договор 10% агентской комиссии. Так что сторговать 100 тысяч при покупке — всего лишь вопрос хорошего переговорщика.

Собственно как откаты, можно рассматривать и чаевые. Как сами знаете, во многих приложениях они есть (например, Яндекс-такси).

Где-то я видел исследования, что в ряде случаев воровство работника и получение им откатов выгодно для компании. Ну очевидный пример — это чаевые, но там были и ещё примеры. Увы, сейчас поискал — и не нашел.

А вот для кого откаты точно не выгодны — это для конкурентов.

А общая гипотеза такая — там, где товары/услуги хорошо сравниваются, откаты (скидки, бонусы, чаевые) — могут быть и полезны, а там, где для сравнения нужна экспертиза — скорее всего вредны.

Статическое распределение объектов FreeRTOS

-1
Ну корпоративной не я первый её обозвал. Это отсылка к корпорации микрософт и дурной реализации многозадачности в Windows 3.11. Но вы правы — действительно кооперативная.

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

В этом коде даже лишних строчек нет. В чем костыльность то?
Ну любой стереотипный код, не несущий смысловой нагрузки, а применяемый из-за технических ограничений — это в той или иной мере костыль. Просто у вас глаз замылился, вы к этим костылям привыкли.

Ну а если строго по определению — костыль, это «неполное решением, не отвечающие требованиям к дальнейшему развитию системы». Что будет, если у вас на COM-порту flow-control, и с другой стороны на пару минут запретили передачу?

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

Костыльность таймера + семафора в том, что это дурная замена для vTaskDelayUntil. То есть у вас не обосновано, почему именно такое странное решение. Между прочим, если vTask1 слишком долго будет сидеть в функции вывода, то у вас уменьшится число генераций value. Причем это ещё зависит от поведения vTask2 — он тоже может слишком надолго занять критсекцию.

Если уж меряться, то в моем текущем проекте их более 400 :) Со временем привыкаешь писать код, который железобетонно работает в таких условиях
Первая ассоциация на железобетон — обрушение козырька на Сенной. После этого на всех станциях метро с аналогичными козырьками поставили костыли (подпорки), которые поддерживают козырек. Вторая ассоциация — крошащийся железобетонный балкон в собственном кабинете. :-)

Так что железобетонный — это такой, который при падении губит кучу народу. Ибо слишком тяжел. :-)

Вы лучше численные данные скажите — какая у вас наработка на видимый пользователю отказ? У меня (если уж меряться) — больше 15 лет без видимых пользователю сбоев в 365*24. Не то, что багов не было, просто было написано хорошее и многоуровневое восстановление после отказов.

А вот что реально интересно — как устроен watchdog для 400 тредов? Баг, помеха по питанию, ТЗЧ — и какой-то тред завис. Что у вас дальше происходит? Есть ли перезапуск отказавших тредов и как останавливается отказавший тред? А как идет штатное завершение приложения? Кстати, из 400 тредов, сколько однотипных (разные инстансы одного кода)? У меня однотипных штук 12 (из 20) было.

Статическое распределение объектов FreeRTOS

-1
На мой взгляд, любая прошивка где нужно одновременно делать две (и более) задачи решается намного проще и элегантнее, если использовать FreeRTOS.

И сразу — код, в котором вместо простоты и элегантности пара костылей (костыли я выделил).

xSemaphoreTake(xSemaphore, portMAX_DELAY);
int value = random(1000);
xQueueSend(xQueue, &value, portMAX_DELAY);

xSemaphoreTake(xMutex, portMAX_DELAY);
Serial.println("Test");
xSemaphoreGive(xMutex);


Увы, это взаимоисключающие параграфы. Настоящая многозадачность нужна в редких случаях:

  1. Вам важно, чтобы при зацикливании в одной нити, все остальные продолжали бы работать.
  2. У вас долго выполняются расчеты в одной из нитей.
  3. У вас долгое ожидание в одной из нитей и его не избежать.
  4. Время простоя очень мало, процессор еле справляется
  5. Очень высокоскоростные процессы


Может я что-то забыл, но это основные случаи. Они довольно редкие. А в типовой ситуации хватает корпоративной многозадачности, причем реализованной внутри одного треда. Делается это довольно просто — пишется шедюлер и процедуры запускаются в рамках одного треда, но по расписанию.

Мьютексы и критические секции — не нужны, задачи выполняются по очереди. Очереди FreeRTOS не нужны, достаточно кольцевого буфера. Нет проблемы «как одним watchdog сделать перезапуск при зависании любого из 20 тредов». Более того, даже кольцевой буфер не нужен, если мы запускаем читателя сразу после писателя.

Упрощенный код
static int value;

void vTask1(struct deferred_executor_task *from_task) {
    value = random(1000);
    Serial.println("Test");
    deferred_executor_add_task (&from_task, 0);     // запускаем сразу
    deferred_executor_add_task (&from_task, 1000);// запускаем через секунду
}

void vTask2(struct deferred_executor_task *from_task) {
	Serial.println(value)
}

static struct deferred_executor defexec;
static struct deferred_executor_task vTask1_task;
static struct deferred_executor_task vTask2_task;

void setup() {
      Serial.begin(9600);
      deferred_executor_init (&defexec, "MAIN_DEFEXEC", 
                                          MAIN_DEFEXEC_STACK_SIZE,
                                         MAIN_DEFEXEC_PRIORITY);
      deferred_executor_task_init (&vTask1_task,  &defexec,  vTask1);
      deferred_executor_task_init (&vTask2_task,  &defexec,  vTask2);
      deferred_executor_add_task (&vTask1_task, 0);// запускаем сразу
      vTaskStartScheduler();
}


Из преимуществ — почти без переделки кода все будет работать под linux. А если дописать диспетчер — то и под Windows. Так что отладка — упрощается в разы. Ну и самое главное — нет никаких гонок.

К сожалению, у нас в реальных программах и длинные вычисления и высокоскоростные процессы, так что приходится использовать треды. Но все низкоскоростное (мигание светодиодами, обработка команд от CAN) — идет в одной нити с диспетчером.

Я не противник тредов (в одной из моих программ их было чуть более 20), но не надо их использовать в таких простых случаях. Тред — это тред, у него большой оверхед. Короткие кусочки вполне можно выполнять последовательно, в рамках одного треда.

В вашем примере, если и нужен тред — то для вывода на консоль. То есть блокировки надо бы заменить на отправку в очередь. Правда, мы в аналогичной ситуации обходимся драйвером. printf работают параллельно и независимо, но вызывают _write, которая запихивает байты в очередь к драйверу. А уже драйвер работает с портом.

P.S. Авторство идеи и обе реализации — моего коллеги.

Статическое распределение памяти в микроконтроллерах

+1
не очень понятно зачем использовать динамическое выделение для объектов, буферов, и массивов заранее известного размера

Для повторного использования памяти, разумеется. Увы, не всегда дисциплина использования памяти — стековая.

не вспомнил ни одного примера для младших и средних микроконтроллеров, где бы применение динамического выделения памяти было бы действительно оправданно.
Рассказываю. Микропроцессор средний — Cortex M7, всего лишь мегабайт памяти в 5 разных регионах. Задача — разная хитрая математика (GNSS) с матрицами по 32K каждая. И в этой математике — не стековая дисциплина использования матриц.

Хитрый пример
  1. Создали матрицу A
  2. Заполнили A
  3. Создали матрицу B
  4. Преобразовали A в B (увы, для преобразования нужны две матрицы)
  5. Создали матрицу C
  6. Заполнили С из A и B (например векторное умножение матриц)
  7. Освободили матрицу A
  8. Создали матрицу D
  9. Заполнили D из B и C
  10. Освободили матрицу C
  11. Освободили матрицу B
  12. Вывели результат из матрицы D
  13. Освободили матрицу D


Время жизни матрицы А: 1-7
Время жизни матрицы B: 3-11
Время жизни матрицы C: 5-10
Время жизни матрицы D: 8-13

То есть максимально нам нужно 3 матрицы, но если использовать стек — то получится 4. Получается, или повторно использовать матрицу A как D или пользоваться динамическим распределением. А повторное использование плохо тем, что все это может быть разнесено по нескольким процедурам, скажем шаги 1-7 — одна процедура, шаги 8-13 — вторая.

В итоге — сделал 3 массива для матриц, рассадил их по регионам памяти и собственный быстрый аллокатор. Всего сейчас используется 12 матриц, из них 6 — динамически.

Ещё есть старый прием из 70х (из языков вроде Фортрана, где не было кучи). Создать массив — и самому выделять память оттуда. Ну типа с 1ого элемента — это у нас A, с 72ого — B, а с 95ого — С. Хорошо помогает на задачках, когда у нас есть элементы разных типов, памяти мало, и мы хотим выставить пользователю ограничения помягче. Тогда можно не ограничивать число элементов каждого типа, а ввести общее ограничение.

Примерно так работала программа прочностных расчетов «Ладога», по которой методом конечных элементов в сотне институтов считались заводские цеха. Она не ограничивала число узлов и число связей между узлами, а вводила общее ограничение, которого всегда хватало. А внутри — был огромный массив, из которого бралась память для всего.

Искусственный интеллект оценил авторство песен The Beatles

0
В визбористике есть каноническое «стихи Павла Шубина, музыка Сергея Никитина, песня Юрия Визбора»

Есть город матросов

Приведение в удобный для работы вид микро-ЭВМ УКНЦ Электроника МС 0511 архитектуры PDP-11

0
dBase — это СУБД, а электронные таблицы — это супер-кастрированный excel. То есть в одни ячейки можно было ввести числа, в другие формулы и посчитать. Звался, разумеется CALC.

Материала на статью там нет, особенностей было всего две. Очень хитрое округление при выводе, чтобы 2 + 3 было 5, а не 4.99999999. Внутренняя точность — float, и это сказывается при расчетах. Вторая особенность — памяти мало, поэтому исходный код выражений не хранился. При вводе выражения оно компилировалось в шитый код и в таком виде хранилось. Для редактирования — был декомпилятор, преобразовывавший обратно из шитого кода в строку.

Поскольку вся было написано почти 30 лет назад, то больше ничего уже не помню. Написан был по заказу Гриценко, для продававшегося им учебного комплекта для УКНЦ. Вроде в несколько тысяч школ этот комплект попал.

Приведение в удобный для работы вид микро-ЭВМ УКНЦ Электроника МС 0511 архитектуры PDP-11

0
Ну я автор электронных таблиц для УКНЦ и некоторое время поддерживал Pascal-Fast (в том числе для УКНЦ) производства Антона Москаля. Но сорцов с тех времен не осталось. Максимум — могу про архитектуру приложений рассказать.

Что на самом деле случилось с исчезнувшим малайзийским Боингом (часть 1/3)

0
Профессиональный приёмник ОБЯЗАН НЕ РАБОТАТЬ в условиях «проволочка на балконе», иначе доверия ему нет.

Да зелен — ягодки нет зрелой:
Тотчас оскомину набьешь.


Чувствительность NV08-CSM: сопровождение –190 дБВт, «холодный» старт –173 дБВт. Любой приемник с такой же или лучшей чувствительностью будет принимать на разъем.

Так что вам предстоит доказать два странных тезиса: и что среди «профессиональных» приемников нет приёмников с такой же чувствительностью. И что чувствительность была ухудшена специально, ради мифического «доверия». Ну попробуйте, докажите этот бред. :-)

На самом деле делается намного проще. Разумеется, ни один разработчик не будет ухудшать характеристики. Просто обычно есть детектор подключения антенны и он по умолчанию установлен так, что без антенны выдается сигнал аварии. Но если его отключить — прием на разъем вполне возможен.

ни разу не встречал определение semi-professional.
Правильно, «semi-professional» вы выдумали сами. Сами выдумали, сами удивляетесь. Перевод на английский будет «RTK», «RTK-ready», «full RINEX», «full raw data» или «full carrier phase measurements». В любом случае, мне абсолютно не важны английские аналоги.

Мне кажется вы сами придумали это деление.
Вот вам пруф на статью Красноярцев, они точно с нами не связаны.

А термин придуман той же командой, что выдумала и сделала первый двухсистемный приемник (GPS/ГЛОНАС). Помните «Мы этого не знали. Мы дураки. Мы сделали.»? Угу, это НАВИС. Оказалось нет, вроде с Роскомоса термин пришел.

Есть приёмники Survey grade, есть GIS, есть Construction, есть Consumer,
Будьте уж так любезны, переведите эти термины на русский язык и расскажите их технический смысл. Ну если он есть, разумеется. Потому как по первым впечатлениям — обычный маркетинговый булшит.

Например в чипе SiRF Star есть сырые данные,
Очень сомневаюсь, что там есть полная фаза в циклах, там, судя по характеристикам, даже сглаживания кода доплером нет. Для навигационного решения хватает псевдодальности, Для расчета скоростей и сглаживания кода вполне хватает доплера. И если в приемнике сделали когерентный прием и контроль обратного захвата ФАПЧ, то это не для бытовой аппаратуры, а для реализации RTK. Так что поверю, когда вы дадите ссылку на RTK-решение на основе sirf.

Тут вы правы лишь в одном — полупроф от бытового приемника отличается только прошивкой.

u-Blox — типичный «продвинутый» бытовой чип, не более.
Остапа понесло, унесло и пронесло. Бытовой двухчастотный RTK? Ну или одночастотный? Если можно, то трольте в другом месте. Может ещё и сказку про «бытовой» PPP расскажите? А то Ublox его скоро выпустит.

Я работал с GNSS (с тримблами в частности, геодезия и высокоточная морская навигация) с 1994 года
Как говорил Станиславский — «Не верю». Продавали, использовали — вполне возможно. Но не работали, в смысле не писали ни код тримблов, ни коды высокоточки. Одной попытки спросить «на форуме геодезистов» (это из первоначальной версии вашего сообщения) про то, что к геодезии не относится, достаточно, чтобы понять, что вы высокоточку не писали.

Теперь отвечу на то, что не увидел в вашем первом комментарии, ибо читал неотредактированную версию.

«профессиональный» (высокие значения масок возвышения и S/N, антенна со стабильным фазовым центром, подавляющая отраженку) и «без антенны» (низкий S/N) являются антонимами.
Ох, как всё запущено. Начнем с простого. Для подавления «отраженки» используется ground. Прилепите любую антенну на крышу автомобиля — и будет практически стопроцентное подавление. Можно использовать choke ring. И все это не имеет отношения к стабильности фазового центра. А сама стабильность — имеет слабое отношение к её сертифицированности. Мы используем антенны Tallysman TW2405 — как видите, стабильность фазового центра не сертифицирована, но сам фазовый центр — весьма стабилен.

Ну а теперь главное. Что нужно, чтобы обеспечить S/N выше 50? Не догадываетесь? Чувствительность нужна. И именно высокая чувствительность дает S/N в районе 30 без антенны. То есть противоречие вы просто выдумали.

Если вы не знали, то «маски» в любом хорошем приемнике регулируются. Так что ничто не мешает вам взять хороший приемник с высокой чувствительностью, уменьшить маску по S/N, отключить детектор антенны и наблюдать прием нескольких спутников без антенны.

Собственно, чтобы понимать это — достаточно уметь считать на уровне 2ого класса. Берете уровень приема 55dB с антенной, вычитаете 24dB усиления антенны — что получится? Угу 31dB. Вот вам и прием без антенны. Даже чуть больше, ибо от антенны 2-3 dB теряются в кабеле и разъемах.

Что на самом деле случилось с исчезнувшим малайзийским Боингом (часть 1/3)

0
Ну давайте разбираться.

Приемниками GNSS в данный момент называют: микросхемы, микросборки, платы и устройства. Геодезисты работают с устройствами, то есть в их понимании «приемник» — это прибор в корпусе, в который может входить даже антенна и радиомодем. Поскольку мы занимаемся третичной обработкой (RTK, PPP), то приемники в корпусе используем только на макетах. Так что, если наши приборы попадут к геодезистам, они будут считать авторами приемника нас.

ГОСТ весьма странно определяет геодезический приемник геодезическая навигационная аппаратура потребителя ГНСС: Навигационная аппаратура потребителя ГНСС, предназначенная для выполнения геодезических работ. Но в общем это приемник ценой от сотен тысяч рублей, вот типичный пример. Как правило, это двухчастотные приемники с большим числом каналов, с низким кодовым и фазовым шумом, бинарным протоколом обмена и выдачей сырых измерений (псевдодальность, псевдофаза, доплер) по каждому каналу приема. Как правило, профессиональные приемники аттестуются как средства измерений.

С другой стороны, идут бытовые приемники. Цена — от пары долларов, выдают только решение в NMEA, качество измерений — ну обычно КВО-50 3 метра. То есть 12 часов в сутки решение попадает в круг радиусом 3 метра, остальные 12 часов — не попадает.

Между этими классами идут полупрофы. Основной признак — это выдача сырых измерений (псевдодальность, псевдофаза, доплер) по каждому спутнику. Цена — от 10 до 200 долларов. Сейчас полупрофы бывают даже на мобильниках. Посмотрите на табличку. Те приемники, которые выдаю псевдофазу (carrier phase) вместо суммарного доплера (ADR) — это полупрофы. Отличие в том, что в псевдофазе неоднозначность расстояния до спутника идет в целых циклах, а в суммарном доплере — в нецелых. То есть приемник должен выровнять фазу и избавится от обратного захвата ФАПЧ на метках времени.

Самые известные на хабре полупрофы это Ublox. Чтобы выделить их, в селекторе ставите галочку на «raw data».

Теперь конкретней о приеме на антенный разъем. Эксперимент в машине был с NV08-CSM. Прибор с двумя приемниками была в металлическом корпусе, прием шел на разъем TNC (папа) Собственно мне было надо продемонстрировать сообщение о потере всех спутников, добиться этого я смог, лишь закрыв TNC пальцем.

Разумеется, прием спутников означает ровно то, что написано — захват сигнала в кодовое слежение и выделение эфемеридной информации. Для навигационного 3D решения нужен прием 4х спутников одной системы или 5 от двух систем, а у меня тогда принимались 2 GPS и 2 ГЛОНАСС. Но для большинства описанного выше хватит захвата в слежение одного спутника с выделением эфемеридной информации. Собственно, для НАВИС — не удивляет, по расказам один из приемников НАВИС (вроде этот) пришлось на испытаниях в подвал заносить, чтобы сбить навигационное решение.

Попробовал сделать то же самое с GEOS-5MR. Прием шел то ли на плату (она вне корпуса), то ли на разъемы SМА. Расстояние до двери балкона — метр. По картинке видно, что захват только в кодовое слежение, фазового нет.

Картинки
Geos-noant1
image


Если будете повторять опыт, то самое главное — это отключить контроль питания антенны в приемнике. Иначе обнаружив, что антенна не подключена, приемник выключит обнаружение сигналов.

Что на самом деле случилось с исчезнувшим малайзийским Боингом (часть 1/3)

0
Смартфон видели? А «антенну спутниковой связи» в нем нашли? А ведь GNSS (GPS/ГЛОНАСС/GALILEO/BEIDOU) это именно спутниковая связь. Причем для многих приемников полупрофессионального класса антенна не нужна — они спокойно принимают на антенный разъем. При этом мощность передатчиков отдельных спутников — от 50 ватт.

Да это будет управление без квитирования приема, но управлять — вполне возможно.

Бытовые приемники GNSS позволяют:

  • Контроль по времени использования. Например, после указанной даты — двигатель не заводится.
  • Контроль по периоду использования. После 10 тысяч часов — не работаем до выполнения ТО авторизованным мастером.
  • Контроль по месту использования. Например, только Октябрьская железная дорога.


Если брать полупрофессиональный приемник, то добавляется ещё куча возможностей:

  • Отключение в зоне военного конфликта. Детектируется включение selective access на высоких спутниках.
  • Передача команд через MEOSAR Скажем у GALILEO там 16/96 битов, помимо ID буя. Можно купить буй, пометить его как тестовый и активировать. Ответная команда (RLM) будет принята любым приемником.


Так что передать команду «окирпичить» тепловоз в случае, если очередной раз деньги не заплатили — вполне возможно через штатные системы GNSS. Рано или поздно, но она будет принята.

На тех же технологиях в тех же габаритах с той же скоростью (50 бод) можно сделать и прием произвольной информации, в том числе обновления прошивки. Нужно только будет немного допрограммировать приемник и иметь соответствующий спутник. Тот же iridum обладает видимой антенной потому, что у него 9600 бод, а не 50. Ну и есть обратный канал, который тепловозу не нужен.

Презентация как код, или Почему я больше не пользуюсь Powerpoint-ом

-1
Термин тот же, просто если память не изменяет, то в каких-то книжках 70-80 годов расшифровывался именно так. Потому что цикл «отредактировал, сходил на печать, взял распечатку, глянул глазками, пометил правки ручкой, дождался машинного времени, внес правки, отправил на печать» — мягко говоря, всех достал. Идеал был «отредактировал — а заказчик печатает сразу набело».

С приходом персоналок отличие между тем, кто редактирует документ и тем, кто забирает его с распечатки, разумеется, стерлось. Молодежь не понимает, что ЭВМ могла занимать целый этаж, а час машинного времени стоит половину зарплаты программиста.

У меня вполне нагуглился: раз, два, три, четыре… ЧЯДНТ? Но вообще материалы доинтернетной эпохи гуглятся очень плохо.

А по вашей логике получается, что стандарта С++17 не существует? Ибо полный текст стандарта (а не final draft) не гуглится. Как и куча других платных стандартов.

Даже некоторые вещи из современных ГОСТ не гуглятся. Вот в этом ГОСТ упомянут PRDCU. Он тоже не гуглится.

P.S. insolite, товарищ, при написании с мобильника в поезде, очень плохо по клавиатуре попадает. Так что там и VIVIVIC мог быть. Но как раз изначальный смысл термина — не распечатывать много раз, а видеть на экране то, что будет напечатано. И для плоского текста — это эквивалентно экранному редактированию. В отличие от строчного.

А что товарища могила ждет не дождется — это факт.

Презентация как код, или Почему я больше не пользуюсь Powerpoint-ом

-3
WISIWYG — What I See (on screen) Is What You get (on paper). То есть я могу сделать документ и передать его вам для печати. И вы при печати получите ровно то, что у меня на экране. По крайней мере так оно понималось лет 30-40 назад, в эпоху до персоналок.

В этом смысле барабанные принтеры и полноэкранные редакторы обеспечивали лучший WISIWYG, чем нынешний ворд. С вордом надо очень постараться, чтобы на любом принтере оно печаталось одинаково. Ну хотя бы из-за разных дефолтных размеров полей.

Перевод строки я вие переводом строки не потому что это WYSIWYG, а потому что это то, как поле ввода отображает ascii-символ #10.
Гм, вы редакторы текста писали? Ну ОК, напиши редактор текста для принтера с клавиатурой электрической печатающей машинки, то есть для CONSUL 260. А первые дисплеи были ненамного умнее CONSUL.

Как вы думаете, как отрабатывается простейший backspace? В режиме замены — сдвиг курсора влево, вывод пробела, опять сдвиг влево. Если backspace умеет отрабатывать в нулевой позиции строки, то все хитрее — может потребоваться даже сдвиг экрана, если мы делаем backspace из нулевой колонки нулевой строки. Ещё сложнее — в режиме вставки.

Так что WISIWYG режим требует от терминала хотя бы 8-битного процессора, терминалы на дискретной логике поддержать его не могут.

Собственно попробуйте в консольном режиме написать WISIWYG редактор — сразу увидите, как много операций вам надо.

А нынешние «поля ввода» практически все нужное умеют сами, это не секрет.

Презентация как код, или Почему я больше не пользуюсь Powerpoint-ом

-1
Вы что, д_у_м_а_е_т_е, в эпоху м*о*н*о*ш*и*р*и*н*н*ы*х шрифтов и б*а*р*а*б*а*н*н*ы*х принтеров форматирования НЕ БЫЛО? А фразу «не повышай на меня шрифт» никогда не слышали?

Верстка и форматирование в эту эпоху были, как и программы для них.

Выключкупо формату изначально делали вручную, пробелами. Потом появились программы верстки, делающие выключку в плоских текстах, потом стало возможным эту выключку делать в WISIWYG редакторах вручную. Более того, некоторые из них (может ЛЕКСИКОН?) умели делать выключку сами. Несмотря на плоские тексты.

Аналогично с форматированием программного кода в алгоподобных языках — форматеры появились где-то в 60ые. Да, отступы делались пробелами и табуляциями, но они делались.

Строго говоря, нынешний WISIWYG тоже неполноценен, ибо по цветам на принтере получаем совсем не то, что на экране. Так что вангую, что после широкого распространения дешевых цветных принтеров и вхождения в документы цвета понятие WISIWYG расшириться и на точную цветопередачу.

А что с переходом на пропорциональные шрифты и графическую печать оно сузилось — это закономерно.
1 There