Blog/content/posts/2023/crystal/accessing-serial-port.md
2023-05-16 01:30:20 +03:00

5.6 KiB
Raw Permalink Blame History

title date draft tags
📟 FAQ по доступу к Serial из Crystal 2023-05-16T01:29:30+03:00 false
crystal
serial
tips

Перевёл FAQ чувака с SOF, на вопрос работы с Serial в Crystal.

Как мне получить доступ к Serial в Linux/BSD?

Открыть его как файл. В Linux/BSD последовательное соединение устанавливается в тот момент, когда устройство было подключено, и затем отображается в разделе /dev/ (обычно как /dev/ttyUSB0). Чтобы получить доступ к этому соединению, просто откройте его как обычный файл. Иногда этого достаточно, чтобы начать взаимодействовать с устройством, поскольку современное оборудование работает со всеми скоростями и флагами по умолчанию.

Как мне настроить устройство Serial/tty в Linux/BSD?

Необходимо установить флаги termios для файла. Если необходимо для соединения установить такие параметры, как скорость передачи данных в бодах, IXON/IXOFF и т.д., это можно сделать еще до запуска вашей программы с помощью команды stty, если она доступна. Например чтобы установить скорость передачи данных в бодах, необходимо выполнить следующую команду: stty -F /dev/ttyUSB0 9600. И после того, как соединение настроено, можно просто открыть соединение как файл и начать использовать.

Вы можете запустить stty из Crystal с помощью Process.run, если нужен простой способ настройки устройства из вашего приложения. Я бы, вероятно, порекомендовал этот способо в качестве решения.

Как мне установить флаги termios из Crystal, не используя stty?

Используйте функции termios напрямую. Crystal предоставляет FileDescriptor с несколькими распространенными настройками termios, такими как cooked, что означает, наличие минимальных привязок termios.

Мы можем начать с использования существующего кода:

require "termios"

# Открываем файл
serial_file = File.open("/dev/ttyACM0")
raise "Oh no, not a TTY" unless serial_file.tty?

# Извлекаем unix FD. Это всего лишь цифра.
fd = serial_file.fd

# Извлекаем существующие флаги TTY файла
raise "Can't access TTY?" unless LibC.tcgetattr(fd, out mode) == 0

# `mode` теперь содержит структуру termios. Давайте включим, ммм.. ISTRIP and IXON
mode.c_iflag |= (Termios::InputMode::ISTRIP | Termios::InputMode::IXON).value
# Давайте также отключим IXOFF.
mode.c_iflag &= ~Termios::InputMode::IXOFF.value

# Обнаружение неисправности: в Termios недоступна скорость cfset[ввода-вывода]
# Давайте добавим их, чтобы изменить скорость передачи данных в бодах было не так сложно.
lib LibC
  fun cfsetispeed(termios_p : Termios*, speed : SpeedT) : Int
  fun cfsetospeed(termios_p : Termios*, speed : SpeedT) : Int
end

# Используйте приведенные выше функции, чтобы установить скорость ввода
# и скорость вывода на заданную вами скорость передачи данных в бодах.
LibC.cfsetispeed(pointerof(mode), Termios::BaudRate::B9600)
LibC.cfsetospeed(pointerof(mode), Termios::BaudRate::B9600)
# Пишите свои изменения в FDA.
LibC.tcsetattr(fd, Termios::LineControl::TCSANOW, pointerof(mode))

# Сделано! Ваш дескриптор serial_file готов к использованию.

Чтобы установить другие флаги, обратитесь к руководству termios или к этому замечательному руководству по Serial, которое я только что нашел.

Есть ли библиотека, которая могла бы сделать все это за меня?

Нет :(. Но было бы здорово, если бы кто-нибудь написал. Вероятно, что написать библиотеку не составит большого труда, если у кого-нибудь будет личный интерес :)

Источник