Pull to refresh

Comments 39

Какое-либо промежуточное ПО планируется?
Не совсем ясен вопрос.

В целом — внутренние разработки на микроконтроллерах, мы теперь делаем на базе своей ОС. Причём не везде нужно ядро, но драйверы нужны везде. Идея драйверов позаимствована у Константина Чижова и его библиотеки mcucpp. Результирующий код получается сверхоптимальным без каких-либо усилий со стороны прикладного программиста.
Я понимаю, что это только первая статья из цикла, но именно в ней хотелось бы видеть основные отличия вашей системы от существующих популярных RTOS. Я так понимаю, модель распространения у неё отлична от свободной, иначе бы вы это указали.
И ещё. Объектно ориентированный подход чаще всего используется с динамической моделью выделения памяти. Я понимаю, что на современных контроллерах использование динамической памяти не есть что-то из ряда вон выходящее, но одновременно с этим вы ограничиваете вашу систему статическим набором задач. Здесь я вижу некоторое противоречие. Если вы не используете динамическую память, значит ваша программа не очень сложная и процедурный подход оправдывает себя. Или же наоборот, если вы делаете сложную динамическую систему, зачем её ограничивать фиксированным набором задач. Или ООП здесь для только тех кто пересел с высокоуровневых языков и уже не хочет отказываться от ООП-мышления в пользу процедурного?
И ещё. Объектно ориентированный подход чаще всего используется с динамической моделью выделения памяти.

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

А когда начнётся описание драйверов — там ещё будут шаблоны, которые не только не усложняют результирующий ассемблерный код, но и здорово его оптимизируют…
Бесила!?
Вот тут поподробней.
Какие RTOS вы изучали и что из них скопировали.
Эээээ. Вообще-то это не совсем законно, изучать для того, чтобы скопировать. Давайте скажем мягче, просто изучили, чтобы получить опыт…

Рассматривали FreeRTOS, CMSIS RTOS, uC OSII, Альтеровскую RTOS. Сейчас точно не вспомню, что ещё рассматривалось более поверхностно.

Из более высоких ОС была рассмотрена QNX, но часть её идей была выбрана, как цель для дальнейших устремлений.

Исходно было решено, что мы делаем ОС для низших контроллеров. Чтобы результат был реализуем, а не где-то на горизонте. Так что никакой изолированной памяти, ничего иного. Были выбраны Cortex M, их операционки и рассматривались. Потом — появились коммерческие задачи, список процессоров был расширен.

Чуть не забыл. Проекту не один год. И даже не два. Так что в те времена список имеющихся ОС был не очень богат.

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

Если говорить о объектах и шаблонах и ОСРВ сразу вспоминается eCos. Немногие ОСРВ были написаны в то время на C++.

У eCOS файловая система и TCP стек были на чистейшем C-и.
Там только ядро да стандартная библиотека были на C++.
Хотя пример удачный.
Вот в таких гибридов превращаются все потуги написать RTOS на C++.
И здесь так будет.
Если бы C++ давал хоть какое-нибудь преимущество в скорости написания или уменьшении отладки или в надежности, то все для embedded было бы давно переписано на C++.
Вон на ПК Python почти мгновенно поднялся, и все библиотеки на него были переписаны. А тут десятилетиями тормоза.
Нет, что ни говорите а в embedded у С++ с текущими либами нет перспектив.
Эти споры можно вести вечно. И обе стороны будут давать массу аргументов.

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

Дальше, за счёт строгой типизации, ограничений области видимости и прочих подобных вещей, мы ставим себе на службу механизм IntelliSense, который упрощает разработку прикладному программисту. Его же бросают с проекта на проект, везде надо вспоминать, что к чему. И IntelliSense — быстрее введёт в курс дела, чем очередное копание в документации. Опять же… В тексте у меня есть хороший пример, как это помогает, но график выкладывания сюда утверждал не я. Поэтому пока просто предлагаю верить на слово, что есть. Опубликовано будет позже.

