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

96 lines
5.6 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

---
title: "📟 FAQ по доступу к Serial из Crystal"
date: 2023-05-16T01:29:30+03:00
draft: false
tags: [crystal, serial, tips]
---
Перевёл FAQ чувака с SOF, на вопрос работы с Serial в Crystal.
## Как мне получить доступ к Serial в Linux/BSD?
Открыть его как файл.
В Linux/BSD последовательное соединение устанавливается в тот момент,
когда устройство было подключено,
и затем отображается в разделе `/dev/` (обычно как `/dev/ttyUSB0`).
Чтобы получить доступ к этому соединению, просто откройте его как обычный файл.
Иногда этого достаточно, чтобы начать взаимодействовать с устройством,
поскольку современное оборудование работает со всеми скоростями и флагами по умолчанию.
## Как мне настроить устройство Serial/tty в Linux/BSD?
Необходимо установить флаги [termios](https://linux.die.net/man/3/termios) для файла.
Если необходимо для соединения установить такие параметры,
как скорость передачи данных в бодах, IXON/IXOFF и т.д.,
это можно сделать еще до запуска вашей программы с помощью команды
[stty](https://linux.die.net/man/1/stty), если она доступна.
Например чтобы установить скорость передачи данных в бодах,
необходимо выполнить следующую команду: `stty -F /dev/ttyUSB0 9600`.
И после того, как соединение настроено,
можно просто открыть соединение как файл и начать использовать.
Вы можете запустить `stty` из Crystal с помощью
`Process.run`, если нужен простой способ настройки устройства из вашего приложения.
Я бы, вероятно, порекомендовал этот способо в качестве решения.
## Как мне установить флаги termios из Crystal, не используя stty?
Используйте функции `termios` напрямую.
Crystal предоставляет FileDescriptor с несколькими
распространенными настройками `termios`, такими как
[cooked](https://crystal-lang.org/api/1.8.2/IO/FileDescriptor.html#cooked%28%26%3Aself-%3E_%29-instance-method),
что означает, наличие минимальных привязок
[termios](https://github.com/crystal-lang/crystal/blob/master/src/termios.cr).
Мы можем начать с использования существующего кода:
```crystal
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 готов к использованию.
```
Чтобы установить другие флаги, обратитесь
к [руководству](https://linux.die.net/man/3/termios) termios
или к этому замечательному
[руководству](https://en.wikibooks.org/wiki/Serial_Programming/termios) по Serial,
которое я только что нашел.
## Есть ли библиотека, которая могла бы сделать все это за меня?
Нет :(. Но было бы здорово, если бы кто-нибудь написал.
Вероятно, что написать библиотеку не составит большого труда,
если у кого-нибудь будет личный интерес :)
## Источник
- [Crystal-lang Accessing Serial port](https://stackoverflow.com/questions/51069578/crystal-lang-accessing-serial-port) — StackOverFlow.