Доброго времени суток. Использование универсальных протоколов взаимодействия устройств уже давно является неотъемлемой частью разработки любого технического продукта в нашем мире. К сожалению, сфера здравоохранения находится сейчас в роли догоняющей, и эксперты только начинают рассматривать возможности использования общих методов коммуникации в своих продуктах. Так на возникающий спрос начинают появляться открытые стандарты взаимодействия, удовлетворяющие требованиям медицинской отрасли.
![](https://habrastorage.org/getpro/habr/upload_files/80c/fc9/ff2/80cfc9ff2a38718123fc7c6b77a2c921.jpg)
В этой статье Аурига поделится опытом разработки решений, направленных на использование подходов автоматизированного тестирования медицинских устройств в соответствии с открытым стандартом IEEE 11073 Service-oriented Device Connectivity (SDC), разработанным некоммерческой организацией OR.NET.
Краткое описание работы SDC протокола
Общее описание SDC протокола хорошо рассмотрено в статье "Как общаться в проприетарном зоопарке или проблема совместимости медицинских устройств", поэтому здесь будет дана информация, которая будет необходима для понимания принципов работы SDC, а следовательно, и принципов тестирования совместимости с этим протоколом.
Как указано на сайте OR.NET, SDC является семейством стандартов (подробная схема представлена здесь). Мы же будем рассматривать одну из важнейших его частей, а именно ISO/IEEE 11073-10207: Domain information and service model for service-oriented point-of-care medical device communication. Эта часть стандарта определяет как описание возможностей медицинских устройств так и их текущего состояния, так и способы которым потребитель услуг может взаимодействовать с устройствами реализующими роль поставщика услуг. Ненормативное название этого стандарта Basic Integrated Clinical Environment Protocol Specification (здесь и далее сокращенно BICEPS).
Итак, основами SDC протокола являются: MDIB – как абстрактная модель, описывающая наше медицинское PoC устройство, и модель взаимодействия, основанная на сервисах и используемая для связи поставщика и потребителя данных медицинского устройства.
MDIB
MDIB – абстрактная модель, описанная в виде XML файла и содержащая все необходимые элементы и сущности для описания работы нашего устройства.
![Представление MDIB через статическую и динамическую части информации Представление MDIB через статическую и динамическую части информации](https://habrastorage.org/getpro/habr/upload_files/78f/159/632/78f159632aa85b638670e80bd61707ce.png)
Каждый элемент в MDIB имеет две отдельных части: Descriptor (часть хранящая статические или очень редко меняющиеся данные) и State (часть, хранящая в себе данные, динамически изменяющиеся в процессе работы устройства).
![Общее представление MDIB по BICEPS Общее представление MDIB по BICEPS](https://habrastorage.org/getpro/habr/upload_files/839/b5a/f01/839b5af01ac01b94a5685792f7bcd814.png)
MDIB состоит из:
MDS (Medical Device System) – абстрактная модель всего PoC медицинского устройства,
VMD (Virtual Medical Device) – абстрактная модель одной из подсистем PoC медицинского устройства (например модуль ЭКГ, модуль измерения температуры и т.д.),
а также из Channel, AlertSystem и SCO (Service Control Object) – эти элементы служат для логической группировки метрик (Metric), тревог (Alert condition и Alert signal) и операций (Operation) соответственно.
Рассмотрим поподробнее последние упомянутые сущности.
Metrics – сущности, отвечающие за определенные измеряемые данные или настройки. Могут быть числовыми (например, метрика, отвечающая за температуру пациента), строковыми (метрика, показывающая выбранный в текущий момент набор ЭКГ отведений), осциллограмма (одномерный массив числовых измерений необходимый для отрисовки, например для отображения ЭКГ или дыхания пациента).
Alert conditions – сущности, отражающие собой то или иное состояние пациента или устройства, при которых должна быть объявлена тревога. Отражают такие ситуации как нарушение граничных значений метрик, выставленных врачом, проблемы с используемым оборудованием (поломка сенсора, нарушение целостности манжеты тонометра) и т. п.
Alert signals – сущности, отражающие вид уведомлений, используемых при тревогах. Могут быть визуальными: отображение информации на экране устройства, аудиальными: воспроизведение определенных звуков при тревоге или ощутимыми (Tangible) – сигналы тревоги проявляются ощущаемым образом, например вибрацией.
Operations – сущности отражающие возможности удаленного управления устройством, такие как установка лимитов для измеряемых метрик, включение и выключение условий тревоги, изменения настроек устройства.
Модель взаимодействия, основанная на сервисах
Мы кратко рассмотрели с вами MDIB, теперь же перейдем к сервисной модели взаимодействия.
![Сервисы используемые для получения доступа к MDIB Сервисы используемые для получения доступа к MDIB](https://habrastorage.org/getpro/habr/upload_files/408/fed/580/408fed58024a04a73e6bff26ff427f5f.png)
Указанная модель показывает все сервисы, которые описаны в стандарте для получения доступа к МDIB и удаленного управления. Рассмотрим только несколько основных, необходимых нам в дальнейшем.
Get service
Позволяет клиенту получить у поставщика весь MDIB или определенную его часть.
Operation Name | MEP | Brief Description |
GetMdib | RR | Request the whole MDIB
|
GetMdDescription | RR | Request the descriptive part of the MDIB only
|
GetMdState | RR | Request the state part of the MDIB only |
Description event service
Позволяет клиенту получить информацию об изменении дескриптора для какой-либо сущности в MDIB.
Operation Name | MEP | Brief Description |
DescriptionModificationReport
| PS | Receive information on any pm:AbstractDescriptor ELEMENT
|
State event service
Основной сервис, позволяющий клиенту получить данные об изменении state для того или иного элемента MDIB.
Operation Name | MEP | Brief Description |
EpisodicAlertReport / | PS | Receive information on any pm:AbstractAlertState ELEMENT |
EpisodicComponentReport / | PS | Receive information on any pm:AbstractDeviceComponentState |
PeriodicMetricReport / | PS | Receive information on any pm:AbstractMetricState ELEMENT |
EpisodicOperationalStateReport /
| PS | Receive information on any pm:AbstractOperationState ELEMENT |
SystemErrorReport
| PS | Receive information on occurring system errors |
Дальнейшие примеры будут касаться системы тревог и будут опираться на State Event service, а точнее на сообщения типа AbstractAlertReport, включающие в себя EpisodicAlertReport и PeriodicAlertReport сообщения. Давайте рассмотрим их поподробнее.
![Схема AbstractAlertReport Схема AbstractAlertReport](https://habrastorage.org/getpro/habr/upload_files/a57/c3b/bd3/a57c3bbd349bcc54dc2d911cedf16ca6.png)
Из представленной выше схемы нам с вами будут интересны атрибут MdibVersion и дочерний элемент ReportPart:
MdibVersion включает в себя текущий номер версии MDIB.
ReportPart же представляет собой набор AlertState изменяющихся с текущим обновлением:
![Схема части ReporPart для AbstractAlertReport Схема части ReporPart для AbstractAlertReport](https://habrastorage.org/getpro/habr/upload_files/5d3/142/916/5d3142916e1313c30486e757a30a9475.png)
Если мы с вами посмотрим внутрь msg:AlertState, то увидим что каждый AlertState представляет собой набор атрибутов State одной из трех сущностей: AlertSystem, AlertCondition или AlertSignal.
![Схема AlertState Схема AlertState](https://habrastorage.org/getpro/habr/upload_files/7e4/092/71e/7e409271ea155a09b91fb1eddeda7c30.png)
Итак, AbstractAlertReport представляет собой сообщение, хранящее в себе изменения State атрибутов для таких элементов как AlertSystem, AlertCondition или AlertSignal. И любой клиент, подписавшийся на данные типы сообщений, будет своевременно получать информацию об изменении состояния любых тревог, существующих в устройстве.
Базовый порядок взаимодействия поставщика информации с клиентом
![Базовый порядок взаимодействия поставщика информации с клиентом Базовый порядок взаимодействия поставщика информации с клиентом](https://habrastorage.org/getpro/habr/upload_files/f38/2ff/9c7/f382ff9c72f564d8b647e58c9e46c1da.png)
Рассмотрим указанную выше схему взаимодействия:
Поставщик информации объявляет об устройстве в сети.
Клиент устанавливает соединение поставщиком информации и подписывается на необходимые для него сервисы (например, Description event service, State event service, Waveform service, Context service и т. д., в зависимости от нужд клиента.).
Клиент получает MDIB.
Клиент запрашивает и получает данные контекста (пункты 4 и 5 на схеме).
После этого он получает только сообщения с обновлением информации от тех сервисов, на которые он подписался (пункт 6. на схеме).
Библиотека sdc11073
Так как SDC протокол — это открытый стандарт взаимодействия медицинских устройств, существуют пакеты для работы с ним на разных языках программирования. Мы в целях автоматизированного тестирования используем пакет, находящийся в открытом доступе на github и написанный на языке программирования Python. Подробно на его реализации и работе останавливаться не будем, но рассмотрим основные моменты, которые нам могут пригодиться в дальнейших примерах.
Итак, пакет sdc11 073 — это полноценная реализация SDC протокола, написанная на Python. Он позволяет вам создать как SDC устройство, которое будет являться провайдером данных, так и SDC клиент, являющийся потребителем данных.
Также эта реализация создает объектно‑ориентированную модель MDIB на основе получаемого xml файла, что очень сильно упрощает обработку и тестирование данных MDIB. Так создается объект класс MDIB, который включает в себя дескрипторы и стейты для каждого элемента в текущем MDIB с использованием типов данных, описанных в BICEPS. Например, элемент MDIB, являющийся дескриптором какой‑либо числовой метрики (предположим, метрику показывающую частоту сердечных сокращений), будет представлен объектом класса NumericMetricDescriptorContainer, который является дочерним классом AbstractMetricDescriptorContainer (отвечающий за представление общих параметров для метрик всех типов), который, в свою очередь, является дочерним классом AbstractDescriptorContainer (отвечает за предоставление общих параметров для всех дескрипторов в MDIB). Такое объектно‑ориентированное представление хорошо помогает для определения и фильтрации данных, необходимых для той или иной проверки или взаимодействия.
Пакет предоставляет и дополнительные типы данных, основанные на BICEPS и использующиеся атрибутами тех или иных объектов (например объект класса AbstractDescriptorContainer имеет атрибут Type, являющийся объектом класса CodedValue и повторяющий структуру, описанную в BICEPS).
Если хотите узнать больше или опробовать этот пакет самостоятельно — он доступен по ссылке, указанной мной выше. Проект постоянно обновляется и дорабатывается, а также имеет довольно неплохую базу тестовых примеров для того, чтобы можно было разобраться со всей его функциональностью.
SDC протокол и автоматизированное тестирование
Рассмотрим типичные требования, предъявляемые к устройствам, общающимся по SDC протоколу, и способы их верификации при использовании автоматизированного тестирования. Ниже будут подобраны примеры требований, взятые из BICEPS или из общих требований к поведению продуктов, работающих с SDC протоколом, которые имеет смысл проверять, используя средства автоматизированного тестирования. Здесь стоит уточнить, что наиболее полное тестирование медицинских продуктов, использующих SDC протокол, достигается сочетанием подходов как автоматизированного, так и ручного тестирования.
Начнем с требований по тестированию статических данных MDIB (здесь и далее во всех примерах алгоритмы проверки будут основываться на использовании описанной выше библиотеки sdc11 073):
All HANDLEs SHALL be unique within one MDIB sequence of a SERVICE PROVIDER
Относительно этого требования необходимо уточнить, что большинство продуктов, использующих SDC протокол, не изменяют во время своей работы Handle (уникальный идентификатор объекта) элементов. Если ваш продукт требует изменения уникальных идентификаторов сущностей во время работы, вам необходимо будет учитывать каждый такой случай индивидуально.
Проверка же этого требования довольно банальна:
Создание симуляции клиента и установка соединения с SDC устройством
Получение объекта MDIB.
Сбор всех элементов типов AbstractDescriptorContainer и AbstractMultiStateContainer.
Проверка уникальности атрибута Handle для каждого элемента в собранной коллекции.
Например, при использовании Python можно собрать все существующие Handle в объект типа List и далее на основе этого объекта сформировать новый объект типа Set, сравнить длины получившихся двух объектов и указать на дублирующийся объект, если таковой найдется.
Пункт 1 и 2 данного алгоритма будут использоваться во всех дальнейших примерах и вследствие этого будут опущены.
Этот же алгоритм будет применен для проверки следующего требования:
A HANDLE SHALL consist of characters that match only valid Unicode codes greater than U+0020, except for U+FFFD (replacement character)
Здесь тоже все довольно просто. Выполняем пункты 1–3 из прошлого примера, а далее идем по каждому Handle из коллекции и проверяем все символы, из которых он состоит, на валидность.
A SERVICE PROVIDER SHOULD describe all offered remote invocation capabilities using the pm:ScoDescriptor structure in pm:MdsDescriptor/pm:Sco.
В этом требовании под remote invocation capabilities подразумеваются объекты Operation (pm:AbstractOperationDescriptor), так как именно они отвечают за удаленное управление устройством. Зная это, наше требование сводится к тому, что все имеющиеся в MDIB операции должны быть дочерними элементами элемента ScoDescriptor:
Собираем все объекты класса AbstractOperationDesriptor.
Проверяем, что у собранных нами объектов атрибут parentHandle указывает на Handle объекта класса ScoDescriptor.
Проверяем, что объект класса ScoDescriptor, на который ссылаются наши Operation, сам ссылается атрибутом parentHandle на Handle объекта класса MdsDescriptor.
An SDC SERVICE PROVIDER shall define pm:AbstractDescriptor/pm:Type for ELEMENTs of the following TYPEs or any TYPE derived from the listed TYPEs if used:
pm:AbstractComplexDeviceComponentDescriptor
pm:ChannelDescriptor
pm:AbstractOperationDescriptor
pm:AlertConditionDescriptor
pm:AbstractMetricDescriptor.
Это требование говорит о том, что все объекты с перечисленными ниже типами, а также типами, наследуемыми от перечисленных, должны иметь атрибут Type. Алгоритм проверки:
Собрать все объекты классов AbstractComplexDeviceComponentDescriptorContainer, ChannelDescriptorContainer, AbstractMetricDescriptorContainer, AbstractOperationDescriptorContainer, AlertConditionDescriptorContainer.
Проверить, что атрибут Type каждого отобранного объекта является объектом класса CodedValue.
Думаю, что примеров проверки статических данных достаточно, пора переходить к требованиям, которые можно проверить только во время работы нашего устройства. Лучшим подходом будет использование программной симуляции поведения устройства для автоматического воспроизведения необходимых для тестирования ситуаций.
В предыдущих примерах мы с вами работали с объектом MDIB, хранящим в себе все дескрипторы и стейты, предоставленные нам в xml файле MDIB. Теперь же нам нужно будет работать еще и с сервисными сообщениями, обновляющими переданную нам информацию. В этом нам поможет реализованный функционал ObservableProperties из библиотеки sdc11 073. Так например, с помощью них мы можем выполнять действия, определенные написанной нами функцией или методом при получении клиентом необходимого нам типа сообщений. Для простоты анализа в дальнейших примерах мы предположим, что описываем функцию, которая при получении сообщения необходимого нам типа просто кладет это сообщение на хранение в отдельно созданный список.
A change to pm:AlertConditionState/@Presence of an ALERT CONDITION SHALL always be delivered together with an ALERT SYSTEM state update within one msg:AbstractAlertReport MESSAGE.
Итак, перейдем к проверке описанного выше требования:
Подписываемся на получение сообщений EpisodicAlertReport и PeriodicAlertReport, используя написанную нами функцию.
Начинаем симуляцию тревоги на устройстве.
Ждем изменения состояния pm:AlertConditionState/@Presence с False на True.
Останавливаем сбор сообщений.
Анализируем список полученных нами сообщений.
Сообщения, получаемые с помощью ObservableProperties, будут храниться в виде xml записей, поэтому для их анализа можно воспользоваться библиотекой lxml или любой другой, с которой вам удобно работать. Все что нам остается, это найти сообщение, в котором AlertConditionState/@Presence был изменен на True, и убедиться, что в этом же сообщении есть изменение стейта родительской AlertSystem (Определить Handle родительской AlertSystem можно обратившись к атрибуту объекта стейта descriptorContainer.parentHandle).
Повторить шаги 1–5, только теперь в шаге 2 вместо симуляции тревоги симулировать ее отключение и в последующих шагах ждать смены pm:AlertConditionState/@Presence с True на False.
If pm:AlertConditionState/@Presence is "true" for any physiological alarm condition or technical alarm condition, then the HANDLE of the corresponding ALERT CONDITION SHALL be added to pm:AlertSystemState/@ PresentPhysiologicalAlarmConditions or pm:AlertSystemState/@PresentTechnicalAlarmConditions, respectively.
Это требование говорит о том, что любая присутствующая тревога, в зависимости от ее типа (физиологическая или техническая), должна быть отражена в соответствующем списке присутствующих тревог.
Обычно списки PresentPhysiologicalAlarmConditions и PresentTechnicalAlarmConditions при наличии более чем одной AlertSystem представлены только в одной определенной AlertSystem (например, в AlertSystem, являющейся дочерним элементом MDS).
Алгоритм проверки:
Подписываемся на получение сообщений EpisodicAlertReport и PeriodicAlertReport, используя написанную нами функцию.
Начинаем симуляцию тревоги на устройстве.
Ждем изменения состояния pm:AlertConditionState/@Presence с False на True.
Останавливаем сбор сообщений.
Находим в списке полученных нами сообщений сообщение с необходимыми нам изменениями AlertConditionState.
Проверяем, что в этом же сообщении находятся изменения стейта необходимой нам AlertSystem и присутствие нашего AlertCondition в соответствующем списке.
Повторяем шаги 1–7 с изменением Presence на False и проверкой исчезновения AlertCondition из соответствующего списка.
Два следующих требования могут быть проверены вместе:
If the ALERT PROVIDER sets an pm:AlertSignalState/@ActivateState = Off and on the same pm:AlertSignalState there is not set pm:AlertSignalState/@Presence = Off, the ALERT PROVIDER shall set and retain pm:AlertSignalState/@Presence = Off in an MDIB version lower than the the MDIB version where it is set pm:AlertSignalState/@ActivationState = Off.
и
If the ALERT PROVIDER sets an pm:AlertConditionState/@ActivateState = Off and on the same pm:AlertConditionState there is not set pm:AlertConditionState/@Presence = true, the SERVICE PROVIDER shall set and retain pm:AlertConditionState/@Presence = false in an MDIB version lower than the MDIB version where it is set pm:AlertConditionState/@ActivationState = Off.
Подписываемся на получение сообщений EpisodicAlertReport и PeriodicAlertReport, используя написанную нами функцию.
Начинаем симуляцию тревоги на устройстве.
Отключаем проверку тревоги на устройстве так, чтобы ActivationState нашей тревоги стал равен Off.
Останавливаем сбор сообщений.
Ищем сообщения, в которых AlertConditionState/Presence изменился на False и AlertSignalState/Presence изменился на Off. Запоминаем MdibVersion этих сообщений соответственно.
Ищем сообщения, в которых AlertConditionState/ActivationState и AlertSignalState/ActivationState изменились на Off. Запоминаем MdibVersion этих сообщений соответственно.
Сравниваем MdibVersion изменения атрибута Presence и изменения атрибута ActivationState. MdibVersion изменения атрибута Presence должна быть меньше.
An AlertConditionDescriptor/Priority shall only be updated if the AlertConditionState/Presence = false and all related AlertSignalState/Presence are Off or Ack.
Для проверки этого требования нам понадобиться новый тип сообщений msg:DescriptorModificationReport. Он очень похож на вышеописанный нами AbstractAlertReport:
![Схема DescriptorModificationReport Схема DescriptorModificationReport](https://habrastorage.org/getpro/habr/upload_files/188/53b/5fb/18853b5fb5566f375280e9e8ab3631e2.png)
И его ReportPart хранит в себе изменения атрибутов дескриптора объекта.
![Схема ReportPart для DescriptorModificationReport Схема ReportPart для DescriptorModificationReport](https://habrastorage.org/getpro/habr/upload_files/27d/4c2/85e/27d4c285e3d844a3e4b6a30c6a4bc50f.png)
Теперь, когда у нас есть описание DescriptorModificationReport перейдем к алгоритму проверки:
Подписываемся на получение сообщений EpisodicAlertReport, PeriodicAlertReport и DescriptorModificationReport, используя написанную нами функцию.
Начинаем симуляцию тревоги на устройстве.
Изменяем приоритет активной тревоги на устройстве.
Ждем изменения приоритета в объекте AlertConditionDescriptor.
Останавливаем сбор сообщений.
Ищем сообщения, в которых AlertConditionState/Presence изменился на False и AlertSignalState/Presence изменился на Off. Запоминаем MdibVersion этих сообщений соответственно.
Ищем сообщение DescriptorModificationReport с необходимыми нам изменениями и запоминаем его MdibVersion.
Сравниваем версии MdibVersion изменения атрибута Presence и DecriptorModificationReport. MdibVersion изменения атрибута Presence должна быть меньше.
Дополнительно можно проверить то, что после изменения Priority у AlertConditionDescriptor, AlertConditionState/@Presence и AlertSignalState/@Presence вернулись в исходное состояние (если ваше устройство поддерживает продолжение тревоги после смены ее приоритета).
Заключение
Нет сомнений в том, что с каждым годом спрос на использование открытых протоколов взаимодействия в медицинской отрасли будет только расти. Это означает, что потребуется разработка все большего количества устройств, работающих с новыми протоколами взаимодействия, а также разработка средств по конвертации старых протоколов для связи с уже существующими на рынке устройствами.
Мы же с вами рассмотрели базовые принципы работы SDC протокола, а также существующие уже сейчас средства и подходы для проведения автоматизированного тестирования продуктов на соответствие этому протоколу.