О функции Beep (02.12.2021). Печать
2021 - Декабрь
02.12.2021 17:02
Save & Share
Казалось бы, простая функция, заставляющая динамик пискнуть. Но, как всегда бывает при взаимодействии с железом, - использование данной функции может вызвать трудности. Mein kampf gegen Beep.


Звуковые оповещения используются, преимущественно, для фиксации пользователя на определенном событии. Если в операционной системе такие события, в основном, отображаются пользователю и имеют посыл вида "пошел на хрен!" - то при работе с самоконтролем аппаратуры назначение несколько иное:
- противный, громкий и раздражающий писк. Индикация этапов длительного во времени теста и его завершения - нет необходимости сидеть перед монитором (и вообще близко к аппаратуре). Комментирование некорректных действий пользователя - дрессировка пользователя на внимательность;
- тихий и приятный писк. Индикация завершения инициализации программы, ошибок самой программы, номера этапа теста при разработке.

С учетом "рекомендаций" по переходу на отечественное программное обеспечение [1, 2, 3], госпредприятиям диктуются жесткие условия их выполнения как перехода с Windows на Linux. В связи с обострением этой ситуации сейчас - не рекомендуется устраиваться программистом в государственную контору. Также на собеседовании стоит уточнять, будет ли участие в таком мероприятии. Потому что это - засада:
- переход с Windows на Linux - миграция, а миграция (даже незначительная) - геморрой (выяснилось сейчас, что даже переход с Linux на Linux - геморрой);
- в большинстве случаев такая миграция означает отказ от работоспособных программ Windows и переписывание их неизменного функционала с нуля под Linux - как мартышкин труд, переливание из пустого в порожнее;
- Linux намного более глючная ОС, чем Windows, - при этом глюки бывают полностью алогичные и непредсказуемые. Например, отладчик Qt работает некорректно на одном ПК - и корректно на другом. Одинаковая ОС, одинаковая версия Qt, нет недостатка пакетов, все 1600 пакетов одинаковых версий с точностью до ревизии. А проблема - критическая и требует решения.

В Windows функция Beep была практически прозрачна и вызывалась несколькими способами, на выбор:
- тупо из среды программирования (в большинстве случаев, даже никаких H-файлов подключать не надо);
- тупо записью в порт 0x61 значения 3 (пищит) или 1 (не пищит). Если порты закрыты - открыть их, подключив внешнюю библиотеку;
- тупо один раз в жизни создать/скачать BAT-файл с бинарным содержимым «65 63 68 6F 20 07» («echo [BEL]», где 07 – [BEL] – двойной Beep) – и вызывать функцией вида ShellExecute из любой среды программирования. Динамик работает только с числом 07 из 256 возможных вариантов. Возможно, это решение зависит от открытости порта 0x61;
- из библиотеки User32.dll, Kernel32.dll или cmdext.dll (если есть).

В Linux же заставить динамик пискнуть вызвала проблемы:
- OpenSuse v.12.1: пришлось вообще самописную функцию писать, приведенную ниже;
- Astra Linux v.2.12.43: дополнительно скачать пакет "beep". Вызов возможен только из консоли - для ПО пришлось писать другую самописную функцию (от OpenSuse не подошла): выполнения команд в терминале. Но функция выполнялась - а динамик продолжал молчать. И выяснился неочевидный момент: при каждом запуске операционной системы нужно выполнять в терминале "sudo modprobe pcspkr". Потом выяснилось, что в Linux запуск из терминала и запуск из среды программирования - не одно и то же: нельзя выполнить команды с "|", вызванный инсталлятор драйвера платы падает на 75% выполнения, часть команд отказывается работать даже под суперпользователем и т.д. Поэтому с корректным выполнением консольной команды "beep" из ПО - считай, повезло.

В функции Beep указывается, обычно, 2 параметра: высота тона и длительность звучания. Однако первый параметр назывался высотой тона, измеряемой в барках и мелах, - ошибочно: это частота в герцах (что и было обнаружено в man beep). 1800 соответствует тихому приятному писку, 2000 среднему обычному, 2500-2700 - мерзкому громкому.

