Embedded linux что это
После того как я опубликовал на хабре анонс, меня спросили:
- Где эту штуку можно использовать?
- На каком железе это будет работать?
Надеюсь, в статье вы найдете ответы на эти вопросы.
Начнем с того, что такое встроенная система.
Такие компьютеры можно условно разделить на два класса:
Большой класс встроенных систем в противоположность малому обычно обладает операционной системой и управление осуществляется специализированным программным обеспечением работающего в ней. Этот подход удобен, когда устройство обладает большим количеством сложных интерфейсов ввод-вывода или выполняет сложные функции. К примеру такого рода устройством является беспроводной VoIP-телефон. В нем есть беспроводной модуль Wi-Fi, клавиатура, экран, динамик и микрофон. При осуществлении звонка встраиваемая система должна одновременно обеспечивать кодирование/декодирование звука, подключение к точке доступа, взаимодействие с VoIP-АТС и передачу звука ей. Реализация всех этих задач в виде одной программы, работающей напрямую с аппаратным обеспечением, весьма сложна. Но если воспользоваться операционной системой, она возьмет на себя львиную долю рутинной работы, предоставляя программисту более простой интерфейс, за счет чего задача становится менее трудоемкой. Используются встроенные системы большого класса не так широко как малого, но в более сложных устройствах. Из того, что вы можете встретить в повседневной жизни, это:
- VoIP-телефоны
- Маршрутизаторы
- Точки доступа
- Сетевые хранилища (NAS,SAN)
- КПК
- Некоторые цифровые фотоаппараты
- Сотовые телефоны
- Игровые приставки
- Принтеры
- Платежные и инфомационные терминалы
Конечно, далеко не все из перечисленых устройств используют в качестве операционной системы Linux. Кроме Linux существуют специализированные операционные системы для встраиваемых систем, некоторые из них могут работать даже на малом классе встраиваемых систем. Linux же может работать на встраиваемых системах большого класса, соответствующих следующим критериям:
- Процессор поддерживается ядром
- Минимум 4 мегабайта ОЗУ
- Минимум 2 мегабайта ПЗУ
Если у вас есть устройство с встраиваемой системой такого класса, то остается только найти способ загрузить ядро Linux на нем. Это может позволить расширить его функции или даже модифицировать их под свои нужды. Ограничиваться это будет только ресурсами устройства и вашей фантазией. :)
Обращаюсь к вам как к специалисту :)
Подскажите, реально ли собрать на базе OpenEmbedded компактный дистрибутив с X, FireFox или Opera и Flash? Вариант использовать десктоп дистрибутив не подходит, так как в них слишком много лишнего, а мне нужен именно минимум, необходимый для работы вышеозначенного софта.
Приемущество второго метода в том что размер дистрибутива будет меньше и существенно проще его изменять. Но вообще все зависит от какое железо и какие задачи.
Доброго времени суток!
Реально ли Embedded Linux бесплатен и средства разработки под него? Если нет, тогда нужна любая инфа про то сколько и за что.
Есть и бесплатные и платные. OpenEmbedded является бесплатной.
Проект коммерческий. Ни исходники ни схемы разрабатываемого девайса не будут свободно распространяться. Не будет ли проблем с GPL лицензиями?
Нет. В случае соблюдения GPL лицензии. Во первых вы не должны линковать свое ПО с GPL ПО, с LGPL можно. Во вторых предоставлять исходники на те части что распрастраняются под лицензией GPL. Причем эти части достаточно передавать тем кто будет использовать вашу систему. Если ваше ПО не содержит GPL кода то оно не должно распрастраняться под этой лицензией.
3. У кого меньше время на разработку?
Без понятия. Ответить на этот вопрос без знания специфики проекта невозможно.
он у меня валяется без дела, хочу поставить на него линукс и писать программы для него на с.
С линуксом знаком мало, но собираюсь осваивать эту платформу.
Про него написано, что процессор STMP3738 ARM9-based и что Available with a Linux BSP and support from Embedded Alley
Можно ли поставить на этот навигатор какой-нибудь линукс и как мне это сделать, хотя бы примерно, в общих чертах?
Я в этом новичок, с чего начать? Какие нужны для этого инструменты и программы?
Для начала выясните как туда загружать linux и какой из платформ входящих в OpenEmbedded он соответствует. После этого вы сможете что-то сделать с этим навигатором.
В этой небольшой серии статей я попытаюсь пролить свет на тему построения Embedded Linux устройств, начиная от сборки загрузчика и до написания драйвера под отдельно разработанный внешний модуль с автоматизацией всех промежуточных процессов.
Платформой послужит плата BeagleBone Black с процессором производства Техасских Инструментов AM3358 и ядром Arm Cortex-A8, и, чтобы не плодить мигающие светодиодами мануалы, основной задачей устройства будет отправка смайлов в топовый чат, широко известного в узких кругах, сайта, в соответствии с командами от смайл-пульта. Впрочем, без мигания светодиодами тоже не обошлось.
Итак, на столе лежит чистая, т.е. без каких-либо предустановленных дистрибутивов, плата BeagleBone Black, блок питания, переходник USB-UART. Для общения с платой, переходник нужно подключить к 6-ти выводному разъему, где первый вывод обозначен точкой - это GND, выводы 4/5 - RX/TX соответственно. После установки скорости в какой-либо терминальной программе, например putty, на 115200, можно взаимодействовать с платой, о подключении подробнее и с картинками здесь.
Топовые чаты, пульты и светодиоды будут позже, а сейчас на плату подается питание и плата отвечает CCCCCCCCCCC
В переводе с бутлоадерского это означает, что первичному загрузчику, зашитому в ROM процессора, нечего загружать. Ситуацию проясняет Reference Manual, где на странице 5025 в разделе 26.1.5 описана процедура начальной загрузки. Процедура такая: первичный загрузчик проводит некоторую инициализацию: тактирование процессора, необходимой периферии, того же UART, и, в зависимости от логических уровней на выводах SYSBOOT, строит приоритетный список источников где можно взять следующий загрузчик, т.е. посмотреть сначала на MMC карте, SPI-EEPROM или сразу ждать данных по Ethernet.
Я использую способ загрузки с помощью SD карты, вот что говорит об этом раздел RM 26.1.8.5.5 на странице 5057: первичный загрузчик сначала проверяет несколько адресов 0x0/ 0x20000/ 0x40000/ 0x60000 на наличие так называемой TOC структуры, по которой он может определить загрузочный код, если так код не найти, то первичный загрузчик, предполагая на SD карте наличие файловой системы FAT, будет искать там файл с названием MLO, как это расшифровывается в RM не сказано, но многие склоняются что Master LOader. Возникает резонный вопрос, где же взять этот MLO?
Das U-Boot
Das U-Boot или просто U-Boot - Universal Boot Loader, один из самых, если не самый, распространенный загрузчик для встроенных систем, именно с его помощью можно создать требуемый вторичный загрузчик (MLO), который будет загружать третичный загрузчик (сам U-Boot), который будет загружать ядро Linux.
Перед скачиванием U-Boot, стоит сходить в репозиторий и найти тег последней версии, далее
U-Boot содержит больше тысячи конфигураций, в том числе нужную:
Это конфигурация платы AM335x evaluation module, этот модуль лежит в основе других плат, в том числе BeagleBone Black, что можно видеть, к примеру, по Device Tree, но о нем позже. Настраивается и собирается U-Boot с помощью Kconfig, то же, что используется и при сборке ядра Linux.
Установка нужного конфига:
Можно, к примеру, убрать, установленную по умолчанию, 2-х секундную задержку при загрузке платы с U-Boot
Boot options ---> Autoboot options ---> (0) delay in seconds before automatically booting
В вышеуказанных командах, используется компилятор по умолчанию, если таковой в системе установлен, и, скорее всего, он не подходит для ARM процессоров, и здесь пора упомянуть о кросскомпиляции.
ARM Toolchain
Один из видов кросскомпиляции это сборка на одной архитектуре, как правило x86-64, именуемой HOST, исходного кода для другой, именуемой TARGET. Например, для TARGET архитектуры ARMv7-A, ядра ARM CortexA-8 процессора AM3358, платы BeagleBone Black. К слову, чтобы не запутаться в ARM’ах, даже есть свой справочник, так их много и разных.
Сама сборка осуществляется набором инструментов - компилятор, компоновщик, runtime библиотеки, заголовочные файлы ядра; так называемый Toolchain. Toolchain можно собрать самостоятельно либо с помощью crosstool-NG, а можно взять готовый от компании Linaro, или самой ARM. Здесь я буду использовать Toolchain от ARM “GNU Toolchain for the A-profile Architecture Version 10.2-2020.11, x86_64 Linux hosted cross compilers, AArch32 target with hard float (arm-linux-none-gnueabihf)", если не вдаваться в излишние подробности, то это все означает, что набор инструментов будет работать на десктопной машине с Linux и собирать программы для 32-х битной ARM платформы с аппаратной поддержкой операций с плавающей запятой.
Теперь для успешной сборки U-Boot, нужно указать в переменных ARCH и CROSS_COMPILE требуемые архитектуру и путь к кросскомпилятору соответственно, например так
Либо использовать export ARCH/CROSS_COMPILE , чтобы каждый раз не набирать все это. Я, для наглядности, буду каждый раз набирать все это.
После сборки U-Boot, в папке появятся необходимые файлы, а именно
MLO - вторичный загрузчик (напомню, первичный зашит в самом процессоре)
u-boot.img - третичный загрузчик, собственно U-Boot
Для успешной загрузки с SD карты, нужно ее некоторым образом разметить. Карта должна содержать минимум два раздела, первый, отмеченный как BOOT, с файловой системой FAT, второй раздел с ext4. Разметить карту можно, к примеру, программой fdisk.
Теперь нужно просто скопировать результаты сборки U-Boot в FAT раздел, вставить карту в BeagleBone Black и в терминале наблюдать уже более осознанный ответ платы
В ответе платы есть такие строки
Failed to load ‘boot.scr’
Failed to load ‘uEnv.txt’
U-Boot, во время загрузки, смотрит наличие дополнительных команд, сначала в файле boot.scr, при его наличии, затем, если boot.scr не нашлось, в uEnv.txt. Эти файлы, помимо очередности при поиске, отличаются тем, что в файле uEnv.txt, дополнительные команды представлены в текстовом виде, т.е. он проще для восприятия и редактирования. U-Boot не создает файлы с дополнительными командами, делать это нужно самостоятельно.
Здесь происходят некоторые манипуляции в результате которых U-Boot загружает из SD карты в RAM по адресу [loadaddr] - образ ядра [zImage], и по адресу [fdtaddr] - дерево устройств [Flattened Device Tree]. Формируются аргументы, передаваемые ядру Linux, это параметры консоли, к которой подключен переходник USB-UART [console=ttyS0,115200n8], место размещения корневой файловой системы [bootpartition=mmcblk0p2], параметры разрешения на чтение/запись корневой файловой системы [rw], ее тип [ext4] и ожидание появления корневой файловой системы [rootwait]. Чтобы раскрутить всю цепочку действий U-Boot, можно, после того как U-Boot прекратит попытки найти что бы загрузить и выдаст приглашение на работу в виде =>, ввести команду printenv , она покажет значения всех переменных, которыми располагает U-Boot.
В завершении своей работы U-Boot, командой bootz , вместе с вышеуказанными аргументами и адресом дерева устройств, передает управление ядру Linux.
Ядро Linux
Прежде чем приступать к любым действиям с ядром, стоит заглянуть сюда и убедится в наличии необходимых пакетов. Следующим шагом нужно определиться с тем, какую версию ядра использовать. Здесь я использую версию 5.4.92 и вот по каким соображениям. Одной из основных причин того, что не стоит брать просто последнюю версию ядра, доступную на данный момент, наряду с наличием драйверов, является невозможность быстро протестировать это ядро на всем разнообразии платформ поддерживаемых Linux, а значит можно потратить кучу сил и времени на исправление неполадок, если что-то пойдет не так, и не факт что это вообще получится сделать. BeagleBone Black имеет официальный репозиторий, где можно найти версию ядра, протестированную на данной платформе, и long term версия 5.4.92 была последней на тот момент.
Нужный конфиг, расположенный в /arch/arm/configs, называется omap2plus_defconfig, OMAP - это название линейки процессоров, продолжением которых является AM3358, впринципе, подойдет и более общий multi_v7_defconfig.
Сам конфиг пока остается без изменений, поэтому можно просто его установить и запустить компиляцию ядра(zImage), модулей(modules) и дерева устройств(dtbs)
Проходит некоторое время.
Результат сборки, в виде zImage, находится в /arch/arm/boot, там же в папке /dts находится скомпилированное дерево устройств am335x-boneblack.dtb, оба отправляются на SD карту к файлам загрузчика. На этом FAT раздел SD карты можно считать скомплектованным. Итого, там присутствуют:
MLO - вторичный загрузчик
u-boot.img - третичный загрузчик
uEnv.txt - дополнительные команды загрузчика
zImage - образ ядра Linux
am335x-boneblack.dtb - скомпилированное дерево устройств платы
Еще при сборке ядра заказывались модули ядра, но они уже относятся к корневой файловой системе.
Корневая файловая система. BusyBox
Ядро получает корневую файловую систему путем монтирования блочного устройства, заданного в, переданном при запуске ядра, аргументе root=, и далее, первым делом, исполняет оттуда программу под названием init.
Если запустить BeagleBone Black, имея только вышеуказанные файлы для FAT раздела, то ядро будет паниковать по причине отсутствия init и, в целом, по причине пустой rootfs, т.е. корневой файловой системы.
Можно шаг за шагом создать все минимально необходимые компоненты корневой файловой системы, такие как оболочка, различные демоны запускаемые init, сам init, конфигурационные файлы, узлы устройств, псевдофайловые системы /proc и /sys и просто системные приложения. Для желающих совершать подобные подвиги, существует проект Linux From Scratch, здесь же я воспользуюсь швейцарским ножом встроенных систем с Linux, утилитой BusyBox.
Скачивание последней, на тот момент, версии:
Настройка конфигурации по умолчанию:
Чтобы не думать сейчас о разделяемых библиотеках, стоит установить статическую сборку BusyBox:
Settings ---> Build static binary (no shared libs)
Установка в папку по умолчанию _install:
Теперь в папке _install можно видеть будущую корневую файловую систему, в которую нужно добавить некоторые вещи.
Папки, помимо созданных BusyBox:
Стартовый скрипт. Дело в том, что, запускаемая в первую очередь, программа init, делает много полезного, например, выводит в консоль приглашение, но до выдачи приглашения, init проверяет наличие стартового скрипта /etc/init.d/rcS, и, при наличии, запускает его.
Этот скрипт монтирует псевдофайловые системы proc и sysfs, и ничего не мешает ему запускать, к примеру, пользовательскую программу, отвечающую за функционал устройства, но лучше будет делать это в отдельных скриптах, скомпонованных по функциональному назначению.
Стоит сказать, что работа init, на самом деле, начинается с чтения конфигурационного файла /etc/inittab, но BusyBox’овская init включает таблицу inittab по умолчанию, если таковой не окажется в корневой файловой системе.
Теперь пора вспомнить про модули ядра. Их также нужно разместить в корневой файловой системе в /lib/modules/5.4.92/, но сейчас они разбросаны по всей папке в которой собиралось ядро. Чтобы собрать модули в кучу, нужно в папке с ядром выполнить
Где в INSTALL_MOD_PATH указать путь к папке с корневой файловой системой, кросскомпилятор указывать не нужно, т.к. здесь модули ядра просто копируются по месту назначения. В результате папка /lib корневой файловой системы пополнится разделом /lib/mudules/5.4.92/ содержащим модули ядра, полученные при компиляции ядра.
Осталось скопировать все содержимое папки _install во второй раздел SD карты, тот который с ext4, и поменять владельца всего содержимого на root.
После запуска BeagleBone Black с корневой файловой системой, через 1.910315 секунды после старта ядра, система предложит активировать консоль и начать работу.
Но начать работу в такой системе, скорее всего не получится, т.к. в ней нет ничего кроме системных утилит BusyBox и моей небольшой программы, нарисовавшей приветствие, зато, эта система поможет получить общее представление о том, какая магия происходит внутри подобных устройств. Именно общее, т.к. в реальных устройствах, из-за необходимости минимизации времени загрузки, ограниченности ресурсов, заточенности под конкретную задачу, различий между ARM процессорами, построение системы может сильно отличаться. Например, на малинке, вообще сначала стартует графический процессор, который затем запускает все остальное.
По поводу же заявленных в начале драйверов, взаимодействия с внешними устройствами, автоматизации сборки и некоторого полезного функционала, пойдет рассказ в следующей статье.
Встроенный компьютер отличается от персонального компьютера (ПК) тем, что встроенная система спроектирована или сконструирована для одной или нескольких конкретных целей, в то время как ПК предназначены для широкого спектра функций. Встроенный компьютер может быть спроектирован с минимальной производительностью, необходимой для достижения его конкретных целей, что обеспечивает лёгкую и высокоэффективную компьютерную платформу. Категория охватывает широкий спектр вычислительных устройств, от бытовой электроники до оборудования авионики, роверов и космических кораблей, которые исследуют солнечную систему. Но, как и любой компьютер, аппаратное обеспечение встроенной системы бесполезно без программной платформы, и во многих случаях выбранная программная платформа представляет собой некий вид встроенной Linux®.
Linux® доказала свою популярность во многих областях встраиваемых вычислений благодаря высокому уровню настройки и гибкости, а также разнообразной аппаратной поддержке. Ядро Linux® имеет модульную архитектуру, что означает, что разработчик или инженер может выбирать драйверы и программное обеспечение высокого уровня, необходимое для конкретной системы. Поддержка множества различных микропроцессорных архитектур также является важным преимуществом, предлагаемой встроенной Linux®, поскольку во встроенных системах может использоваться микропроцессор, который сильно отличается от тех, которые имеются в ПК. Как проект программного обеспечения с открытым исходным кодом, Linux® также может использоваться без ограничений и лицензионных отчислений, которые могут присутствовать в коммерческих предложениях.
Некоторые версии встроенной Linux® могут быть построены практически с нуля, в то время как другие являются слегка изменёнными версиями существующих дистрибутивов. Как коммерческие, так и некоммерческие организации предлагают свои собственные готовые дистрибутивы, предназначенные для производителей и дизайнерских фирм. Например, мобильные телефоны и медиаплееры обычно используют готовые варианты встроенной Linux®. Компьютерные системы или сетевые устройства могут использовать только слегка изменённую версию дистрибутива Linux® для настольных компьютеров.
В областях с высокими требованиями в режиме реального времени или требованиями к производительности конечный пользователь часто активно участвует в разработке системы. Например, Национальное управление по аэронавтике и исследованию космического пространства (НАСА) получает программное обеспечение Linux® от сторонних поставщиков, но устанавливает руководящие указания для поставщиков. Другие организации, такие как компании, производящие оборудование для тестирования авионики, могут разработать собственный вариант встроенной Linux®.
Мы с гордостью сообщаем, что устройство Magic Box функционирует под управлением операционной системы Linux, а точнее её Embedded редакции. Вы спросите, почему мы выбрали именно эту ОС, а не использовали привычную для всех ОС линейки Windows? С удовольствием отвечаем.
Ни для кого не секрет, что ОС Windows установлена на 70% ПК во всём мире. И это делает её максимально распространённой операционной системой на персональных, пользовательских компьютерах. Однако не все знают, что в серверном сегменте уже порядка 50 лет бал правят Unix – подобные системы. Стоит ли рассказывать, что Unix – подобные системы хорошо зарекомендовали себя как системы для построения интранет и интернет – серверов, что большинство ОС, применяемых в военной сфере основаны на Unix – подобных системах и даже крупнейшая сетевая энциклопедия Wikipedia работает под управлением Linux. Как вы видите, для решения задач, требующих повышенной надёжности и отказоустойчивости ОС, максимальной её гибкости и способности работать на любых аппаратных платформах все выбирают не ОС Windows. Мы тоже выбрали Embedded Linux.
Ведь Embedded Linux – это специализированная версия ОС GNU/Linux, адаптированная для использования в промышленных устройствах, беспилотных летательных аппаратах, DVR и других специализированных устройствах. Особенностью этой модификации ОС является малый размер образа самой системы, а так же невысокие требования к ресурсам аппаратной платформы и высокая степень оптимизации кода под конкретную аппаратную платформу. Windows (кроме редакции CE) до сих пор не может работает на процессорах архитектуры ARM, что уж говорить о специализированных процессорах, таких как TI DaVinchi. Windows CE имеет ограниченный функционал и требует специализированного ПО. Кроме всех этих недостатков, ОС стоит денег, которые производители устройств закладывают в стоимость готовых решений.
Embedded Linux же представляет собой полноценную ОС, современную и функциональную, способную работать на любой архитектуре и адаптированную под особенности этой архитектуры, безопасную и не подверженную разрушительному влиянию вирусов. А главное – полностью бесплатную и поддерживаемую миллионами свободных разработчиков во всём мире.
Разрабатывая Magic Box мы хотели сделать его лучшим в своём роде. И мы использовали для этого самые лучшие компоненты - лучшую свободную ОС, лучшие отечественные алгоритмы видеоаналитики, специализированные аппаратные компоненты. И мы уверены, что аналогов устройству Magic Box нет как на российском, так и на зарубежном рынках.
Встроенные системы: добьется ли Linux успеха и в этой области?
Пригодна ли ОС Linux для применения во встроенных системах?
- Работа в масштабе реального времени. Linux не является операционной системой реального времени, что немедленно создает определенные неудобства с технической точки зрения многим производителям устройств, в которых этот режим необходим. Чтобы ускорить реакцию системы, многие клиенты пользуются «Linux с ядром реального времени». Однако, как мы уже отмечали, Linux это уже ядро. Так что эти производители на практике пользуются некоторой гибридной формой программного обеспечения с открытым исходным кодом. Другие производители для повышения его быстродействия модифицируют ядро, хотя и за счет отказа от других достоинств Linux. Но как только вы начинаете модифицировать операционную систему (любую ), вы тут же фактически берете на себя все обязанности и расходы по программированию и поддержке. Бесплатные программы становятся не такими уж и бесплатными, когда вы сами должны нести все расходы по их поддержке и сопровождению.
- Эффективность. Разработчики встроенных систем превзошли самих себя в создании продуктов со все более широкими функциональными возможностями при все более ужесточающихся требованиях к размерам, весу, энергопотреблению и стоимости. Свой вклад в этот процесс вносят как производители полупроводниковых приборов, так и поставщики программного обеспечения. Если для работы сервера увеличение объема занимаемой памяти или небольшое снижение эффективности операционной системы не так уж и страшно, то в устройстве со встроенной системой эффективность операционной системы определяется типом используемого процессора, а объем устанавливаемой памяти непосредственно определяется размером прошиваемого ПО. Все это напрямую определяет стоимость, срок службы аккумулятора, функциональные возможности и, в конечном счете, конкурентоспособность устройства. Компания Wind River постоянно совершенствует свой основной продукт операционную систему VxWorks чтобы она меньшими силами решала больше задач. Не так давно один из наших партнеров производителей устройств беспроводной связи уже был готов использовать Linux в своих продуктах и почти приступил к разработке ПО для работы под Linux, пока не выяснил, что это ему обойдется в 2 мегабайта из общей памяти устройства. Такая же конфигурация программных средств на базе VxWorks требовала всего 250 килобайт. Этому партнеру для достижения запланированной цены и функциональных возможностей требовалось экономить память, в то время как «бесплатное » программное обеспечение обходилось слишком дорого с точки зрения использования памяти.
- Время включения. Предполагается, что большинство устройств со встроенной системой должно реагировать на команды пользователя практически мгновенно. Для программистов, пишущих программы для персональных компьютеров или серверов, большим сюрпризом оказывается то, что, если встроенная система создана не на основе стандартной архитектуры Intel, добиться быстрой начальной загрузки Linux крайне тяжело. Создатели встроенных систем много работают над тем, чтобы решить вопросы инициализации, исполнения процедур самотестирования и загрузки в не-Intel-овских архитектурах, но Linux в этой области не предлагает никакой помощи.
- Инструментальные средства. Насколько мы можем видеть, налицо серьезный недостаток инструментальных средств разработки встраиваемых систем на базе Linux. Разработка, тестирование и отладка программ для коммерческого рынка занимает слишком много времени, если у вас под рукой нет соответствующего инструментария, причем инструментальные средства, требуемые для разработки встраиваемых приложений (типа кросс-компиляторов, отладчиков и средств анализа в масштабе реального времени), в значительной степени отличаются от аналогичных средств для более традиционных рынков Linux-систем. Не так давно один из наших клиентов, компания, известная выдающимся дизайном своих продуктов, рассматривала вопрос применения Linux в устройствах беспроводной связи. Однако как только её специалисты осознали, что на разработку таких устройств с Linux может уйти практически год, они обратились к нам и в результате стали продавать свой продукт на рынке всего через четыре месяца.
Так что же делать производителю встроенных систем?
22.04.2014
Читайте также: