Как стать автором
Обновить

.NET nanoFramework — платформа для разработки приложений на C# для микроконтроллеров

Время на прочтение 14 мин
Количество просмотров 22K
nanoframework

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

.NET nanoFramework является малой версией «большого» .NET Framework предназначенного для настольных систем. Разработка приложений ведется на языке C# в среде разработки Visual Studio. Сама платформа является исполнительной средой .NET кода, это позволяет абстрагироваться от аппаратного обеспечения и дает возможность переносить программный код с одного микроконтроллера на другой, который тоже поддерживает .NET nanoFramework. Программный код на C# для настольных систем, без изменений или с небольшой адаптацией (необходимо помнить про малый объем оперативной памяти) исполнится на микроконтроллере. Благодаря этому, разработчики на .NET с минимальными знаниями в области микроэлектроники смогут разрабатывать различные устройства на .NET nanoFramework.

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

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

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

Особенности .NET nanoFramework:

  • Может работать на 32- и 64-разрядных микроконтроллерах ARM, с наличием всего 256 КБ флэш-памяти и 64 КБ ОЗУ.
  • Работает нативно на чипе, в настоящее время поддерживаются устройства ARM Cortex-M и ESP32.
  • Поддерживает самые распространенные интерфейсы такие как :GPIO, UART, SPI, I2C, USB, networking.
  • Обеспечивает встроенную поддержку многопоточности.
  • Включает функции управления электропитанием для обеспечения энергоэффективности, например, устройств работающих от аккумуляторных батарей.
  • Поддерживает совмещение управляемого кода на C# и неуправляемого кода на C/C++ в одном проекте.
  • Автоматическая сборка мусора благодаря сборщику мусора.

В сравнение с другими платформами:

  • Доступен интерактивный отладчик при запуске кода на самом устройстве с точками останова.
  • Есть развитая и бесплатная среда программирования с Microsoft Visual Studio.
  • Поддержка большого количества недорогих плат от различных производителей, включая: платы Discovery и Nucleo от ST Microelectronics, Quail  от Mikrobus, Netduino  от Wilderness Labs, ESP32  DevKit C, Texas Instruments CC3220 Launchpad, CC1352 Launchpad и NXP MIMXRT1060-EVK.
  • Легко переносится на другие аппаратные платформы и устройства на ОС RTOS . В настоящее время совместимость обеспечивается в соответствие с  CMSIS и ESP32 FreeRTOS.
  • Полностью бесплатное решение с открытым исходным кодом, никаких скрытых лицензионных отчислений. От основных компонентов до утилит, используемых для создания, развертывания, отладки и компонентов IDE.


Предыстория


Вначале было Слово и было это Слово .NET Micro Framework от компании Micrsoft. До появления .NET nanoFramework, в Microsoft любительский проект перерос в серьезную платформу .NET Micro Framework, которая быстро завоевала популярность на американском рынке. Такая компания GHI Electronics с 2008 года, построила весь свой бизнес на разработке микроконтроллеров и решений на базе .NET Micro Framework. В портфолио GHI Electronics были небольшие микроконтроллеры в стиле Arduino — FEZ Domino и весьма производительные с несколькими мегабайтами ОЗУ (для микроконтроллеров это весьма круто).

Микроконтроллеры компании GHI Electronics

GHI Electronics Modules

Устройства могли работать практически с любой периферией, была поддержка стека TCP/IP, WiFI, обновления по воздуху. Была даже ограниченная реализация СУБД SQLite, поддержка USB Host и USB Client. Не трудно понять что компания быстро смогла себе сделать имя, стать основным разработчикам решений на .NET Micro Framework, продукцию которой постановляют во все страны мира.

В 2014 г. в проекте Школьный звонок на .NET Micro Framework с удаленным управлением мною использовалась плата FEZ Domino от GHI Electronics. Так же было и множество других проектов таких как Netduino.

FEZ Domino

FEZ Domino

