Чтение онлайн

ЖАНРЫ

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

Кёртен Роб

Шрифт:

// Вместо этого

// 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 единственным возвращаемым значением было число записанных байт.)

Пример функции io_devctl, имеющей дело с данными

В предыдущем примере io_devctl мы подняли вопрос о том, как устанавливать произвольные значения частоты дискретизации, Очевидно, создание большого количества констант DCMD_AUDIO_SET_SAMPLE_RATE_* было бы не самым оптимальным решением — у нас бы просто не хватило разрядности поля dcmd.

С клиентской стороны мы будем использовать указатель на частоту дискретизации, dev_data_ptr, которую мы просто передадим как целое, поэтому поле nbytes будет содержать число байт в целом числе (для 32-разрядных машин это 4). Будем предполагать, что для этих целей определена константа DCMD_AUDIO_SET_SAMPLE_RATE.

Также неплохо было бы уметь считывать текущее значение частоты дискретизации. Для этого мы также будем использовать переменные dev_data_ptr и nbytes, как описано выше, но в обратном направлении — администратор ресурсов запишет nbytes данных в ячейку памяти, на которую указывает dev_data_ptr, вместо чтения данных из этой ячейки. Предположим, что для этого определена константа DCMD_AUDIO_GET_SAMPLE_RATE.

Давайте посмотрим, что в таком случае происходит в функции io_devctl администратора ресурсов (того, что обсуждалось в предыдущем примере, мы здесь касаться не будем):

/*

 * io_devctl2.с

*/

#include <stdio.h>

#include <stdlib.h>

#include <unistd.h>

#include <errno.h>

#include <devctl.h>

#include <sys/neutrino.h>

#include <sys/iofunc.h>

#define DCMD_AUDIO_SET_SAMPLE_RATE 1

#define DCMD_AUDIO_GET_SAMPLE_RATE 2

int io_devctl(resmgr_context_t *ctp, io_devctl_t *msg,

 iofunc_ocb_t *ocb) {

 int sts;

 void *data;

 int nbytes;

 if ((sts =

iofunc_devctl_default(ctp, msg, ocb)) !=

_RESMGR_DEFAULT) {

return (sts);

 }

 // 1) Установить указатель на область данных сообщения

 data = _DEVCTL_DATA(msg);

 // 2)
Установить число возвращаемых байт в 0

 nbytes = 0;

 // Проверить все команды; покажем только те, которые нам

 // здесь интересны

 switch (msg->i.dcmd) {

...

 // 3) Обработать команду SET

 case DCMD_AUDIO_SET_SAMPLE_RATE:

audio_set_samplerate(*(int*)data);

break;

 // 4) Обработать команду GET

 case DCMD_AUDIO_GET_SAMPLE_RATE:

*(int*)data = audio_get_samplerate;

nbytes = sizeof(int);

break;

...

 }

 // 5) Возвратить данные (если есть) клиенту

 memset(&msg->о, 0, sizeof(msg->о));

 msg->о.nbytes = nbytes;

 SETIOV(ctp->iov, &msg->o, sizeof(msg->o) + nbytes);

 return (_RESMGR_NPARTS(1));

}

Этап 1

В «шапке» мы декларировали указатель типа

void*
по имени data («данные»), которые мы будем использовать в качестве универсального указателя на область данных. Если вы обратитесь к приведенному выше описанию io_devctl, то вы увидите, что структура данных состоит из объединения заголовков входной и выходной структур, за которым неявно следует область данных. На этапе 1 указатель на эту область данных возвращается макросом _DEVCTL_DATA.

Этап 2

Здесь мы должны указать, сколько байт мы собираемся возвратить клиенту. Я для удобства обнулил переменную nbytes перед выполнением каких-либо действий — теперь мне не придется принудительно обнулять ее в каждой ветви

switch
/
case
.

Этап 3

Пришло время для команды «set» («установить»). Мы вызываем фиктивную функцию audio_set_samplerate и передаем ей значение частоты дискретизации, полученное разыменованием указателя data (который мы коварно выставили указателем на целое число... нет, никакого коварства, обычный для Си прием приведения типов). Это ключевой механизм, потому что это и есть наш способ «интерпретации» области данных (клиентского указателя dev_data_ptr) в соответствии с командой. В более сложном случае вы, наверное, выполнили бы приведение его типа к какой-нибудь структуре побольше вместо простого целого числа. Очевидно, что описания этой структуры на стороне как клиента, так и администратора ресурсов, должны быть идентичными, поэтому лучшим местом для описания такой структуры является заголовочный файл, в котором хранятся ваши командные константы DCMD_*

Этап 4

Обработка команды «get» («получить») на этапе 4 во многом аналогична (по части приведения типов), кроме того, что на этот раз мы записываем данные в структуру вместо считывания из нее. Заметьте, что мы также присваиваем переменной nbytes число байт, которые мы хотим возвратить клиенту. В случае более сложного доступа к данным вы должны были бы возвратить размер области данных (т.е. если бы эта область была бы структурой, вам нужно было бы возвратить ее размер).

Поделиться с друзьями: