LINUX.ORG.RU

Сообщения vbr

 

Как работает UART over USB, если получатель тормозит?

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

У меня есть девайс, который на компьютере принимает ровнёхонько 20 000 байтов в секунду, вообще без видимых флюктуаций. А вот на смартфоне не успевает и выходит на процентов 10-20 меньше. Я в протоколах этих не разбираюсь и предполагал, что там как-то автоматически будет буферизоваться всё где-то (в разумных пределах), а я там уже буду вычитывать, к примеру 100 раз в секунду по 200 байтов за раз, ну или как получится.

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

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

 , ,

vbr
()

nginx.service: Can't open PID file /run/nginx.pid (yet?) after start: Bad file descriptor

Archlinux, после старта nginx появляется такая ошибка в логе.

May 08 15:10:55 alpine systemd[1]: Starting A high performance web server and a reverse proxy server...
May 08 15:10:56 alpine systemd[1]: nginx.service: Can't open PID file /run/nginx.pid (yet?) after start: Bad file descriptor
May 08 15:10:56 alpine systemd[1]: Started A high performance web server and a reverse proxy server.

systemd юнит:

# systemctl cat nginx
# /usr/lib/systemd/system/nginx.service
[Unit]
Description=A high performance web server and a reverse proxy server
After=network.target network-online.target nss-lookup.target

[Service]
Type=forking
PIDFile=/run/nginx.pid
PrivateDevices=yes
SyslogLevel=err

ExecStart=/usr/bin/nginx -g 'pid /run/nginx.pid; error_log stderr;'
ExecReload=/usr/bin/nginx -s reload
KillMode=mixed

[Install]
WantedBy=multi-user.target

В nginx.conf ничего, относящегося к делу нет.

Файл /run/nginx.pid создаётся, pid в нём присутствует.

Почитал man open, пишут, что

EBADF
(openat()) pathname is relative but dirfd is neither AT_FDCWD nor a valid file descriptor.

и совсем запутался. В исходниках systemd не осилил понять, что происходит, тут и тут если кому интересно.

Версия systemd 253.4-1-arch.

Так в принципе оно вроде работает, но это же неправильно.

/run это tmpfs, никаких симлинков вроде нигде не задействовано.

Перемещено hobbit из general

 ,

vbr
()

arch живой?

Разочаровавшись в дебиане решил попробовать сабж первый раз в жизни и приятно удивился. Сходу поставил его в не самой дефолтной конфигурации (шифрование рута, syslinux, systemd в initramfs). Всё прошло прям как по маслу, я приятно удивлён. Особенно порадовало наличие vi, а не этого новомодного vim.

Собственно интересует лишь - насколько он живой? Всё же такой подход, как у него, нынче не слишком популярен, все кажется сейчас угорают по убунте и подобному.

 ,

vbr
()

Cloudflare R2, в чём подвох?

Это сервис типа S3 но без оплаты egress. Не пойму, в чём подвох. Цена за хранение тоже божеская ($15/TB). Что мне мешает сделать клон ютуба и обанкротить клаудфляр?

 

vbr
()

Максимально повторяемая страница на разных браузерах

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

Ширина и высота у страницы фиксированные.

Шрифты я использую свои.

На что ещё нужно обратить внимание, по крайней мере из очевидного?

Я так понимаю, применять что-то вроде font-size: xx-large не стоит, т.к. это не соответствует конкретному кеглю и лучше применять что-то вроде font-size: 30px.

 

vbr
()

Как правильно использовать C без стандартной библиотеки?

Хочу писать на C для МК, но так, чтобы ни единого байта не было в бинарнике, не от моего кода.

В целом я понимаю, как это всё собрать и слинковать. Вопрос больше в том, что компилятор C в моём понимании генерирует код, рассчитывая на определённый рантайм, который я у него хочу забрать. К примеру я слыхал, что компилятор может генерировать вызовы функций вроде memcpy, если посчитает нужным. Также я не очень хорошо представляю, что происходит до вызова main и насколько это важно.