В октябре 2015 года на GitHub был опубликован релиз .NET Micro Framework v4.4, этот релиз оказался последним. Компании Micrsoft отказалась дальше развивать платформу, с этого момента начинает свою историю проект nanoFramework (с 2017 года), в основе которого кодовая база .NET Micro Framework. Многие основные библиотеки были полностью переписаны, некоторые перенесены как есть, было проведено множество чисток и улучшений кода. Энтузиасты встраиваемых систем, гики увлеченные программированием, возродили платформу!

Работа над платформой ведется в основном в свободное время. Некоторые из основных участников работают в компаниях, которые активно спонсируют .NET nanoFramework и предлагают свои рабочие часы для продвижения проекта. Если вы используете .NET nanoFramework как часть своего продукта или просто хотите его поддержать, можете сделать пожертвование. Это позволяет оплачивать затраты на инфраструктуру и уделять больше времени на реализацию проекта.


Архитектура платформы


Платформа включает в себя уменьшенную версию .NET Common Language Runtime (CLR) и подмножество библиотек базовых классов .NET вместе с наиболее распространенными API-интерфейсами, включенными в универсальную платформу Windows (UWP).  В текущей реализации, .NET nanoFramework работает поверх ChibiOS которая поддерживается, некоторыми платами ST Microelectronics, Espressif ESP32, Texas Instruments CC3220 Launchpad, CC1352 Launchpad и NXP MIMXRT1060-EVK. Разработка ведется в Microsoft Visual Studio или Visual Studio Code, отладка производится непосредственно на устройстве в интерактивном режиме.

Общая архитектура


Для того чтобы эффективно писать код на C # на микроконтроллере, необходимо понимать (на высоком уровне), как это работает. Весь код в микроконтроллере делится на 4 логических компонента, как показано ниже:

nanoframework architecture

На самом высоком уровне находится ваше приложение на C #, которое необходимо запускать на MCU. Ниже располагается уровень CLR, исполнительная среда для нашей программы. Загрузчик — базовый компонент любого микроконтроллера, запускает среду CLR при включении MCU. Наконец, на самом низком уровне у нас есть MCU.

Для использования .NET nanoFramework необходимо загрузить среду nanoCLR на микроконтроллер. После этого приложение на C#, скомпилированное в виде бинарного файла, можно загружать на микроконтроллер.

Схема архитектуры .NET nanoFramework


nanoframework architecture

nanoCLR базируется на слое аппаратной абстракции (HAL). HAL предоставляет абстракцию устройств и стандартизует методы и функции работы с устройствами. Это позволяет использовать наборы функций которые одинаковы доступны на уровне абстракции платформы (PAL) и конкретных драйверов. Среда nanoCLR построена на PAL и содержит некоторые ключевые библиотеки, такие как mscorlib (System и несколько других пространств имен), которые всегда используются. Модульность .NET nanoFramework позволяет добавлять пространства имен (namespaces) и классы, связанные с nanoCLR.


ChibiOS


ChibiOS/RT — компактная многозадачная операционная система реального времени (ОСРВ). Предназначена для встраиваемых приложений, работающих в реальном времени. Эта ОСРВ отличается высокой мобильностью, компактными размерами и, главным образом имеет свою собственную уникальную архитектуру, которая как никак подходит для быстрого и эффективного переключения контекста.

Основные характеристики:

  • Эффективное и портативное ядро.
  • Лучшая в своем классе реализация переключения контекста.
  • Множество поддерживаемых платформ.
  • Статичная архитектура — все статически выделяется во время компиляции.
  • Динамические расширения — динамические объекты поддерживаются как дополнительный слой надстройки статичного ядра.
  • Богатый набор примитивов для ОСРВ: потоки (threads), виртуальные таймера (virtual timers), семафоры (semaphores), мьютексы (mutexes), переменные условия/синхронизации (condition variables), сообщения (messages), очереди (queues), флаги событий (event flags) и почтовый ящик (mailboxes).
  • Поддержка алгоритма наследования для мьютексов.
  • HAL-компонент поддержки различных абстрактных драйверов устройств: порт, последовательный порт, ADC, CAN, I2C, MAC, MMC, PWM, SPI, UART, USB, USB-CDC.
  • Поддержка внешних компонентов uIP, lwIP, FatFs.
  • Инструментарий для отладки ОСРВ