А «Этого же можно добиться и другими путями» — ну да, можно. Но там надо добиваться, а тут — оно само получается.

Итого: Заставлять всех переходить на ООП — глупо. Верить, что скоро все перейдут на ООП — наивно. Но по крайней мере, попробовать — достоинства от этого видятся неплохие. Была возможность. Попробовали. Понравилось. Не всё гладко, но не жалею, что попробовали. Продолжаем развивать.

Как потом оказалось (начинали мы давно), попробовали не только мы. И во всех случаях, тоже был успех. А либы — это дело наживное, были бы Заказчики (то есть, оплата работ).
Есть интересный разговор про C++ на embedded на cppcon 2016, а если точнее то доклад о том как обсуждать С++ для embedded с C разработчиками. Я не то чтобы имею отношение к embedded разработки, где-то чуть повыше, так что конкретно по этому вопросу у меня прям своего отношения, есть просто какое-то непонимание на уровне того какой оверхед ожидают C разработчики от C++. Но в данном видео довольно мало C++ и скорее больше именно какой-то психологии что мне показалось довольно интересным.

Ссылка: www.youtube.com/watch?v=D7Sd8A6_fYU
Моя точка зрения, что все решают либы. Сам язык не важен.
Языки изобретают такие же интроверты, мало понимающие в массовой психологии и не стоит от них ожидать неких ментальных практик лучшего использования мозга.
Они там в своих языках решают свои локальные проблемы связанные с особенностями их инструментов и прикладной областью, которые мы даже не знаем или проблемы организации коллективного программирования.
Единственное что действительно полезно — это либы которые они по ходу создают или портируют. Одновременно с этим они их и документируют.

В малых встраиваемых системах коллективное программирование не играет важной роли. К примеру приложения для Arduino практически всегда программируют в одиночку. Там сама среда не располагает к коллективной работе.
А real-time embedded еще и сильно связан с ассемблером. При отладке постоянно надо смотреть ассемблер сгенерированный компилятором. Чем прямее связь исходников с ассемблером тем легче отлаживать.
Несмотря на то что С-и и C++ похожи, интеграция большинства либ в приложение на C++ требует коррекции либ.
Но дело обстоит так, что трудоемкость коррекция сколько нибудь стоящих либ своей ценой превышает ценность всех тех мелких удобств С++.
Вот и все, ничего личного, только энергозатраты.
Это просто замечательно, что в наше время имеется возможность попробовать все варианты. Какой вариант окажется более удачным — покажет время. Вот когда направление развития задавал Госплан — там цена ошибки в выборе была высока.

Лет 5 назад, делая систему JTAG сканирования под C#, я нашёл парсер BSDL на чистых Сях. Обернуть его в объектную библиотеку заняло менее рабочего дня. Не проникая внутрь. Просто сначала собрал LIB файл, затем — уже вокруг него сделал плюсовую обёртку на C++ CLR. А это дело уже автоматически «засосалось» в любой .NET компилятор. Так что не так это страшно.

Часть библиотек сейчас разрабатывается сразу под Плюсы. Часть — проще написать заново, чем взять чужие.

В общем, оба варианта рассуждений имеют право на существование, а что окажется жизнеспособней — покажет время. Благо сейчас есть возможность рискнуть.
Ну и да. Если у контроллера 190К ОЗУ (это не считая 2М флэша) — уже можно подумать на тему работы с динамической памятью, если быстродействие не сильно поджимает. А если ещё и припаяно 8М SDRAM — и подавно. Есть такая макетка от ST, а у меня на столе есть и реальная плата с ОЗУшкой такой. То есть, динамическая память — это, конечно, зло (так как время работы операций new и delete неизвестно, а также возможна фрагментация адресного пространства), но кому она нравится — почему бы и не воспользоваться ею? На свой страх и риск. Но само собой, это всё вторично. Первична — именно структурированность кода.
Существует placement new и создание constexpr экземпляров.
Второе дает просто прекрасные результаты, код выглядит как будто написан для пк, но сочетание static constexpr для экземпляра внутри какого то скоупа позволяет компилятору произвести аллокацию на этапе компиляции и поместить экземпляр во флеш.
Выглядит это примерно так, и код ниже может не использоватьт оперативную память вообще (я инитил итуглил светодиодом в бесконечном вайле, на gcc-arm-none-eabi, эта логика вырождалось в 50 байт кода во флеше и 0 байт оперативной памяти)