Также развитие этого вопроса - тот же вопрос про C++.

 ,

vbr
()

Не могу собрать Qt для кросс-компиляции

Хочу написать приложение, которое будет работать на arm девайсе. Документации не нашёл, делаю по крохам информации, которую нашёл, но ничего не получилось.

Во-первых нужно собрать Qt для хоста.

Хост у меня дебиан. Ставлю пакеты cmake gcc g++ mesa-common-dev ninja-build perl. Собираю командами

../qt-everywhere-src-6.4.3/configure -prefix /mnt/data/qt-host -submodules qtbase
cmake --build . --parallel 4
cmake --install .

Это у меня получилось.

Далее нужно собрать Qt для таргета. Таргет у меня это какая-то китайская плата с i.MX8MM. Есть rootfs для неё.

Первая проблема в том, что не понятно, где брать компилятор. Я поставил таким образом:

dpkg --add-architecture arm64
apt-get update
apt-get install gcc-arm-linux-gnueabi g++-arm-linux-gnueabi

Также пробовал вариации с --add-architecture arm и gnueabhf. Не знаю, чем они отличаются и как понять, какой мне надо.

Далее написал файл imx8mm.cmake со следующими строчками:

set(CMAKE_SYSTEM_NAME Linux)
set(CMAKE_SYSTEM_PROCESSOR aarch64)
set(CMAKE_C_COMPILER arm-linux-gnueabi-gcc)
set(CMAKE_CXX_COMPILER arm-linux-gnueabi-g++)
set(CMAKE_SYSROOT ${INPUT_sysroot})
set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)
set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE ONLY)

и пытаюсь сконфигурировать Qt командой

/mnt/data/qt-everywhere-src-6.4.3/configure \
  -prefix /opt/qt \
  -extprefix /mnt/data/qt-embedded \
  -qt-host-path /mnt/data/qt-host \
  -sysroot /mnt/data/rootfs-ok8mm \
  -submodules qtbase \
  -nomake examples -nomake tests \
  -- \
  -DCMAKE_TOOLCHAIN_FILE=/home/build/imx8mm.cmake

Это всё кончается ошибкой

ERROR: The OpenGL functionality tests failed! You might need to modify the OpenGL package search path by setting the OpenGL_DIR CMake variable to the OpenGL library's installation directory.

Я не знаю, где посмотреть точно какая ошибка ему помешала.

В файле CMakeError.log есть миллион ошибок, но в том числе одна, которая мне кажется важной и которую я не знаю, как решить:

: && /usr/bin/arm-linux-gnueabi-gcc --sysroot=/mnt/data/rootfs-ok8mm -DCHECK_FUNCTION_EXISTS=XOpenDisplay -fPIE -pie CMakeFiles/cmTC_d6b57.dir/CheckFunctionExists.c.o -o cmTC_d6b57  /mnt/data/rootfs-ok8mm/usr/lib/libX11.so  /mnt/data/rootfs-ok8mm/usr/lib/libXext.so  /mnt/data/rootfs-ok8mm/usr/lib/libGLESv2.so  /mnt/data/rootfs-ok8mm/usr/lib/libEGL.so && :
/mnt/data/rootfs-ok8mm/usr/lib/libX11.so: file not recognized: file format not recognized
collect2: error: ld returned 1 exit status

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

Вот вывод readelf -a /mnt/data/rootfs-ok8mm/usr/lib/libX11.so.6.3.0, может быть он чем-то поможет: https://pastebin.com/raw/5t5dQ2qw

Также ещё вижу такие проблемы: в usr/include платы нет заголовков для EGL, но при этом сами библиотеки в usr/lib есть. Пока до ошибок с EGL не дошёл, планировал их решить установкой пакета EGL в хостовую систему и изменением set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY) на BOTH, хотя не уверен, что это правильно.

Может быть я зря на Qt 6 это пытаюсь делать и лучше использовать Qt 5? На плате установлена Qt 5 и есть какие-то примеры на Qt 5. Но, как я понимаю, мне всё равно для своей разработки надо собирать локально версию для кросс-компиляции.

 ,

