Промежуточное программное обеспечение с общим коммуникационным медиа-слоем - PullRequest
1 голос
/ 16 апреля 2010

Привет всем,

Я пытаюсь реализовать промежуточное программное обеспечение (драйвер) для встроенного устройства с общим коммуникационным медиа-уровнем. Не уверен, что это лучший способ сделать это, поэтому я обращаюсь за советом к более опытным пользователям stackoverflow :). В основном у нас есть устройства по всей стране, которые общаются с нашими серверами (или кпк / ноутбук используется в полевых условиях). Обычная форма связи по TCP / IP, но может также использовать usb, RF-адаптер, IR и т. Д. Планируется, что объект будет соответствовать каждому из этих устройств, обрабатывать собственный протокол с одной стороны и запрашивать / отвечать с другой внутренние системы на другом.

Дело в том, как создать нечто общее между средой и объектами обработки. Я поэкспериментировал с диспетчером TCP, использующим boost.asio, но попытка создать что-то общее кажется кошмаром :). Кто-нибудь пытался сделать что-то подобное? Как лучше всего это сделать?

Пример: устройство подключается к нашему серверу Linux. Создается новый экземпляр промежуточного программного обеспечения (на сервере), который сообщает о себе одной из запущенных служб (подробности не важны). Служба отвечает за синхронизацию времени устройства. Таким образом, он спрашивает промежуточное программное обеспечение, сколько времени у устройства, драйвер переводит его на язык устройства (протокол) и отправляет сообщение, ответы устройства, а драйвер снова переводит его для службы. Это может показаться излишним для такого простого запроса, но представьте, что есть более сложные запросы, которые драйвер должен перевести, также есть несколько версий устройства, которые используют другой протокол и т. Д., Но будут использовать одну и ту же службу синхронизации времени. Цель состоит в том, чтобы абстрагировать устройства через промежуточное ПО, чтобы иметь возможность использовать один и тот же сервис для связи с ними.

Другой пример: мы обнаруживаем, что удаленная связь с устройством отключена. Итак, мы отправляем кого-то с КПК, он подключается к устройству с помощью USB-кабеля. Запускает приложение, которое имеет те же функции, что и служба Timesync. Снова создается экземпляр промежуточного программного обеспечения (на КПК) для преобразования связи между приложением и устройством, на этот раз только с использованием USB / последовательного носителя, а не TCP / IP, как в предыдущем примере. Надеюсь, теперь это имеет смысл:)

Cheers, Том

Ответы [ 2 ]

1 голос
/ 16 апреля 2010

Дело в том, как создать нечто общее между средой и объектами обработки. Я поэкспериментировал с диспетчером TCP, использующим boost.asio, но попытка создать что-то общее кажется кошмаром :). Кто-нибудь пытался сделать что-то подобное? Как лучше всего это сделать?

Я не использовал Boost, но я обычно решал проблему такого рода, создавая базовый класс Device, с которым взаимодействует сервер, а затем делил его на подклассы для каждого типа устройства и заставлял подклассы работать с устройством. нечетность. Таким образом, класс Device становится определением вашего протокола. Кроме того, класс Device должен быть переносимым, а подклассы - нет.

Если вам нужно было стать более изощренным, вы можете использовать шаблон Factory для создания реальных подклассов объектов.

Что касается реального общения, я бы посмотрел, смогу ли я просто запустить один процесс на устройство. Если вам нужно иметь более одного Устройства на процесс, в Linux я бы просто использовал select() и его друзей для управления вводом / выводом между различными экземплярами Устройства. Я не знаю, как это сделать в Windows; select работает только для сокетов, а не для последовательных портов или других файловых вещей.

Другие вещи, которые приходят на ум, могут оказаться полезными, в том числе dbus и библиотека MPI (Message Passing Interface), хотя они не являются полными решениями вашей проблемы (dbus не осуществляет межкомпьютерные коммуникации, IIRC).

Помогает ли это вообще?

РЕДАКТИРОВАТЬ: Требуется отформатированный ответ на ответ Тома ...

Содержит ли ваш класс устройств специфичные для связи части? Потому что это то, чего я хотел избежать.

Подклассы содержат специфичные для связи части. Вот и весь смысл использования здесь подклассов; универсальный материал входит в базовый класс, а специфика - в подкласс.

Я думал о чем-то вроде этого: скажем, есть диспетчер, специфичный для используемого носителя, который создает объект Connection для каждого соединения (специфичный для носителя), Device obj. будет также создан, но только общий, и Соединение будет передавать входящие данные на Устройство, и Устройство будет передавать ответы обратно Соединению.