Поддерживаемые платформы:

  • ARM7, ARM9
  • Cortex-M0, -M0+, -M3, -M4, -M7
  • PPC e200zX
  • STM8
  • MSP430
  • AVR
  • x86
  • PIC32

Области применения ChibiOs/RT:

  • Автомобильная электроника.
  • Робототехника и промышленная автоматика.
  • Бытовая электроника.
  • Системы управления электроэнергией.
  • DIY.

ChibiOS/RT также был портирована на Raspberry Pi, и были реализованы следующие драйверы устройств: порт (GPIO), Seral, GPT (универсальный таймер), I2C, SPI и PWM.


Поддерживаемые устройства


Поддерживаемые устройства делятся на две категории: основные платы и поддерживаемые сообществом.

Основные платы:

  • ESP32 WROOM-32, ESP32 WROOM-32D, ESP32 WROOM-32U, ESP32 SOLO-1
  • ESP-WROVER-KIT, ESP32 WROVER-B, ESP32 WROVER-IB
  • STM32NUCLEO-F091RC
  • STM32F429IDISCOVERY
  • STM32F769IDISCOVERY
  • OrgPal PalThree
  • CC1352R1_LAUNCHXL
  • CC3220SF_LAUNCHXL
  • MIMXRT1060 Evalboard
  • Netduino N3 WiFi

Платы поддерживаемые сообществом:

  • ESP32 ULX3S
  • STM32NUCLEO144-F746ZG
  • STM32F4DISCOVERY
  • TI CC1352P1 LAUNCHXL
  • GHI FEZ cerb40 nf
  • I2M Electron nf
  • I2M Oxygen
  • ST Nucleo 144 f439zi
  • ST Nucleo 64 f401re/f411re nf
  • STM NUCLEO144 F439ZI board
  • QUAIL


Пример программы


Примеры кода представлены в разделе nanoframework/Samples. Рассмотрим базовый пример, Blinky — пример программы позволяющей мигать встроенным светодиодом на плате ESP32-WROOM:

using System.Device.Gpio;
using System;
using System.Threading;

namespace Blinky
{
	public class Program
    {
        private static GpioController s_GpioController;
        public static void Main()
        {
            s_GpioController = new GpioController();

            // ESP32 DevKit: 4 is a valid GPIO pin in, some boards like Xiuxin ESP32 may require GPIO Pin 2 instead.
            GpioPin led = s_GpioController.OpenPin(4,PinMode.Output);
            led.Write(PinValue.Low);

            while (true)
            {
                led.Toggle();
                Thread.Sleep(125);
                led.Toggle();
                Thread.Sleep(125);
                led.Toggle();
                Thread.Sleep(125);
                led.Toggle();
                Thread.Sleep(525);
            }
        }        
    }
}

Программный код простой и понятный. Не требуется никаких детальных знаний аппаратной платформы, все что нужно знать, это распиновку платы. Вначале кода объявляется глобальный объект GpioController, затем устанавливается контакт с номером 4 на вывод, после этого в коде идет простое инверсное переключение  состояния. Это все что требуется знать.


Что сейчас доступно из коробки?


Аппаратные интерфейсы:

  • Windows.Devices.WiFi — работа с Wi-Fi сетью.
  • nanoFramework.Devices.Can — работа с CAN шиной. CAN (Controller Area Network) — стандарт промышленной сети, ориентированный, прежде всего, на объединение в единую сеть различных исполнительных устройств и датчиков. Используется прежде всего в автомобилях.
  • 1-Wire — 1-Wire интерфейс, используется для подключения одного/нескольких температурных датчиков DS18B20.
  • Windows.Devices.I2c, System.Device.I2c — I2C шина для подключения нескольких устройств.
  • Windows.Devices.Spi — SPI шина.
  • Windows.Devices.Adc — аналого-цифровой преобразователь (АЦП).
  • Windows.Devices.Pwm — широтно-импульсная модуляция (ШИМ).
  • System.Devices.Dac -  цифро-аналоговый преобразователь (ЦАП).