vbr
()

А как в виртуальной машине поддерживать актуальное время?

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

Перемещено hobbit из general

 ,

vbr
()

Docker linux/amd64 работает под M1 маком с розеттой

Давно хотел проверить, но никак не доходили руки. Вообще говорят, что и в докер десктопе это есть, я не проверял. В целом запустил федору через Virtualization.Framework на M1 макбуке, в ней поставил докер, а также розетту. И теперь:

% docker run --rm -it --platform linux/amd64 debian:11 uname -a
Linux 3ae5494cbd64 6.1.18-200.fc37.aarch64 #1 SMP PREEMPT_DYNAMIC Sat Mar 11 16:03:54 UTC 2023 x86_64 GNU/Linux

Для меня это важно, мне этого давно не хватало. На qemu эмуляция была, но там такая медленная скорость, что было не юзабельно. А тут ничего так, шустренько.

% time docker run --rm -it --platform linux/amd64 debian:11 bash -c "head -c $((1024 * 1024 * 1024)) /dev/zero | sha256sum"
0.02s user 0.02s system 0% cpu 5.759 total

% time docker run --rm -it --platform linux/arm64 debian:11 bash -c "head -c $((1024 * 1024 * 1024)) /dev/zero | sha256sum"
0.03s user 0.02s system 0% cpu 4.770 total

 , ,

vbr
()

За сколько может грузиться самый быстрый линукс?

Если он запускается в виртуалке. Загрузчика вообще нет, сразу ядро и initrd подаётся на вход. Скомпилировать ядро без всего кроме того что надо для виртуалки. Как-то юзерспейс максимально быстро стартануть. Systemd самый быстрый?

У меня сейчас в виртуалке федора с UEFI за несколько секунд грузится. Мне интересно, можно ли это ускорить. Чего она там делает эти несколько секунд - не понятно. dmesg если кому интересно.

 

vbr
()

Как на старом ядре запустить современный браузер?

Имеется китайская плата на i.mx6ull. Китайцы туда поставили китайский линукс на китайском ядре 4.1.15. Браузера там нет. Я хочу туда засунуть веб приложение. Свое ядро более актуальной версии скомпилять пока не вышло. Посоветуйте как быть.

 , ,

vbr
()

Как разобраться с китайским SoB?

Имеется такая плата: OKMX6ULL-C

К ней по шлейфу подключил маленький дисплей. При подаче питания грузится какой-то китайский линукс с демо-программами.

Теперь мне надо из этого сделать что-то своё. Я на raspberry собирал свой линукс, но как тут подступиться, пока не понимаю.

Во-первых я не могу подключиться к нему по UART-у, чтобы работать полноценно, а не на крохотном дисплейчике. На выходных пинах есть UART2, …, UART4. Я подключил USB UART к UART2, но дальше соединиться не смог. К распберри я так подключался.

Судя по схеме UART1 разведён на USB-C выход на этой плате через USB-UART микросхему. Не очень понимаю, для чего это сделано. Можно ли подключить этот выход к компьютеру напрямую? Я боюсь спалить что-нибудь.

Во-вторых я не понимаю, как там вообще устроена загрузка. В распберри просто сд-карта, с неё и грузишься. Тут внутри есть emmc память на 8 гигабайтов. Встроенный линукс грузится именно с неё. Там два раздела, один на 500 MB, там ядро и ещё какой-то файл dtb. На втором разделе корень. В принципе слот для сд-карты есть. Пока грузиться с него не пробовал, т.к. вообще не очень понимаю, что туда сувать.

Ещё есть два раздела mmcblk1boot1 4MiB, mmcblk1boot0 4MiB. Они не монтируются, не знаю, что там на них.

В /etc/issue написано Freescale i.MX Release Distro 4.1.15-2.0.1 \n \l

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

Насколько я понимаю, производитель процессора это NXP, компания нормальная, но саму плату сделали китайцы.

