Книга: Введение в QNX/Neutrino 2. Руководство по программированию приложений реального времени в QNX Realtime Platform

Простой пример функции io_devctl()

Простой пример функции io_devctl()

Клиентский вызов devctl() формально определен так:

#include <sys/types.h>
#include <unistd.h>
#include <devctl.h>
int devctl(int fd, int dcmd, void *dev_data_ptr,
 size_t nbytes, int *dev_info_ptr);

Прежде чем рассматривать эту функцию с позиций администратора ресурсов, надо сначала понять, что это за зверь. Функция devctl() применяется для «нестандартных» и «управляющих» операций. Например, вы можете записывать данные в звуковую плату (реальные оцифрованные звуковые фрагменты, которые звуковая плата должна будет конвертировать в аналоговый аудиосигнал) и принять решение об изменении числа каналов от одного (моно) до двух (стерео) или об изменении частоты дискретизации данных от стандарта CD (44.1 кГц) к стандарту DAT (48 кГц). Такие вещи было бы правильно делать при помощи функции devctl(). При написании администратора ресурсов вы можете решить, что вам вообще не нужны никакие devctl(), и что всю необходимую функциональность можно свести к стандартным функциям read() и write(). С другой стороны, вы можете захотеть использовать как вызовы devctl() наряду с вызовами read() и write(), так и только devctl() — это будет зависеть от вашего устройства.

Функция devctl() принимает 5 аргументов:

fd Дескриптор файла администратора ресурсов, которому вы посылаете команду devctl().
dcmd Собственно команда — комбинация из двух разрядов направления обмена данными и 30 разрядов команды (см. ниже).
dev_data_ptr Указатель на область данных, которые передаются, принимаются или и то, и другое.
nbytes Размер области данных, на которую указывает dev_data_ptr.
dev_info_ptr Переменная для дополнительной информации, установку которой может выполнить администратор ресурса.

Двумя старшими разрядами команды dcmd кодируется направление обмена данными, если он вообще имеет место. Подробности см. выше в описании функций ввода/вывода (параграф «io_devctl()»).

Когда администратор ресурсов принимает сообщение _IO_DEVCTL, оно обрабатывается вашей функцией io_devctl(). Ниже представлен очень простой пример, который предполагается использовать для настройки каналов и частоты дискретизации для аудиоустройства, как упоминалось выше.

/*
 * io_devctl1.c
*/
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <sys/neutrino.h>
#include <sys/iofunc.h>
#define DCMD_AUDIO_SET_CHANNEL_MONO    1
#define DCMD_AUDIO_SET_CHANNEL_STEREO  2
#define DCMD_AUDIO_SET_SAMPLE_RATE_CD  3
#define DCMD_AUDIO_SET_SAMPLE_RATE_DAT 4
int io_devctl(resmgr_context_t *ctp, io_devctl_t *msg,
 iofunc_ocb_t *ocb) {
 int sts;
 // 1) Проверить, не является ли это обычным
 // POSIX-совместимым devctl()
 if ((sts =
  iofunc_devctl_default(ctp, msg, ocb)) !=
   _RESMGR_DEFAULT) {
  return (sts);
 }
 // 2) Узнать, что за команда, и отработать ее
 switch (msg->i.dcmd) {
 case DCMD_AUDIO_SET_CHANNEL_MONO:
  audio_set_nchannels(1);
  break;
 case DCMD_AUDIO_SET_CHANNEL_STEREO:
  audio_set_nchannels(2);
  break;
 case DCMD_AUDIO_SET_SAMPLE_RATE_CD:
  audio_set_samplerate(44100);
  break;
 case DCMD_AUDIO_SET_SAMPLE_RATE_DAT:
  audio_set_samplerate(48000);
  break;
 // 3) Если мы не знаем такой команды, отвергнуть ее
 default:
  return (ENOSYS);
 }
 // 4) Сказать клиенту, что все отработано
 memset(imsg->о, 0, sizeof(msg->о));
 SETIOV(ctp->iov, &msg->o, sizeof(msg->o));
 return (_RESMGR_NPARTS(1));
}

Этап 1

На первом этапе мы снова видим применение вспомогательной функции, на этот раз — функции iofunc_devctl_default(), которая используется для выполнения всей обработки по умолчанию для devctl(). Если вы не поставляете свою версию io_devctl(), а только инициализируете таблицы функций ввода/вывода и установления соединения при помощи iofunc_func_init(), будет вызвана именно iofunc_devctl_default(). Мы включаем ее в нашу версию io_devctl(), потому что мы хотим, чтобы она обработала для нас все стандартные POSIX-варианты вызова devctl(). Затем мы проверяем возвращаемое значение; если это не _RESMGR_DEFAULT, значит, функция iofunc_devctl_default() «обработала» запрос, и нам остается только возвратить это значение, выдав его за «наше».

Если возвращенное значение является константой _RESMGR_DEFAULT, это говорит нам, что вспомогательная функция не обработала запрос, и что мы должны выяснить, является ли он одним из «наших».

Этап 2

Эта проверка выполняется на этапе 2 при помощи инструкции switch/case. Мы просто проверяем значение dcmd, которое клиентский код указал во втором параметре функции devctl(), на предмет совпадения с какой-нибудь из «наших» команд. Обратите внимание, что для выполнения фактической «работы» для клиента мы вызываем фиктивные функции audio_set_nchannels() и audio_set_samplerate(). Здесь важно отметить, что мы преднамеренно избегаем обсуждения области данных функции devctl(). Вы можете подумать: «А что если я хочу установить частоту дискретизации в некое значение n? Как это сделать?» На этот вопрос мы ответим в следующем примере io_devctl(), который представлен ниже.

Этап 3

Этот этап — дань концепции защитного программирования. Мы возвращаем код ошибки ENOSYS, чтобы сообщить клиенту, что мы не распознали его запрос.

Этап 4

Наконец, мы обнуляем возвратную структуру и устанавливаем на нее одноэлементный вектор ввода/вывода. Затем мы возвращаем библиотеке администратора ресурсов единицу (1) через макрос _RESMGR_NPARTS(), сообщая ей тем самым, что мы возвращаем одноэлементный вектор ввода/вывода. Это и будет возвращено клиенту. Как вариант, мы могли бы применить макрос _RESMGR_PTR():

// Вместо этого
// 4) Сказать клиенту, что это сработало
memset(imsg->о, 0, sizeof(msg->о));
SETIOV(&ctp->iov, &msg->о, sizeof(msg->o));
return (_RESMGR_NPARTS(1));
//Мы могли бы сделать так:
// 4) Сказать клиенту, что это сработало
memset(imsg->о, 0, sizeof(msg->о));
return (_RESMGR_PTR(ctp, imsg->o, sizeof(msg->o)));

Причиной тому, что мы здесь обнулили возвращаемую структуру (вспомните, в примерах io_read() и io_write() мы этого не делали) является то, что в данном случае возвращаемая структура имеет реальное содержимое! (В случае с io_read() мы возвращали только собственно данные и число считанных байт — никакой «возвращаемой структуры» не было; в случае же с io_write() единственным возвращаемым значением было число записанных байт.)

Оглавление книги


Генерация: 1.817. Запросов К БД/Cache: 3 / 1
поделиться
Вверх Вниз