Классы:

  • Windows.Devices.SerialCommunication — работа с последовательным интерфейсом.
  • MQTT — MQTT клиент, порт популярной библиотеки M2Mqtt. Библиотека предназначена для отправки коротких сообщений, используется для Интернета вещей и M2M взаимодействия.
  • System.Net.Http.Server и System.Net.Http.Client — готовые классы Web-сервера и Web-клиента с поддержкой TLS/SSL.
  • Json — работа с данными в формате Json.
  • nanoFramework.Graphics — библиотека работы с отображения графических примитивов на LCD-TFT дисплеях.
  • System.Collections — коллекции объектов.
  • Discord bot — реализация Discord бота.
  • Json Serializer and Deserializer — Json сериализацияя/десериализация.

Сетевые протоколы:

  • AMQP.Net Lite — Облегченная версия открытого протокола AMQP 1.0 для передачи сообщений между компонентами системы. Основная идея заключается в том, что отдельные подсистемы (или независимые приложения) могут обмениваться произвольным образом сообщениями через AMQP-брокера, который осуществляет маршрутизацию, гарантирует доставку, распределяет потоки данных, предоставляет  подписку на нужные типы сообщений. Используется в инфраструктуре Azure, поддерживает шифрование TLS.
  • SNTP — протокол синхронизации времени по компьютерной сети.


Библиотеки классов


В таблице представлена общая организация библиотек классов .NET nanoFramework. Приведенные ниже примеры относятся к ChibiOS (которая в настоящее время является эталонной реализацией .NET nanoFramework):

Библиотека класса Название Nuget пакета
Base Class Library (also know as mscorlib) nanoFramework.CoreLibrary
nanoFramework.Hardware.Esp32 nanoFramework.Hardware.Esp32
nanoFramework.Runtime.Events nanoFramework.Runtime.Events
nanoFramework.Runtime.Native nanoFramework.Runtime.Native
nanoFramework.Runtime.Sntp nanoFramework.Runtime.Sntp
Windows.Devices.Adc nanoFramework.Windows.Devices.Adc
Windows.Devices.I2c nanoFramework.Windows.Devices.I2c
Windows.Device.Gpio nanoFramework.Windows.Devices.Gpio
Windows.Devices.Pwm nanoFramework.Windows.Devices.Pwm
Windows.Devices.SerialCommunication nanoFramework.Windows.Devices.SerialCommunication
Windows.Devices.Spi nanoFramework.Windows.Devices.Spi
Windows.Devices.WiFi nanoFramework.Windows.Devices.WiFi
Windows.Networking.Sockets nanoFramework.Windows.Networking.Sockets
Windows.Storage nanoFramework.Windows.Storage
Windows.Storage.Streams nanoFramework.Windows.Storage.Streams
System.Net nanoFramework.Windows.System.Net

Все  дополнительные пакеты добавляются с помощью системы Nuget, как это принято в .NET Core.


Unit-тестирование


nanoframework unit test architecture

Тестирование настольного приложения на рабочей станции не вызывает никаких проблем, но все обстоит иначе, если необходимо тестировать приложение для микроконтроллера. Исполнительная среда должна быть эквивалентна по характеристикам микроконтроллеру. В Unit тестирование кода на C#, используется концепция Адаптера (Adapter). Для тестовой платформы Visual Studio (vstest)  был разработан специальный компонент nanoFramework.TestAdapter. В нем реализовано, два интерфейса для детального описания конфигурации и третий для описания специфических параметров, таких как time out, в зависимости от целевой среды исполнения,  на реальном оборудование или в Win32 nanoCLR. Механизм проведения тестов на Win32 nanoCLR и реальном оборудовании, одинаков. Единственное отличие — это консоль вывода, которая в случае реального оборудования отправляет данные в порт отладки.