constexpr GPIO led1(portA,pin4); //пин и порт светодиода известны компайл тайм 
led1.init(params); //параметры инициализации тоже
led.up(); //тут идет переход по указателю на регистр BSSR порта и сдвинутый на пин, но т.к. мы знаем параметры compile time, то компилятор может подставить нужный регистр
.

Помимо этого, есть вероятность что в C++ добавят compile time allocator.
Что совсем перевернет методы разработки под мк.
Некоторые реальные Заказчики хотят пользоваться достаточно старомодными компиляторами. Поэтому конкретно Ваш пример сейчас решается через static функции, описанные в библиотеке mcucpp (библиотеку можно найти, мы её тоже нашли исходно). Но тоже неплохо решается. Там в дальнейшем тексте (который уже написан, но ещё не опубликован) показано, как он выглядит на плюсах и в ассемблере. Результаты тоже очень даже ничего. Но увы, увы, увы. Иногда желание применить самые свежие решения разбивается о то, что есть Заказчик, компилятор которого не готов к этим подвигам. А проект оплачивает — он, в том числе. Но вода камень точит, будем точить…
Системы реального времени, это системы гарантирующие выполнение задачи за заданный промежуток времени с заданной вероятностью. Соответственно делятся на системы жесткого реального времени HRT (вероятность = 1) и мягкого SRT (< 1 но гарантированно заданная). Так вот заданная вероятность выполнения, динамический набор задач и динамическая память мало совместимы между собой.
Ну вот, на самом интересном месте. Интересует, какой именно подход применяется в качестве «объектного» подхода и как он реализован.
Процедурный подход в современных ОС применяется в основном потому, что для него есть стандартизированный ABI, понимаемый всеми языками. Ничего аналогичного для ООП мира нет. Более того, если мы возьмём главный системный язык (C++), то его ООП ABI не совместим даже внутри разных компиляторов (и даже разных версий!) этого языка. Что уж тут говоришь о совместимости с другими языками. Другое дело, если у вас всё ПО будет компилироваться исключительно в одну бинарную прошивку вместе с ОС — тогда конечно же нет никаких проблем. Но если ваша ОС подразумевает возможность запуска чужого ПО в виде готовых бинарных сборок, то вряд ли у вас есть какой-то ещё выбор помимо процедурного API. Ну разве что ограничить разработку под вашу ОС одним языком и компилятором. )))
Сейчас поддерживается один язык и три компилятора. Само собой, «прошивка» собирается одним компилятором. Но исходники можно скормить одному из трёх.

В целом — все RTOS подобного уровня собираются монолитно с приложением. Мы решили пойти тем же путём. Начинать лучше с реальных вещей, а уже потом — расширять, по мере надобности.
В RTOS нет никаких проблем сделать динамическую загрузку.
В версиях Линукс для ядер без MMU (бывшая uLinux) и в NuttX и в VxWorks и других малых RTOS есть такая возможность.
Проблема только в том, что с загрузкой сторонних приложений не будет работы в реальном времени.
А где не нужно реальное время ставят raspberry pi и прочие модули с линуксом и это получается даже дешевле чем с микроконтроллерами и RTOS.

Промежуточное, я так понимаю, будет все тот же избитый набор: FatFS да lwIP.
Но они то написаны на голом С-и.
Поэтому RTOS-ы на С++ еще долго будут не востребованы.
Поэтому RTOS-ы на С++ еще долго будут не востребованы.


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