У меня есть два гигабайта какой-то мусорной документации, которую они выслали, но я там ничего не понял. Собственно там толком ничего и нет, самое полезное это распиновка самой платы, остальное - тупо несколько десятков даташитов по всем микросхемам, использованным на плате и какой-то «мануал» с putty.exe и ссылками на китайские форумы, откуда предлагается скачать виртуалбокс. В общем такие мануалы мне не нужны.

Я на распи собирал свой линукс через buildroot. Но там был готовый конфиг и человеческие гайды. Как действовать тут - я пока в затруднении.

 , ,

vbr
()

Будут ли языки программирования супер высокого уровня?

В связи с последними разработками в сфере ИИ и рассуждениями о том, заменят ли программистов, интересно было бы подумать о том, насколько можно улучшить производительность.

На мой взгляд за последние лет 30 языки программирования не стали выше уровнем. Если взять тот же Haskell, который в каком-то виде в первый раз появился в 1990 году, то я бы не сказал, что Rust последней версии чем-то категорично его превосходит. В целом примерно одни и те же идеи тусуют в разных пропорциях. Я тут говорю исключительно про то, насколько язык помогает программисту писать код.

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

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

Или же программирование в текущем виде достигло своего апогея и никаких принципиально новых идей уже не стоит ожидать?

 ,

vbr
()

Не могу поморгать диодом из C

Хочу поморгать диодом без библиотек. В целом сетап описан тут. Процессор STM32F030F4P6. Диод подключен, насколько я могу судить, к ноге PA4.

На текущий момент конфигурация такая:

Makefile:

CC = arm-none-eabi-gcc
AS = arm-none-eabi-as
LD = arm-none-eabi-ld
CFLAGS = -mthumb -mcpu=cortex-m0 -O0

.PHONY: all flash

all: app.bin

crt.o: crt.s

app.elf: linker.ld crt.o blink.o
	$(LD) -T linker.ld -o app.elf crt.o blink.o

app.bin: app.elf
	arm-none-eabi-objcopy -O binary $< $@

flash: app.bin
	st-flash --reset write $< 0x8000000

crt.s:

.cpu cortex-m3
.thumb

.word 0x20005000
.word _reset
.thumb_func
_reset:
  bl blink
  b .

linker.ld:

MEMORY {
  FLASH(rx): ORIGIN = 0x08000000, LENGTH = 16K
  RAM (xrw): ORIGIN = 0x20000000, LENGTH = 4K
}

blink.c:

#include <stdint.h>

const uint32_t RCC_BASE = 0x40021000;
const uint32_t GPIOA_BASE = 0x48000000;
const uint32_t RCC_AHBENR_OFFSET = 0x14;
const uint8_t RCC_AHBENR_IOPAEN_BIT = 17;
const uint32_t GPIOx_MODER_OFFSET = 0x00;
const uint8_t GPIOx_MODER_MODE4_BIT_OFFSET = 8;
const uint32_t GPIOx_ODR_OFFSET = 0x14;
const uint8_t GPIOx_ODR_OD4_BIT = 4;

void bit_clear(uint32_t address, uint8_t bit);
void bit_set(uint32_t address, uint8_t bit);
void bit_toggle(uint32_t address, uint8_t bit);

void blink(void) {
  bit_set(RCC_BASE + RCC_AHBENR_OFFSET, RCC_AHBENR_IOPAEN_BIT);
  bit_set(GPIOA_BASE + GPIOx_MODER_OFFSET, GPIOx_MODER_MODE4_BIT_OFFSET);
  bit_set(GPIOA_BASE + GPIOx_ODR_OFFSET, GPIOx_ODR_OD4_BIT);
  volatile uint32_t counter = 0;
  while (1) {
    if (counter % 0x10000 == 0) {
      bit_toggle(GPIOA_BASE + GPIOx_ODR_OFFSET, GPIOx_ODR_OD4_BIT);
    }
    counter++;
  }
}

