Микроконтроллеры содержат микропроцессорное ядро ARM, точнее ARM Cortex-M. Это ядро присуще не только микроконтроллерам STM32, оно существует само по себе, и на его основе выпускается множество микроконтроллеров от разных производителей.
Keil MDK-ARM (произносится «Кеил эм-ди-кей арм») — это среда разработки для микроконтроллеров с ядром ARM Cortex-M.
Данные PostgreSQL будут храниться вне контейнера, в папке «./myapp_data/database».
У загружаемых файлов тоже внешнее хранилище – папка «./myapp_data/media».
Строчка «condition: service_healthy» задает условие, что контейнер с базой данных должен быть не просто запущен, но и база данных должна принимать соединения. Без этого условия веб-приложение запуститься раньше, чем база данных будет доступна.
Для создания образа веб-приложения (web) используется Dockerfile:
FROM python:3.11
WORKDIR /usr/src/app
# Копируем исходники с хоста (из текущей папки)
# в образ (в папку WORKDIR).
COPY . .
# Устанавливаем зависимости веб-приложения.
RUN pip install --no-cache-dir -r requirements.txt
Веб-приложения запускается с помощью скрипта start-prod.sh:
В системном программировании постоянно приходится производить манипуляции с битами и байтами. Именно о таких манипуляциях пойдет речь в данной статье.
Типы
В Go есть типы, которые позволяют точно задать размер числовой переменной:
uint8 – 1 байт
uint16 – 2 байта
uint32 – 4 байта
uint64 – 8 байт
Префикс «u» означает, что значение переменной беззнаковое, то есть 0, 1, 2 и так далее.
Без префикса «u» число будет знаковым, для int8 от -128 до 127. Отрицательные числа кодируются дополнительным кодом.
Типы int и uint лучше не использовать, так как на разных платформах они имеют разную длину, обычно 32 бита или 64 бита. Тип переменной нужно прописывать явно:
var x uint16 = 123
Если не указать тип uint16, то переменная будет типа int.
Поскольку тип uint8 хранит байт, то для этого типа есть синоним – byte. То есть byte и uint8 — это одно и тоже. Там, где нужно передать byte, можно передавать uint8, и наоборот, ошибки не будет.
Набор байт можно представить ввиде массива:
b := []byte{0, 1, 2, 3}
То есть многобайтовые последовательности можно хранить как в перменных типа uintN, так и в массивах. Но при использовании uintN нужно задуматься о порядке байт: little-endian или big-endian. Порядок байт зависит от платформы. Например, переменная типа uint16 содержит число, состоящее их 2-x байт, в памяти эти два байта могут располагаться по разному, в зависимости от платформы (процессора, операционной системы). При переборе ячеек памяти, младший байт может идти перед старшим, а может наоборот. Чаще всего младший байт идет вперед, такой порядок называется little-endian.
В пакете encoding/binary есть методы для преобразования uintN в массив байт и обратно.
Функции для преобразования числа (uint16) в массив байт:
binary.LittleEndian.Uint16([]byte) uint16
binary.BigEndian.Uint16([]byte) uint16
binary.NativeEndian.Uint16([]byte) uint16
Функции для преобразования массива байт в число (uint16):
binary.LittleEndian.PutUint16([]byte, uint16)
binary.BigEndian.PutUint16([]byte, uint16)
binary.NativeEndian.PutUint16([]byte, uint16)
Числа
Go позволяет записывать числа в двоичном и шестнадцетиричном формате. А так же в восьмеричном (но кому он нужен?).
Для удобства восприятия, разряды можно разделять подчеркиванием.
Примеры:
двоичное число: 0b1010_1111
шестнадцетиричное число: 0xF010_1234
Битовые операции
Операция
Пример
И
result = a & b
ИЛИ
result = a | b
Ислючающее ИЛИ
result = a ^ b
Инверсия
result = ^a
И-НЕ
result = a &^ b
Сдвиг влево
result = a << b
Сдвиг вправо
result = a >> b
Эти операции в сочетании с присваиванием:
Операция
Эквивалент
b &= a
b = b & a
b |= a
b = b | a
b ^= a
b = b ^ a
b &^= a
b = b &^ a
b >>= a
b = b >> a
b <<= a
b = b << a
В отличии от языка C в Go появилась новая операция – И-НЕ. Это операция И, но с инверсий второго аргумента, то есть «a И (НЕ b)». Такая операция часто используется для обнуления бита:
a &^= 1<<n
Пример. В результате следующей операции в переменной «a» биту под номером «n» будет присвоен 0.
a := 0b1111
a &^= (1 << 2) // Результат: 1011
Биты считаются с нуля справа налево.
Строковое представление
Различные байтовые и битовые представления можно выводить в консоль или получать ввиде строки, с помощью форматирования строк:
fmt.Printf(format, a, b, c) – печатает в консоль
fmt.Srintf(format, a, b, c) – возвращает строку
format – форматная строка, определяет формат результирующей строки.
Допустим вы владеете сервером с белым IP-адресом 111.222.123.123. И хотите разместить на нем два сайта example.com и example.org. Такое размещение еще называется виртуальным хостингом.
В первую очередь, в настройках DNS сервера для доменов example.com и example.org нужно добавить записи A, которые будут ссылаться на IP-адрес вашего сервера.
Имя записи
Тип записи
Значение
example.com
A
111.222.123.123
example.org
A
111.222.123.123
Чтобы все было серьезно, наши сайты будут работать по протоколу HTTPS. Для этого нам нужен сертификат. Его можно получить бесплатно от Let’s Encrypt. Для этого устанавливаем на сервер утилиту certbot. Как описано в официальной инструкции.
После установки утилиты, получаем сертификат следующей командой:
Создадим папку для конфигурационных файлов и продолжим работать в ней:
mkdir webserver cd webserver
Нам понадобится несколько докер-контейнеров. Проще всего создать их с помощью docker-compose. Создадим конфигурационный файл docker-compose.yml со следующим содержимым:
version: "3"
services:
webserver:
image: nginx
ports:
- 80:80
- 443:443
# При перезагрузке сервера, контейнер запуститься автоматически.
restart: always
volumes:
# Пробрасываем в контейнер файл конфигурации Nginx.
- ./nginx.conf:/etc/nginx/nginx.conf:ro
# Пробрасываем папку для certboot, чтобы обновлять сертификат методом webroot.
- ./certbot:/var/www/html/certbot
# Пробрасываем в контейнер ключи Let's Encrypt.
- /etc/letsencrypt/live/example.com/fullchain.pem:/etc/nginx/certs/fullchain.pem:ro
- /etc/letsencrypt/live/example.com/privkey.pem:/etc/nginx/certs/privkey.pem:ro
# Перед запуском Nginx нужно запустить отдельные сайты.
depends_on:
- example-com
- example-org
example-com:
build: example-com/
example-org:
build: example-org/
С помощью такого конфига, docker-compose создаст три контейнера, то есть три сервера, которые смогут взаимодействовать друг с другом. webserver, example-com и example-org – это доменные имена, с помощью которых сервера могут обращаться друг к другу. Например, http://example-com:8000/.
Теперь создадим конфигурационный файл для Nginx, nginx.conf, со следующим содержимым:
nginx.conf
user nginx;
worker_processes auto;
error_log /var/log/nginx/error.log notice;
pid /var/run/nginx.pid;
events {
worker_connections 1024;
}
http {
include /etc/nginx/mime.types;
default_type application/octet-stream;
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for"';
access_log /var/log/nginx/access.log main;
sendfile on;
keepalive_timeout 65;
# Обработка запросов по HTTP.
server {
listen 80;
server_name _;
# Для обновления сертификата с помощью certbot методом webroot.
location /.well-known/acme-challenge {
root /var/www/html/certbot;
allow all;
}
# Перенаправление HTTP на HTTPS.
location / {
return 301 https://$host$request_uri;
}
}
# Предотвратить обработку HTTP-запросов, если в запросе не указан домен.
server {
listen 80;
server_name "";
}
# Специфика протокола SSL не позволяет использовать разные сертификаты,
# поэтому сертификат один на все домены.
ssl_certificate /etc/nginx/certs/fullchain.pem;
ssl_certificate_key /etc/nginx/certs/privkey.pem;
# предотвратить обработку HTTPS-запросов, если в запросе не указан домен.
server {
listen 443 ssl;
server_name "";
return 444;
}
# В соответствии с доменом, передаем запрос на сервер конкретного сайта.
server {
# Внешний порт – 443 (стандартный порт для HTTPS).
listen 443 ssl;
# Внешний домен.
server_name example.com;
location / {
# Протокол HTTP так как сервер доступен только из внутренней сети.
# example-com – домен сервера, который мы прописали в docker-compose.yml.
# 8000 – порт сервера
proxy_pass http://example-com:8000;
}
}
server {
listen 443 ssl;
server_name example.org;
location / {
proxy_pass http://example-org:8000;
}
}
}
Но у нас пока нет сайтов. Создадим заглушки для них.
В этом документе находится новый проект планировки территории Аметьево с двумя чертежами, описанием проекта и планом работ.
Чертеж 1
Чертеж 2
Генплан
В документе опубликованы 2 чертежа и описание проекта.
Генплан и вся связанная с ним информация размещена в разделе Градостроительство на сайте мэрии Казани.
Ниже приведены выжимки из плана, связанные с Аметьево.
Кликайте на картинки, чтобы увеличить.
Карта планируемого размещения линейных объектов транспортной инфраструктуры местного значения (линейные объекты — это дороги):
Обозначения:
Основной чертеж Генерального плана городского округа Казань (карта функциональных зон):
Обозначения:
Описание генплана находится в документе «Положение о территориальном планировании» (Приложение к решению №5-38.pdf). Этот документ состоит почти из 800 страниц.
Генеральный план г. Казани разработан на следующие проектные периоды:
первая очередь строительства (до 2025 года);
расчетный срок – на 20 лет (до 2040 года);
перспектива – на 35 лет (до 2055 года).
На карте с линейными объектами пунктирными линиями обозначены новые дороги, для них есть условные названия «Проезд №». Более подробная информация о проездах содержится в приложении указанном выше. Проезд №79 — страница 389. Проезд № 116 — страница 416.
При разработке инструментов, которые взаимодействуют с разными СУБД, приходится учитывать много нюансов, потому что одни и теже вещи реализованы по-разному и стандарт SQL поддерживается по-разному. Если рассмотреть достаточное количество СУБД, то окажется, что нет универсального способа удалить функцию или процедуру.
Эти команды принимают имя цели в качестве первого аргумента. Цели создаются командами add_executable и add_library. Для add_executable целью является исполняемый файл, а для add_library — библиотека (статическая или динамическая).
CMake поддерживает следующие команды для добавления глобальных настроек:
include_directories — добавляет пути поиска заголовочных файлов.
link_libraries — добавляет линкуемые библиотеки.
Эти настройки применяются к целям в текущей папке и всех вложенных папках.
Команды для настройки целей и глобальные команды очень похожи, но имеют разную область видимости. К сожалению, нет аналогичных команд для настройки исходных файлов.
set_property
Чтобы добавить настройки к исходному файлу, можно воспользоваться командой set_property или set_source_files_properties. Пример использования:
set_property позволяет добавлять настройки для нескольких исходных файлов одновременно.
Если использовать опцию APPEND, то настройка добавляются к уже существующему списку настроек.
Объектная библиотека
Еще один способ — создать из исходного файла или их набора специальную цель, которая называется объектной библиотекой.
Синтаксис команды для создания объектных библиотек:
add_library( OBJECT ...)
К такой цели можно применять команды с префиксом target_. Например, можно добавить определение LOGGER_TYPE=3 только для файла logger.cpp. Делается это следующим образом
add_library(logger OBJECT logger.cpp)
target_compile_definitions(logger PUBLIC LOGGER_TYPE=3)
Объектную библиотеку можно добавить к другим целям как набор исходных файлов. Для этого в команды add_executable или add_library надо добавить выражение $, где objlib — имя объектной библиотеки. Например:
Поддержка объектных библиотек была введена в CMake версии 2.8.8 (апрель 2012 года). При использовании объектных библиотек рекомендуется в файле CMakeLists.txt ограничить версию CMake на уровне 2.8.8 или выше:
В статье приводится способ настройки общей папки, когда на виртуальной машине установлен Linux, в частности Ubuntu 18.04.
Первым делом нужно установить дополнения гостевой ОС.
В настройках виртуальной машины нужно выбрать общие папки. Нужно поставить галочки «Авто-подключение» и «Создать постоянную папку.»
После сохранения настроек, на рабочем столе виртуальной машины появится папка с префиксом sf_. Это и есть общая папка.
Но пока в эту папку нет доступа. Чтобы доступ появился, нужно добавить своего пользователя в группу vboxsf. Это делается в терминале с помощью следующей команды.
sudo usermod -a -G vboxsf <USERNAME>
Где вместо <USERNAME>, нужно указать ваше имя пользователя.
Доступ в папку откроется после перезагрузки виртуальной машины.