Раньше я использовал другие ОС для программирования под STM32. Потом, само собой разумеется, был вынужден делать на нашей. Ну иначе что это за ОС, которой сам не пользуешься? И теперь все иные подходы мне категорически не нравятся. Сложно рассказывать, пока не было статей про те же драйверы. Короче, может, я просто привык, а может — как раз тот случай, когда при переходе на лучшее особо не замечаешь, а при возврате к старому — сразу ощущается.

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

Arduino же многие пользуются. А там — как раз ООП. И поглядите, что там народ в коде творит. Дух захватывает. Я ради ESP8266 эту библиотеку изучил.
Подумал и решил добавить: Файловая система ещё не устаканилась, так что она ещё в будущем времени. Там исходно планировался именно объектно-ониентированный вариант а-ля Ардуино. Но потом победила точка зрения плюсовых потоков, так как они являются частью стандарта языка в наше время, а в той же Ардуине есть два вида файловых классов, которые очень похожи друг на друга, но не совместимы по синтаксису. Само собой, всё это будет обёрткой вокруг «избитой» процедурной файловой системы.

И не могу не отметить такой Ардуиновский проект, как Marlin — «прошивка» для 3D принтера. Когда я полтора года переносил этот код на ARM, выучил его почти наизусть. Тут недавно залез в самую последнюю версию — не узнал. Всё переделали на классы. Причём как и у нас, ради структурированности.

То есть, мир медленно, но к плюсам движется. Но медленно. Как в своё время транзисторы активно не внедрялись, пока не ушли на пенсию ламповики.
Реальное время и структурированность (если я правильно понял этот ваш термин) несколько несовместимы.
Я сейчас с удовольствием изучил Zephyr OS. Вся написана на C-и. Современная. Поддерживает последний писк моды — mesh сети на Bloetooth.
А у вас я увидел только декларации IoT и ни одного упоминания стека который вы предлагаете для IoT.
Уверен на 99% что у вас не будет стека IoT написанного на C++, максимум опять обертка.
Что до структурированности и реального времени — давайте дождёмся глав с практическими примерами, тогда обсудим конкретные случаи.

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

В целом — на самом деле, какая разница, что на чём базируется? Философия — не мой конёк. В конце концов, оно всё в ассемблер превращается. Интереснее, как это выглядит для прикладного программиста. И вот прикладному программисту всё подаётся в классовом виде. А что мы сами делаем с нуля — оно и от роду объектно-ориентированное. Но кое-что приходится и обернуть, так как всё и сразу сделать невозможно. Тем не менее, если можно стремиться к этому — почему бы не устремиться?

Что до IoT, то мы сейчас работаем с Cortex M, дешёвый IoT модуль на Cortex M3 — это RTL8710, он базируется на старом добром LwIP. А в конце концов, всё превратится в ассемблер. Но на пользовательском уровне — наша ОС, она объектная. Аналогия — объектная Arduino вокруг ESP8266 или того же RTL8710. Причём у неё в основе — ну разумеется, LwIP.
Поэтому RTOS-ы на С++ еще долго будут не востребованы.

Есть например eCos ядро на C++, а API для пользователя на C или C++.
Opensource не очень популярна, но вроде коммерческая еще держится.

Поэтому RTOS-ы на С++ еще долго будут не востребованы.

Глупости какие. Не стоит путать языка на котором написана ОС и то какие она предоставляет API. Внутри очень многие ОС написаны на C++ и это вполне оправдано, т.к. этот язык абсолютно во всём превосходит C. А вот API чаще его выставляется в процедурном стиле, т.к. он давно стандартен и его использование возможно из любых языков/компиляторов.