void bit_clear(uint32_t address, uint8_t bit) {
  uint32_t mask = 1 << bit;
  volatile uint32_t *ptr = (uint32_t *) address;
  *ptr &= ~mask;
}

void bit_set(uint32_t address, uint8_t bit) {
  uint32_t mask = 1 << bit;
  volatile uint32_t *ptr = (uint32_t *) address;
  *ptr |= mask;
}

void bit_toggle(uint32_t address, uint8_t bit) {
  uint32_t mask = 1 << bit;
  volatile uint32_t *ptr = (uint32_t *) address;
  *ptr ^= mask;
}

Адреса брал из RM0360:

2.2.2 Memory map and register boundary addresses

AHB2 0x4800 0000 - 0x4800 03FF GPIOA
AHB1 0x4002 1000 - 0x4002 13FF RCC

7.4.6
Reset and clock control (RCC)
AHB peripheral clock enable register (RCC_AHBENR)
Address offset: 0x14
Bit 17: IOPAEN: I/O port A clock enable

8.4.1
GPIO port mode register (GPIOx_MODER)
Address offset:0x00
Bits 9:8 Port configuration bits
01: General purpose output mode

8.4.6
GPIO port output data register (GPIOx_ODR)
Address offset: 0x14
Bit 4: Port output databit

Насколько я понял из чтения документации:

  1. Нужно настроить регистр RCC_AHBENR и включить I/O port A.
  2. Нужно настроить регистр GPIOx_MODER и включить output mode для PA4.
  3. Для включения/выключения диода нужно менять бит GPIOx_ODR.

Возможно код на C неправильный, я его знаю плохо, пытался писать максимально просто.

На CubeMX пример с HAL копипастил, он работает, диод моргает. Ниже приведу на всякий случай:

/* USER CODE BEGIN Header */
/**
  ******************************************************************************
  * @file           : main.c
  * @brief          : Main program body
  ******************************************************************************
  * @attention
  *
  * Copyright (c) 2023 STMicroelectronics.
  * All rights reserved.
  *
  * This software is licensed under terms that can be found in the LICENSE file
  * in the root directory of this software component.
  * If no LICENSE file comes with this software, it is provided AS-IS.
  *
  ******************************************************************************
  */
/* USER CODE END Header */
/* Includes ------------------------------------------------------------------*/
#include "main.h"

/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */

/* USER CODE END Includes */

/* Private typedef -----------------------------------------------------------*/
/* USER CODE BEGIN PTD */

/* USER CODE END PTD */

/* Private define ------------------------------------------------------------*/
/* USER CODE BEGIN PD */
/* USER CODE END PD */

/* Private macro -------------------------------------------------------------*/
/* USER CODE BEGIN PM */

/* USER CODE END PM */

/* Private variables ---------------------------------------------------------*/

/* USER CODE BEGIN PV */

/* USER CODE END PV */

/* Private function prototypes -----------------------------------------------*/
void SystemClock_Config(void);
static void MX_GPIO_Init(void);
/* USER CODE BEGIN PFP */

/* USER CODE END PFP */

/* Private user code ---------------------------------------------------------*/
/* USER CODE BEGIN 0 */

/* USER CODE END 0 */

/**
  * @brief  The application entry point.
  * @retval int
  */
int main(void)
{
  /* USER CODE BEGIN 1 */

  /* USER CODE END 1 */

  /* MCU Configuration--------------------------------------------------------*/

  /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
  HAL_Init();

  /* USER CODE BEGIN Init */

  /* USER CODE END Init */

  /* Configure the system clock */
  SystemClock_Config();

  /* USER CODE BEGIN SysInit */

  /* USER CODE END SysInit */

  /* Initialize all configured peripherals */
  MX_GPIO_Init();
  /* USER CODE BEGIN 2 */

  /* USER CODE END 2 */

  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  while (1)
  {
    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */
	HAL_GPIO_TogglePin(GPIOA, GPIO_PIN_4);
	HAL_Delay(100);
  }
  /* USER CODE END 3 */
}