Один из интерфейсов называется ITestDiscoverer, который используется Visual Studio для сбора возможных тестов. vstest вызовет адаптер для любой запущенной сборки и передаст бинарный файл dll или exe, соответствующую определенному условию сборки (пока у нас нет TFM, и мы используем небольшой хак  и основной .NET Framework 4.0 ). Затем nanoFramework TestAdapter анализирует каталоги, чтобы найти nfproj, анализируя файлы cs, глядя на определенные атрибуты Test, определенные для nanoFramework. На основе этого составляется список, который передается обратно.

Этот хак выполняется с помощью файла с расширением .runsettings с необходимым минимумов элементов ( для запуска приложения в Win32 nanoCLR, параметр IsRealHardware необходимо выставить в false, в случае реального устройства — true):

nanoframework unit test

Когда выполняется сборка проекта отрабатывает триггер интерфейс ITestExecutor. В случае, если вы работаете в контексте Visual Studio, передается список тестов (индивидуальный или полный список), и именно здесь запускается nanoFramework.nanoCLR.Win32.exe как процесс, передающий nanoFramework.UnitTestLauncher.pe, mscorlib.pe, nanoFramework.TestFramework.pe и, конечно же, тестовую библиотеку для исполняемого файла.

nanoFramework Unit Test загрузит тестовую сборку и выполнит тесты с начиная с первого — Setup, затем TestMethod и, наконец, тесты Cleanup.

Выходные данные этого процесса перенаправляются в TestAdapter, которые затем разбираются. Важное примечание: UnitTestLauncher необходимо собрать и развернуть при отладке! В противном случае он никогда не сможет ничего вывести в консоль. Чтобы запустить тест на реальном оборудование, нужно просто добавить строку ввода в файл runsettings, как указано выше.

По окончании выполнения тестов, возвращается статусы. Простой строковый вывод со статусом теста, имени  метода и времени его выполнения и/или исключение. Тест пройден: MethodName, 1234 или Test failed: MethodName, подробное исключение. Это передается обратно в vstest, а затем отображается в Visual Studio.

Для Unit-тестирования необходимо в проект добавить NuGet пакет nanoFramework.TestFramework. Или использовать готовый проект для Unit-тестирования в Visual Studio, это самый простой способ! Он автоматически добавит в проект NuGet и .runsettings.


Лицензирование


Весь исходный код .NET nanoFramework распространяется по лицензией MIT, включая nf-interpreter, классы библиотек, расширение Visual Studio и все сопутствующие утилиты.

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

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

Но если количество выпущенных коммерческих устройств с ChibiOS не превышает 500 ядер, то оплачивать лицензию не требуется. Свыше этого объема приобретаются пакеты лицензий на 500, 1000, 5000 ядер или неограниченно. При бесплатном коммерческом использование некоторые функции недоступны и в своем продукте необходимо «реализовать» рекламу ChibiOS.