P.S. Если что, мы сами с большим удовольствием использую возможности C++17 в программирование под МК. Правда без всяких ОС. )))
Я к тому, что в других «взрослых» ОС процедурное API является следствием вполне фундаментальных причин, а не чем-то вроде отсталости и т.п. И вы с этими проблемами тоже столкнулись бы, если бы не ограничились упрощённой задачкой с исключительно монолитными прошивками.

Да, и кстати многие из этих взрослых ОС написаны внутри себя с помощью полноценного ООП ещё несколько десятков лет назад, только вот выставить наружу эти интерфейсы в API не получается.
В тексте рассказано про не менее «монолитные» ОС с процедурным подходом. Более мощные в тексте не рассматриваются. Правда, с момента начала разработки появился вполне себе объектный MBED. Ну, и Arduino, хоть это не ОС, а библиотека — но она тоже вполне себе объектная. Что только подтверждает, что для такого типа ОС не только мы на этом деле «повёрнуты», другие идут тем же путём.

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

В общем, Вы верно отмечаете, что всё это — следствие монолитности. Но монолитные системы — это же нормально для систем управления. А более широкое применение и не задумывалось пока.
Теперь уже никто не помнит про такую штуку как COM которую Микрософт придумал как раз чтобы реализовать типа «безопасный обьектно-ориентированный ABI» который базировался на особенностях реализации виртуальных функций в C++

а можно подробнее, какие компиляторы используете для компиляции ос и приложений для нее?

Ну, во-первых, IAR и KEIL. Причём размер ядра такой, что даже в бесплатной версии, умеющей собирать только 32К можно попробовать (мы так автотесты проводим)

Eclipse+GCC — в демонстрационной версии, лежащей на сайте не поддерживается, но для внутренних работ — основной инструмент.
Процедурный подход в современных ОС

Вообще говоря объектно-ориентированный код можно и на чистом C писать, что и используется во многих ОС, в том числе Linux.

Ну да, библиотека GLib — это как раз ООП в полный рост. И на этот ужас без слёз смотреть нельзя. )))
Можно-то можно. Можно вообще много чего. Вопрос в том, какими силами это делается.

Почему-то вспоминается стек USB, прилагаемый к STM32. Там есть чётко выраженные слои, всё замечательно. Но связь — как раз на чистых Сях. И вот выяснилось, что система периодически виснет на больших объёмах передачи, если посылать данные в произвольный момент. Масса исследований, и вот ясно, что она не виснет, если начинать посылать в обработчике прерывания SOF. Осмотр кода показывает, что этот обработчик вполне себе может быть пропущен по слоям, но… Но чтобы протянуть его в готовый «класс» CDC, надо поправить кучу файлов, прописать кучу связей. И каждый раз во время выполнения там идёт проверка на ненулевой указатель — мелкая, но ненужная задержка…