/**
  * @brief System Clock Configuration
  * @retval None
  */
void SystemClock_Config(void)
{
  RCC_OscInitTypeDef RCC_OscInitStruct = {0};
  RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};

  /** Initializes the RCC Oscillators according to the specified parameters
  * in the RCC_OscInitTypeDef structure.
  */
  RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI;
  RCC_OscInitStruct.HSIState = RCC_HSI_ON;
  RCC_OscInitStruct.HSICalibrationValue = RCC_HSICALIBRATION_DEFAULT;
  RCC_OscInitStruct.PLL.PLLState = RCC_PLL_NONE;
  if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
  {
    Error_Handler();
  }

  /** Initializes the CPU, AHB and APB buses clocks
  */
  RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
                              |RCC_CLOCKTYPE_PCLK1;
  RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_HSI;
  RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
  RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV1;

  if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_0) != HAL_OK)
  {
    Error_Handler();
  }
}

/**
  * @brief GPIO Initialization Function
  * @param None
  * @retval None
  */
static void MX_GPIO_Init(void)
{
  GPIO_InitTypeDef GPIO_InitStruct = {0};

  /* GPIO Ports Clock Enable */
  __HAL_RCC_GPIOA_CLK_ENABLE();

  /*Configure GPIO pin Output Level */
  HAL_GPIO_WritePin(GPIOA, GPIO_PIN_4, GPIO_PIN_RESET);

  /*Configure GPIO pin : PA4 */
  GPIO_InitStruct.Pin = GPIO_PIN_4;
  GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
  GPIO_InitStruct.Pull = GPIO_NOPULL;
  GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
  HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);

}

/* USER CODE BEGIN 4 */

/* USER CODE END 4 */

/**
  * @brief  This function is executed in case of error occurrence.
  * @retval None
  */
void Error_Handler(void)
{
  /* USER CODE BEGIN Error_Handler_Debug */
  /* User can add his own implementation to report the HAL error return state */
  __disable_irq();
  while (1)
  {
  }
  /* USER CODE END Error_Handler_Debug */
}

#ifdef  USE_FULL_ASSERT
/**
  * @brief  Reports the name of the source file and the source line number
  *         where the assert_param error has occurred.
  * @param  file: pointer to the source file name
  * @param  line: assert_param error line source number
  * @retval None
  */
void assert_failed(uint8_t *file, uint32_t line)
{
  /* USER CODE BEGIN 6 */
  /* User can add his own implementation to report the file name and line number,
     ex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */
  /* USER CODE END 6 */
}
#endif /* USE_FULL_ASSERT */

Но я в нём ничего не понимаю, хотелось бы попроще.

 , ,

vbr
()

Правильно ли я подключил МК?

Хочу поэкспериментировать с МК. Для этого собрал следующую конструкцию:

Плата Baite STM32F030F4

Модуль зарядки TP4056

Далее у меня есть плата Nucleo L073RZ мануал (стр. 16). Я от этой платы отрезал верхний кусок по линии разреза, как я понимаю, там находится программатор. У этого программатора я вытащил два джампера CN2 чтобы переключить его на работу с внешним МК.

Подключил я это всё следующим образом:

1 провод от модуля зарядки TP4056 с пометкой «OUT +» к плате Baite, пину «header 1 pin 5 VIN»

1 провод от модуля зарядки TP4056 с пометкой «OUT -» к плате Baite, пину «header 1 pin 6 GND»

4 провода от Nucleo L073RZ коннектор CN4 пины VDD_TARGET, SWCLK, GND, SWDIO к Baite пинам SWD header pins 3V3, SWCLK, GND, SWDIO

2 провода от Nucleo L073RZ пины TX RX к Baite пинам Serial header pins RX TX

Вообще вчера я подключал всё почти так же, только питание у модуля зарядки брал похоже не с тех разъёмов. В итоге на Baite шло нефильтрованное питание из USB (примерно 4.5В показывал мультиметр). В целом всё заработало, программу я смог залить, но периодически программатор показывал, что соединения с контролером нет.