Управляемые приложения managed apps (C#) запущенные на .NET nanoFramework не компилируются и не собираются ChibiOS, а интерпретируются «на лету». Поэтому рассматриваются как отдельный компонент от встроенного ПО. Таким образом, схема лицензирования ChibiOS не распространяется на приложения C#, и не зависит от условий лицензирования ChibiOS.


Использование в промышленном сфере


Американская компания OrgPal.Iot специализируется на аппаратных и программных решениях для Интернета вещей (IOT), которые осуществляют сбор данных телеметрии для отдаленнейшего анализа, управление инфраструктурой через частное облако. Компания предоставляет конечные устройства и шлюзы для передачи данных на рабочие станции, сервера и мобильные устройства. Решения совместимы с Azure IoT.

Основные направление компании это мониторинг инфраструктуры:

  • Промышленного производства
  • Нефтяных месторождений
  • Панелей солнечных электростанций
  • Систем управления электропитанием

Одно из разработанных устройств компании это PalThree. PalThree — сертифицированное устройство Azure IoT Ready Gateway & Edge Point для сбора данных и телеметрии с последующей передачей в  облако Azure IoT. На борту большой набор входных интерфейсов для получения данных о технологических процессах. Устройство основано на  STM32 ARM 4 и ARM 7, поставляется в двух вариантах с микроконтроллерами STM32F469x и STM32F769x, с 1 МБ SDRAM на плате, флэш-памятью SPI и QSPI. Программное обеспечение основано на .NET nanoFramework, с ChibiOS для STM32.

Как это работает

nanoframework palthree sensors cloud

Устройство PalThree — используется для частого и точного мониторинга нефтегазовых месторождений. Выбор был обусловлен необходимостью использования простого решения с возможностью интеграции с сотнями датчиков. Многие компании использую различные дорогостоящие решения, это приводит к большой стоимости обслуживания и увеличивает время перестройки инфраструктуры. .NET nanoFramework  — для данных задач подходит как никак лучше из-за высокой скорости разработки решений и легкости интеграций различных интерфейсов.

Цистерны для хранения нефтегазовых продуктов
nanoframework oil tank palthree

Шкаф с PalThree
nanoframework palthree close up


Web-сервер с поддержкой: REST api, многопоточности, параметров в URL запросе, статических файлов.


Специально для .NET nanoFramework, Laurent Ellerbach разработал библиотеку nanoFramework.WebServer, которая по своей сути является «упрощенной версией» ASP.NET.

Возможности Web-сервера:

  • Обработка многопоточных запросов
  • Хранение статических файлов на любом носителе
  • Обработка параметров в URL запросе
  • Возможность одновременной работы нескольких веб-серверов
  • Поддержка команд GET/PUT и любых другие
  • Поддержка любого типа заголовка http-запроса
  • Поддерживает контент в POST запросе
  • Доступно использование контроллеров и маршрутизации
  • Хелперы для возврата кода ошибок, для REST API
  • Поддержка HTTPS
  • Декодирование/кодирование URL

Ограничение: не поддерживает компрессию ZIP в запросе и ответе.

Для использования Web-сервера необходимо просто указать порт и добавить обработчик запросов:

using (WebServer server = new WebServer(80, HttpProtocol.Http)
{
    // Add a handler for commands that are received by the server.
    server.CommandReceived += ServerCommandReceived;

    // Start the server.
    server.Start();

    Thread.Sleep(Timeout.Infinite);
}

Так же, можно передать контроллер, например ControllerTest, и будет использоваться декоратор для маршрутизации и методов:

using (WebServer server = new WebServer(80, HttpProtocol.Http, new Type[] { typeof(ControllerPerson), typeof(ControllerTest) }))
{
    // Start the server.
    server.Start();

    Thread.Sleep(Timeout.Infinite);
}

В следующем примере, определяется маршрут «test» и т.д., в котором определяется метод GET, и «test/any»:

public class ControllerTest
{
    [Route("test"), Route("Test2"), Route("tEst42"), Route("TEST")]
    [CaseSensitive]
    [Method("GET")]
    public void RoutePostTest(WebServerEventArgs e)
    {
        string route = $"The route asked is {e.Context.Request.RawUrl.TrimStart('/').Split('/')[0]}";
        e.Context.Response.ContentType = "text/plain";
        WebServer.OutPutStream(e.Context.Response, route);
    }

    [Route("test/any")]
    public void RouteAnyTest(WebServerEventArgs e)
    {
        WebServer.OutputHttpCode(e.Context.Response, HttpStatusCode.OK);
    }
}

Функция RoutePostTest будет вызываться каждый раз, когда вызываемый URL-адрес будет test, Test2, tEst42 или TEST, URL-адрес может быть с параметрами и методом GET. RouteAnyTest вызывается всякий раз, когда URL-адрес является test/any, независимо от метода. По умолчанию маршруты не чувствительны к регистру, и атрибут должен быть в нижнем регистре.

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

Cooming Soon


В продолжение к публикации, будет практическая работа с загрузкой CLR на ESP32 и Nucleo, с написанием первой программы на C#.

Страница проекта .NET nanoFramework
Теги:
Хабы:
+40
Комментарии 54
Комментарии Комментарии 54

Публикации

Истории

Работа

Ближайшие события

Московский туристический хакатон
Дата 23 марта – 7 апреля
Место
Москва Онлайн
Геймтон «DatsEdenSpace» от DatsTeam
Дата 5 – 6 апреля
Время 17:00 – 20:00
Место
Онлайн