В общем, работать-то оно работает. Но будь там не чистые Си, а Плюсы — при той же подготовительной работе, проделанной авторами стека, было бы достаточно перекрыть виртуальную функцию. И всё. Причём прототип достаточно было бы просто скопировать из родительского класса. Ну проще же было бы. И так — везде по мелочам, на чистых Сях всё достижимо, но усилия — больше.
Забавно — начать пост с обещания развенчать ошибочные представления и тут же нагородить новых.
Если не требуется многозадачность, то необходимо и достаточно взять какую-либо штатную библиотеку для контроллеров
— это утверждение в корне неверно, даже если задача может быть сделала с основном цикле, часто ее перенос под многозадачную ОС приводит к успеху. Был очаровательный пост, не помню где, в котором не простеньком МК делали игрушку с прямым выводом на телевизор и музыкой «на ножке», так в ней применение ОСРВ, при всех накладных расходах, оказалось весьма кстати и существенно упростило разработку ПО.
Современная ОС должна быть многозадачной.
— она может быть какой угодно, но должна многозадачность поддерживать.
Самой ОС не требуется никакой консоли.
— расскажите, какая из ОС требует консоль (именно ОС, а не интерпретатор командной строки, который в состав ОС входит, но, например, в ядро не входит)
Масса аппаратных вещей требует миллисекундных реакций… малейшая задержка приведёт к сбою работы всей аппаратной системы.
— требует микросекундных реакций и никак (от слова совсем) не может быть реализована в виде задачи — только аппаратная реализация критичных задержек, поскольку задержка может привести не к сбою, а к повреждению системы.
Иными словами, в правильно спроектированной программе будет соблюдаться гарантированное время реакции на те или иные события.
как было указано в предыдущем параграфе, это время реакции Вас не порадует, поскольку никаких гарантий по железу не дает.
В них не предусмотрено средств виртуализации памяти (блока MMU)
— блок MPU в последнее время есть, а этого уже позволяет реализовать изоляцию процессов.
Кроме того, у этих контроллеров имеется большой объём флэш-памяти, иногда — специально адаптированной на быстрое исполнение программ
МК без ускорителя доступа к Flash — 2017 год на дворе — такие еще делают? — но это придирки.
Объём ОЗУ в самом контроллере обычно невелик
во многих МК делают много ОЗУ именно для ускорения работы критических фрагментов программы, ну и для специфических задач.
но в пределах одного микроконтроллера изолированные процессы запустить невозможно
— смотри предыдущее примечание об MPU.
ОС компилируется и компонуется монолитно, вместе с программой пользователя
— всего лишь один из подходов, никто не мешает делать правильно и разделить их, остро популярная ESP делает именно так и прекрасно себя чувствует.
Они обе располагаются во флэш-памяти, так как исполнение в ОЗУ на некоторых контроллерах снижает производительность
о ложности данного утверждения см. выше, пример в предыдущем параграфе.
Процедурные программы плохо структурированы, их сложно сопровождать, в них проще допускать досадные ошибки, но не буду долго останавливаться на преимуществах объектно-ориентированного подхода
плохо спроектированный объектно-ориентированный код ничуть не лучше, смею Вас уверить.
Проще сделать новую ОС. Чем, собственно, мы и занялись.
ну и главное, у Вашей ОС нет фатального недостатка.

Ну и в заключение — тем, кто интересуется вопросами ОСРВ на МК, настоятельно рекомендую весьма неплохую книгу «Real-Time Embedded Systems. Open-Source Operating Systems Perspective»
Очень сложно ответить по пунктам и не запутаться. Поэтому скажу только, что MPU у нас используется, мы не смогли с его помощью изолировать процессы. Только — защитить ядро ОС и бороться с нулевыми указателями. Это же говорится и в описаниях на Cortex M, включая книги об этом процессоре. Буду рад, если подскажете, как это сделать, обещаю «продавить» на совещаниях реализацию, чтобы не пропало. Я вообще люблю «продавливать» нестандартные решения.

Очень здорово, что пока что фатальный недостаток не обнаружен (нами, кстати, тоже пока что). Надеюсь, он не вылезет до самого конца публикаций, так как дальше пойдёт описание функциональности. Но законов Мерфи никто не отменял, так что он вполне может объявиться.
Нет, я имел в виду, что в Вашей ОС не будет ФАТАЛЬНОГО недостатка — то, что она сделана не Вами. Все остальные недостатки можно исправить, а этот — никогда.
А по поводу MPU — в указанной книге об этом говорится, накладные расходы великоваты, но реализация есть.
За этот недостаток лично я — спокоен.

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

Исходно считалось, что мы попробуем, наберёмся опыта, а затем — создадим «боевой» проект. Посему не боялись закладывать в архитектуру не устоявшиеся у других варианты, а то, как оно нам виделось правильней (при том, что опыт работы с RTOS в качестве пользователей у нас был, так что виделось нам более-менее чётко). Но потом проект, выросший из прототипа оказался вполне жизнеспособным до сих пор.

Так что за отсутствие этого недостатка я спокоен.
Sign up to leave a comment.

Articles