Сегодня я питание подключил как выше написал, теперь там 4.2В, как я понимаю, более стабильное. Также запитал USB-порт отдельным блоком питания. Пока вроде не отваливается. Вообще допускаю, что я плохо что-то припаял, т.к. паять я не умею, модуль питания и контролер шли без гребёнок, я эту гребёнку к ним припаял и соединил всё на проводках с квадратными разъёмами.

Вопрос 1 - вообще всё правильно?

Вопрос 2 - для чего нужен пин VDD_TARGET? Я сначала подумал, что от него можно запитать контролер, но потом почитав понял, что он питание не даёт а наоборот проверяет.

Вопрос 3 - для чего я подключил TX/RX? Я сам не знаю. Как-то через ST Link можно получить к нему доступ?

Вопрос 4. Можно ли куда-то подключить пин с программатора NRST? Я так понимаю, это удобная штука для перезагрузки контролера, но куда его подключить я не нашёл. Или он не нужен?

 

vbr
()

Контроль своего домена

Предположим, мне не нравится, что гугл в любой момент может забанить мой username@gmail.com, на который завязана вся моя цифровая жизнь.

Ну как линуксоид я иду и покупаю домен. Настраиваю на этот домен почтовый ящик и вот уже я me@username.com, счастье.

Но есть одно «но». Чтобы купить домен, мне надо зарегистрироваться на каком-нибудь namecheap-е. И для регистрации мне нужна… Правильно, почта.

Если я потеряю доступ к своей исходной почте, любая проблема с аккаунтом и доступ к домену я теряю.

Что же делать?

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

Альтернативно: можно после покупки домена и настройки почтового сервера у регистратора сменить почту. Рекурсивненько получается. Но опять же это рецепт для проблем. Забыл домен оплатить вовремя, побежал его продлевать - а зайти не можешь и почта не ходит уже.

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

 

vbr
()

Постгрес в контейнере и ограничение по памяти?

Имеется постгрес в контейнере в кубе. За несколько дней у него растёт потребление по памяти постепенно. Пока не дорастает до лимита, процесс-коннект не прибивает ООМ-ом и всё заново не происходит. Кажется, что это не совсем хорошо. Хочется навести порядок. Начинал с 60M, уже 300M ему выделил, он сегодня до 200 дорос, как чайный гриб, растёт и всё, при том, что он и на 60M работал - ему 200M явно не надо.

Причём судя по тому, что, скажем, он 3 дня работает нормально, это явно не какие-то там пики и тд, просто память утекает в какие-то кеши или хз куда.

В идеале хочется задать постгресу Xmx60m как жаве и он за пределы этих 60m не вылазил и сам рассчитал там размеры для своих кешей и прочего. А не ронял процессы по ООМ.

Как тут правильно поступить?

 , ,

vbr
()

Как грамотно запустить контейнер, чтобы работал Ctrl+C

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

Первое, что пробовал это ENTRYPOINT ["sleep", "infinity"]. Не сработало. sleep игнорирует сигналы. Всякие вариации вроде bash -c "sleep infinity" или bash -c "exec sleep infinity" тоже не работают.

Лучшее, что придумал - ENTRYPOINT ["sh", "-c", "while sleep 1; do true; done"]. Но немного некрасиво - секунду всё равно ждать и крутится там туда-сюда, запускает sleep всё время. И кажись для SIGSTOP не работает, только для SIGINT.

Какой самый классный и короткой способ сделать так, чтобы и по сигналу (SIGINT и SIGSTOP) завершало выполнение, и чтобы в рамках sh работало, и выглядело не монструозно. Через всякие trap-ы и kill-ы и я смогу, но там строк на 10 будет в лучшем случае.

 , , ,

vbr
()

А вы пытаетесь соблюдать FHS в контейнерах?