Функция OpenSuse.
void vBeep_Correct(int iSignal_Code = 0, int iDelay = 83)
{
    int console_fd = -1;
    char *console_device = NULL;

    QVector<int> iFrequency_Array;

    if (iSignal_Code == 0)
    {
        //Ноты.
        iFrequency_Array.append(1046);
        iFrequency_Array.append(988);
        iFrequency_Array.append(880);
        iFrequency_Array.append(784);
        iFrequency_Array.append(698);
        iFrequency_Array.append(659);
        iFrequency_Array.append(587);
        iFrequency_Array.append(523);
    }
    else if (iSignal_Code == 2)
    {
        //Ноты.
        iFrequency_Array.append(523);
        iFrequency_Array.append(587);
        iFrequency_Array.append(659);
        iFrequency_Array.append(698);
        iFrequency_Array.append(784);
        iFrequency_Array.append(880);
        iFrequency_Array.append(988);
        iFrequency_Array.append(1046);
    }
    else
    {
        iFrequency_Array.append(523); //1 элемент.
    }

    if(console_device)
      console_fd = open(console_device, O_WRONLY);
    else
      if((console_fd = open("/dev/tty0", O_WRONLY)) == -1)
        console_fd = open("/dev/vc/0", O_WRONLY);

    for (int i=0; i<iFrequency_Array.count(); i++)
    {
        ioctl(console_fd, KIOCSOUND, 1193180/iFrequency_Array[i]);
        vDelay(iDelay*1000);
    }

    ioctl(console_fd, KIOCSOUND, 0);
    close(console_fd);
}


Функции Astra Linux потом принесу.

1. Путин В.В. Указ президента Российской Федерации (проект). О мерах экономического характера по обеспечению технологической независимости и безопасности объектов критической информационной инфраструктуры / Москва: Кремль, 2020 г.
2. Носков К.Ю. Приказ Минкомсвязи России от 20.09.2018 №486 «Об утверждении методических рекомендаций по переходу государственных компаний на преимущественное использование отечественного программного обеспечения, в том числе отечественного офисного программного обеспечения /Москва: Минкомсвязи РФ, 2021 г.
3. Кремль. Особенности государственного регулирования в сфере использования российских программ для электронных вычислительных машин и баз данных / Москва: Кремль, ФЗ от 27.07.2006 №149-ФЗ, 2022 г. - статья 12.1.

(добавлено 03.12.2021) Функции Astra Linux CE v.2.12.43.

qslProcess_Run("sudo modprobe pcspkr"); //Требуется после каждой перезагрузки для корректной работы.

void vBeep(int iGamma, int iDuration){if (g_bBeep) qslProcess_Run("sudo beep -f" + QString::number(iGamma) + " -l " + QString::number(iDuration));}

QStringList qslProcess_Run(QString qsProcess)
{
    QProcess *qProcess = new QProcess;
    QByteArray qbaResult;

    qProcess->start(qsProcess); //"|" не поддерживается.
    qProcess->waitForFinished(5000);

    qbaResult = qProcess->readAllStandardOutput();
    qProcess->terminate();

    delete qProcess; qProcess = NULL;

    QString qsResult = qbaResult;
    return qsResult.split("\n");
}

(добавлено 05.12.2021) Проблема некорректно работающего отладчика решилась алогичным способом:
- считать, что установка пакетов из интернета не равна установке тех же самых пакетов в оффлайне (хотя в обоих способах все зависимости удовлетворены полностью);
- считать, что операционная система врет, указывая одинаковость количества пакетов и их версий;
- на основании этого - эмпирически выбрать из тысяч пакетов один, "Qt5-default". Установить его на ПК, на котором пакеты устанавливались в оффлайне.

(добавлено 05.01.2023) В Astra Linux SE v.1.4 пищалка не заработала, при установленном пакете Beep. sudo modprobe pcspkr - не помогло. Нашел описание от производителя: «По умолчанию возможность вывода звуковых сигналов... ...заблокирована. ... Данное ограничение необходимо в целях исключения возможности реализации скрытого канала». То есть, тупые СБ-шники запретили разработчикам пищать динамиком в принципе, потому что боятся передачи информации азбукой Морзе! Наверно, ночью будет пищать, когда комп выключен. Или днем, ведь сотрудники глухие - и не услышат надрывающийся динамик. Да и куда динамик должен отправлять свои писки, чтобы что их собирало?
Обновлено ( 05.01.2023 20:44 )