Я думаю, что это может быть немного сложно, и вы ожидаете, что универсальное устройство будет иметь дело с определенным соединением, которое может быть сложно поддерживать быстро.

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

Пример: скажем, у вас есть датчик температуры USB штуковина. У вас есть диспетчер, который ловит сигнал «USB вещь подключена». Когда он видит, что USB-устройство подключено:

  • Диспетчер создает USBTemperatureThingConnection.
  • Диспетчер создает USBTemperatureDevice, который является подклассом устройства, давая USBTemperatureThingConnection USBTemperatureDevice в качестве параметра конструктора.
  • USBTemperatureDevice::USBTemperatureDevice(USBTemperatureThingConnection* conn) идет и устанавливает все, что ему нужно локально, чтобы завершить настройку Соединения, затем отправляет сообщение Диспетчеру устройств, сообщающее, что оно настроило себя.

Некоторое время спустя диспетчер устройств хочет установить время на всех устройствах. Таким образом, он перебирает свой список устройств и вызывает общий (возможно, даже абстрактный) метод Device::SetTime(const struct timespec_t&) для каждого из них.

Когда он достигает вашего температурного устройства, он вызывает USBTemperatureDevice::SetTime(const struct timespec_t&), так как USBTemperatureDevice переопределяет значение в Device (которое было либо абстрактным, то есть virtual void SetTime(const struct timespec_t&) = 0;, либо неактивным, то есть virtual void SetTime(const struct timespec_t&) {}, поэтому вам не нужно переопределять его для устройств, которые не могут установить время). USBTemperatureDevice::SetTime(const struct timespec_t&) делает все, что нужно для датчика температуры USB, используя USBTemperatureThingConnection, чтобы установить время.

Некоторое время спустя устройство может отправить обратно сообщение «Результат установки времени», сообщающее, работает ли оно или нет.Это приходит на USBTemperatureThingConnection, который пробуждает вашу нить, и вам нужно с этим справиться.Таким образом, ваш метод USBTemperatureDevice::DealWithMessageFromSensor() (который существует только в USBTemperatureDevice) погружается в содержимое сообщения и выясняет, работает ли установка времени или нет.Затем он принимает этот результат, превращает его в значение, определенное в enum Device::ResultCode, и вызывает Device::TimeSetComplete(ResultCode result), который записывает результат, устанавливает флаг (bool Device::timeComplete), говорящий о том, что результат находится в, а затем нажимает Semaphore или Condition, чтобы разбудить Диспетчер устройств и заставить его проверить все Device, в случае, если он был заблокирован, ожидая, пока все устройства завершат установку времени, прежде чем продолжить.

Я понятия не имею, что этокартина называется.Если бы я нажал, я бы сказал «подклассы» или «объектно-ориентированный дизайн», если бы я чувствовал раздражение.«Промежуточное программное обеспечение» - это класс Device, DeviceManager и все их подчиненные.Затем приложение просто обращается к диспетчеру устройств или, самое большее, к общему интерфейсу Device определенного устройства.

Кстати.План фабрики был запланирован, каждый объект работал бы в отдельном потоке:)

Приятно слышать.

0 голосов
/ 16 апреля 2010

Я предполагаю, что под TCP / IP вы подразумеваете удаленные узлы, а под USB и т. Д. Локальные устройства, подключенные к одному физическому блоку. Я думаю, что вам не хватает в вашем объяснении той части, которая объявляет о новых локальных устройствах для процесса сервера (то есть аналоге прослушивающего сокета). Опять же, предполагая что-то похожее на Linux uevent, я бы начал с следующая структура:

  • Контроллер: знает точное время, управляет источниками событий, реагирует на события
  • Источник события: генерирует события «новое / удаление устройства», знает его класс устройства.
    • серверный сокет
    • монитор локального устройства
    • и т.д.
  • Класс устройства: инкапсулирует специфичную для устройства логику и управляет / перечисляет устройства
    • тип удаленного устройства (подключенная розетка)
    • Тип устройства USB
    • USB-устройство версии X.Y.Z тип
    • и т.д.

Протокол высокого уровня очень прост - при получении или событии «новое устройство», запрос «Класс устройства» для времени с данного устройства, затем обновление время на Устройство. «Класс устройства» - это драйвер / переводчик / мост, который реализует преобразование интерфейса запроса / обновления в специфичные для устройства команды (сетевой обмен для удаленных узлов). Он также содержит список своих устройств.

Это должно легко отображаться на диаграмме классов. Было ли что-то еще, что я пропустил?

...