Почему-то коробит, когда делают контейнеры с /data, /app и прочим бредом. Всегда делаю контейнеры с /home/build, /opt/app, /srv/data, /mnt/host и тд, пытаясь хоть как-то в FHS. Для меня создавать рандомный каталог в корне это какое-то кощунство. Вполне могу себе представить, что с таким подходом кто-нибудь смонтирует что-нибудь в /dev, типа среда разработки.

А вы как думаете? Есть в этом смысл?

 

vbr
()

Помогите улучшить хук usePromise

Пытаюсь подружить реакт с промисами. React Query и прочую муть не предлагать.

Пока родился такой вариант. Думаю, из сигнатур очевидно, как оно должно работать. Не нравится то, что reducer получился «не чистый». Вызывает abortController.abort(). Хотя и идемпотентный но кажется это всё равно не по феншую.

Как сделать нормально - я не придумал. Хотя думал много и это далеко не первая итерация. Буду благодарен помощи от гуру, если у кого будет хорошая идея.

import { DependencyList, useEffect, useReducer } from "react";

type PromiseFunction<T> = (signal: AbortSignal) => Promise<T>;

type Result<T> =
  | { status: "pending" }
  | { status: "fulfilled"; value: T }
  | { status: "rejected"; reason: unknown };

type State<T> =
  | { status: "uninitialized" }
  | { status: "pending"; id: number; abortController: AbortController }
  | { status: "fulfilled"; value: T }
  | { status: "rejected"; reason: unknown };

type Action<T> =
  | { type: "init"; id: number; abortController: AbortController }
  | { type: "resolve"; id: number; value: T }
  | { type: "reject"; id: number; reason: unknown }
  | { type: "clean" };

function reducer<T>(state: State<T>, action: Action<T>): State<T> {
  switch (action.type) {
    case "init":
      switch (state.status) {
        case "uninitialized":
          return {
            status: "pending",
            id: action.id,
            abortController: action.abortController,
          };
      }
      break;

    case "resolve":
      switch (state.status) {
        case "uninitialized":
          return state;
        case "pending":
          if (action.id < state.id) {
            return state;
          }
          if (action.id == state.id) {
            return { status: "fulfilled", value: action.value };
          }
          break;
      }
      break;

    case "reject":
      switch (state.status) {
        case "uninitialized":
          return state;
        case "pending":
          if (action.id < state.id) {
            return state;
          }
          if (action.id == state.id) {
            return { status: "rejected", reason: action.reason };
          }
          break;
      }
      break;

    case "clean":
      switch (state.status) {
        case "pending":
          state.abortController.abort();
          return { status: "uninitialized" };
        case "fulfilled":
        case "rejected":
          return { status: "uninitialized" };
      }
      break;
  }

  console.error("Unexpected state", state, action);
  return state;
}

function loggingReducer<S, A>(
  reducer: (state: S, action: A) => S,
): (state: S, action: A) => S {
  return (state, action) => {
    try {
      const nextState = reducer(state, action);
      console.log(state, action, nextState);
      return nextState;
    } catch (e) {
      console.log(state, action, e);
      throw e;
    }
  };
}

let nextId = 1;

export default function usePromise<T>(
  promiseFunction: PromiseFunction<T>,
  deps: DependencyList,
): Result<T> {
  const [state, dispatch] = useReducer(loggingReducer(reducer<T>), {
    status: "uninitialized",
  });

  useEffect(() => {
    const id = nextId++;
    const abortController = new AbortController();

    dispatch({ type: "init", id, abortController });

    promiseFunction(abortController.signal).then(
      (value) => dispatch({ type: "resolve", id, value }),
      (reason) => dispatch({ type: "reject", id, reason }),
    );

    return () => dispatch({ type: "clean" });
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, deps);

  switch (state.status) {
    case "uninitialized":
    case "pending":
      return { status: "pending" };

    case "fulfilled":
      return { status: "fulfilled", value: state.value };

    case "rejected":
      return { status: "rejected", reason: state.reason };
  }
}

 

vbr
()

RSS подписка на новые темы