Управление измерительными приборами Rohde-Schwarz по интерфейсу RSIB
Измерительная аппаратура компании Rohde&Schwarz – это профессиональная аппаратура, которая используется в рабочих процессах на многих предприятиях по всему миру. Зачастую необходимо обеспечивать удалённый доступ и управление измерениями и режимами работы измерительной аппаратуры. Для этого у приборов Rohde&Schwarz есть, как правило, несколько возможностей. Одна из них – интерфейс RSIB. Рассмотрим его подробнее.
1Описание интерфейсаудалённого управления RSIB
Интерфейс RSIB использует динамически загружаемую библиотеку RSIB32.DLL, которая содержит несколько экспортируемых функций для работы с измерительными приборами. Эти функции позволяют передавать прибору по локальной сети команды и директивы, а также получать его ответы. Список экспортируемых функций приведён ниже.
Вот какие функции имеются в библиотеке.
Функция | Назначение | |
---|---|---|
RSDLLibfind() | Пытается подключиться к измерительному прибору по IP-адресу. | |
RSDLLibonl() | Переводит прибор в режим online/offline. После перевода в режим offline необходимо заново подключаться к прибору с помощью RSDLLibfind(). | |
RSDLLibwrt() | Отправляет прибору строку. | |
RSDLLilwrt() | Отправляет прибору массив байтов. | |
RSDLLibwrtf() | Отправляет прибору содержимое файла. | |
RSDLLibrd() | Читает из прибора строку. | |
RSDLLilrd() | Читает из прибора заданное число байтов. | |
RSDLLibrdf() | Читает из прибора данные в файл. | |
RSDLLibloc() | Временно переводит прибор в режим LOCAL. | |
RSDLLibeot() | Включает или выключает отправку конца сообщения после операции записи. | |
RSDLLibrsp() | Опрашивает регистр статуса прибора. | |
RSDLLibtmo() | Задаёт таймаут для функций RSIB. | |
RSDLLibsre() | Переводит прибор в режим LOCAL или режим REMOTE. | |
RSDLLTestSRQ() | Проверяет значение бита SRQ прибора. | |
RSDLLWaitSrq() | Ожидает одно из двух событий: 1) прибор установит бит SRQ; 2) бит SRQ не будет установлен прибором в течение времени, заданного тайм-аутом. | |
RSDLLSwapBytes() | Переключает отображение байтов с Big Endian на Little Endian и обратно. Требуется на платформах, отличных от Intel (x86). |
Предлагается сделать класс-обёртку для данной библиотеки в объектно-ориентированном стиле. Для использования базовой функциональности библиотеки некоторые её функции можно оставить без реализации. Нам точно пригодятся функции для подключения к прибору, перевода в режим REMOTE/LOCAL, записи и чтения строк. Эти функции будут нужны для отправки прибору команд SCPI.
Программный код для работы по интерфейсу RSIB (разворачивается)
Imports System.Runtime.InteropServices Imports System.Text Namespace RS ''' <summary> ''' Работа с устройствами Rohde-Schwarz по протоколу RSIB. ''' </summary> Public Class RSIB Implements IDisposable #Region "CTOR" Private Const LibPath As String = "rsib32.dll" Private Const CLOSED_HANDLE As UShort = &H8000US ''' <summary> ''' Дескриптор устройства. Присваивается во время открытия устройства. ''' </summary> Private ReadOnly Property DevHandle As UShort Get Return _DevHandle End Get End Property Private _DevHandle As UShort = CLOSED_HANDLE ''' <summary> ''' Ищет устройство RSIB и подключается к нему по IP-адресу <paramref name="ipAddr"/>. ''' </summary> ''' <param name="ipAddr">IP-адрес устройства.</param> Public Sub New(ipAddr As String) Dim ibsta As Status 'флаги статуса Dim iberr As Errors 'код ошибки Dim ibcntl As UInteger 'счётчик показывает число переданных байтов _DevHandle = RSDLLibfind(ipAddr, ibsta, iberr, ibcntl) CheckResult(ibsta, iberr) End Sub <DllImport(LibPath, CharSet:=CharSet.Ansi)> Private Shared Function RSDLLibfind(udName As String, ByRef ibsta As Status, ByRef iberr As Errors, ByRef ibcntl As UInteger) As UShort End Function ''' <summary> ''' Отключается от устройства. ''' </summary> ''' <remarks> ''' После закрытия устройства программный доступ к устройству становится невозможен. ''' </remarks> Public Sub Close() If (_DevHandle <> CLOSED_HANDLE) Then Try Dim ibsta As Status Dim iberr As Errors Dim ibcntl As UInteger Dim res As Integer = RSDLLibonl(DevHandle, Modes.Local, ibsta, iberr, ibcntl) _DevHandle = CLOSED_HANDLE Catch ex As Exception Debug.WriteLine(ex) End Try End If End Sub <DllImport(LibPath, CharSet:=CharSet.Ansi)> Private Shared Function RSDLLibonl(udName As Integer, mode As Modes, ByRef ibsta As Status, ByRef iberr As Errors, ByRef ibcntl As UInteger) As UShort End Function #End Region '/CTOR #Region "ЗАПИСЬ, ЧТЕНИЕ" ''' <summary> ''' Отправляет команду и читает ответ. ''' </summary> Public Function SendCommand(command As String) As String Dim ibsta As Status Dim iberr As Errors Dim ibcntl As UInteger Dim res As Integer = RSDLLibwrt(DevHandle, command & vbNullChar, ibsta, iberr, ibcntl) CheckResult(ibsta, iberr) If command.Contains("?"c) Then Dim sbAns As New StringBuilder(100) Dim ans As Integer = RSDLLibrd(DevHandle, sbAns, ibsta, iberr, ibcntl) CheckResult(ibsta, iberr) Return sbAns.ToString() End If Return String.Empty End Function <DllImport(LibPath, CharSet:=CharSet.Ansi)> Private Shared Function RSDLLibwrt(udName As Integer, data As String, ByRef ibsta As Status, ByRef iberr As Errors, ByRef ibcntl As UInteger) As Integer End Function <DllImport(LibPath, CharSet:=CharSet.Ansi)> Private Shared Function RSDLLibrd(udName As Integer, data As StringBuilder, ByRef ibsta As Status, ByRef iberr As Errors, ByRef ibcntl As UInteger) As UShort End Function #End Region '/ЗАПИСЬ, ЧТЕНИЕ #Region "УПРАВЛЕНИЕ РЕЖИМОМ" ''' <summary> ''' Переключает устройство в режим <paramref name="mode"/>. ''' </summary> ''' <remarks> ''' После переключения в режим <see cref="Modes.TemporarilyLocal"/> устройство может управляться вручную через фронтальную панель. ''' При следующем удалённом доступе устройство снова переключится в режим <see cref="Modes.Remote"/>. ''' </remarks> Public Sub SetMode(mode As Modes) Dim ibsta As Status Dim iberr As Errors Dim ibcntl As UInteger Select Case mode Case Modes.Local, Modes.Remote Dim res As Integer = RSDLLibsre(DevHandle, mode, ibsta, iberr, ibcntl) Case Modes.TemporarilyLocal Dim res As Integer = RSDLLibloc(DevHandle, ibsta, iberr, ibcntl) End Select CheckResult(ibsta, iberr) End Sub <DllImport(LibPath, CharSet:=CharSet.Ansi)> Private Shared Function RSDLLibsre(udName As Integer, mode As Modes, ByRef ibsta As Status, ByRef iberr As Errors, ByRef ibcntl As UInteger) As UShort End Function <DllImport(LibPath, CharSet:=CharSet.Ansi)> Private Shared Function RSDLLibloc(udName As Integer, ByRef ibsta As Status, ByRef iberr As Errors, ByRef ibcntl As UInteger) As UShort End Function ''' <summary> ''' Включает или выключает отправку конца сообщения после операции записи. ''' </summary> ''' <param name="sendEnd">Если False, то команды могут отправляться несколькими последовательными вызовами <see cref="SendCommand(String)"/>. ''' True должно быть снова установлено перед отправкой последнего блока данных. ''' </param> ''' <remarks> ''' If the END message is disabled, the data of a command can be sent with several successive calls of write functions. ''' The END message must be enabled again before sending the last data block. ''' </remarks> Public Sub SetEndOfMessage(sendEnd As Boolean) Dim ibsta As Status Dim iberr As Errors Dim ibcntl As UInteger Dim res As Integer = RSDLLibeot(DevHandle, sendEnd, ibsta, iberr, ibcntl) CheckResult(ibsta, iberr) End Sub <DllImport(LibPath, CharSet:=CharSet.Ansi)> Private Shared Function RSDLLibeot(udName As Integer, <MarshalAs(UnmanagedType.Bool)> sendEnd As Boolean, ByRef ibsta As Status, ByRef iberr As Errors, ByRef ibcntl As UInteger) As UShort End Function #End Region '/УПРАВЛЕНИЕ РЕЖИМОМ #Region "ERRORS, STATUS" ''' <summary> ''' Опрашивает устройство и возвращает его регистр статуса. ''' </summary> Public Function GetDeviceStatusRegister() As Byte Dim ibsta As Status Dim iberr As Errors Dim ibcntl As UInteger Dim spr As Byte Dim res As Integer = RSDLLibrsp(DevHandle, spr, ibsta, iberr, ibcntl) CheckResult(ibsta, iberr) Return spr End Function <DllImport(LibPath, CharSet:=CharSet.Ansi)> Private Shared Function RSDLLibrsp(udName As Integer, ByRef spr As Byte, ByRef ibsta As Status, ByRef iberr As Errors, ByRef ibcntl As UInteger) As UShort End Function ''' <summary> ''' Проверяет статус и ошибки. ''' </summary> Private Sub CheckResult(stat As Status, err As Errors) If IsErrorOccured(stat) Then Throw New Exception(GetErrorText(err)) ElseIf IsTimeout(stat) Then Throw New Exception("Превышено время ожидания.") End If End Sub ''' <summary> ''' Возвращает текст ошибки. ''' </summary> Private Function GetErrorText(err As Errors) As String Select Case err Case Errors.IBERR_TIMEOUT Return "Превышено время ожидания." Case Errors.IBERR_BUSY Return "Протокол RSIB заблокирован функцией, которая ещё выполняется." Case Errors.IBERR_CONNECT Return "Подключение к инструменту не удалось." Case Errors.IBERR_NO_DEVICE Return "Функция была вызвана с некорректным идентификатором устройства." Case Errors.IBERR_MEM Return "Нет свободной памяти." Case Errors.IBERR_FILE Return "Ошибка во время чтения или записи в файл." Case Errors.IBERR_SEMA Return "Ошибка создания или присваивания семафора (только для UNIX)." Case Else Return "Ошибка во время работы с устройством." End Select End Function Private Function IsAnswerReady(stat As Status) As Boolean Return ((stat And Status.CMPL) = Status.CMPL) End Function Private Function IsTimeout(stat As Status) As Boolean Return ((stat And Status.TIMO) = Status.TIMO) End Function Private Function IsErrorOccured(stat As Status) As Boolean Return ((stat And Status.ERR) = Status.ERR) End Function #End Region '/ERRORS, STATUS #Region "ENUMS" ''' <summary> ''' Состяния устройства. ''' </summary> <Flags()> Public Enum Status As UShort ''' <summary> ''' Флаг установлен, когда произошла ошибка во время вызова функции. ''' </summary> ''' <remarks> ''' При наличии этого флага в статусе необходимо проверить код ошибки для выяснения деталей. ''' </remarks> ERR = &H8000 ''' <summary> ''' Флаг установлен, когда превышено время ожидания во время вызова функции. ''' </summary> TIMO = &H4000 ''' <summary> ''' Флаг установлен, когда устройство завершило обработку принятой команды. ''' Флаг сброшен, когда ответ устройства прочитан или длина буфера недостаточна для ответа. ''' </summary> CMPL = &H100 End Enum ''' <summary> ''' Коды ошибок. ''' </summary> Public Enum Errors As UShort None = 0 ''' <summary> ''' Подключение к инструменту не удалось. ''' </summary> IBERR_CONNECT = 2 ''' <summary> ''' Функция была вызвана с некорректным идентификатором устройства. ''' </summary> IBERR_NO_DEVICE = 3 ''' <summary> ''' Нет свободной памяти. ''' </summary> IBERR_MEM = 4 ''' <summary> ''' Превышено время ожидания. ''' </summary> IBERR_TIMEOUT = 5 ''' <summary> ''' Протокол RSIB заблокирован функцией, которая ещё выполняется. ''' </summary> IBERR_BUSY = 6 ''' <summary> ''' Ошибка во время чтения или записи в файл. ''' </summary> IBERR_FILE = 7 ''' <summary> ''' Ошибка создания или присваивания семафора (только для UNIX). ''' </summary> IBERR_SEMA = 8 End Enum Public Enum Modes As UShort Local = 0 Remote = 1 ''' <summary> ''' Временно переключить в локальный режим. После получения команды снова переходит в удалённый режим. ''' </summary> TemporarilyLocal = 2 End Enum #End Region '/ENUMS #Region "IDISPOSABLE" Private DisposedValue As Boolean Protected Overridable Sub Dispose(disposing As Boolean) If (Not DisposedValue) Then Close() DisposedValue = True End If End Sub Public Sub Dispose() Implements IDisposable.Dispose Dispose(disposing:=True) GC.SuppressFinalize(Me) End Sub #End Region '/IDISPOSABLE End Class End Namespace
Последняя версия кода всегда доступна на Гитхабе, а детальное описание работы по интерфейсу RSIB приведены на официальном сайте Rohde&Schwarz. Библиотеку rsib32.dll можно скачать в конце статьи.
2Использование класса-обёртки RSIBпри работе с аппаратурой Rohde&Schwarz
Использование приведённого программного кода очень простое. Например, запросим у прибора его идентификатор, используя синтаксис SCPI, который поддерживается большинством измерительной аппаратуры (и приборами фирмы Rohde&Schwarz в частности), а затем переведём его в локальный режим:
Using rs As New RS.RSIB("192.168.0.200") 'ввести свой IP-адрес прибора R&S Dim id As String = rs.SendCommand("*IDN?") rs.SetMode(RSIB.Modes.Local) Console.WriteLine($"Прибор {id} переведён в локальный режим.") End Using
Естественно, что необходимо выполнять данный код в блоке обработки ошибок Try…Catch, т.к. если программа не найдёт по указанному IP-адресу измерительный прибор, она выбросит исключение.
Download attachments:
- Скачать библиотеку rsib32.dll (385 Downloads)
Поблагодарить автора:
Поделиться
Related items
2 comments
-
Лев Понедельник, 28 Октябрь 2024 05:46 Ссылка на комментарий
Добрый день! Подскажите пожалуйста а как автоматизировать работу Rohde&Schwarz. Может у вас скрипт есть?
-
aave1 Понедельник, 28 Октябрь 2024 19:26 Ссылка на комментарий
Лев, ваш вопрос очень общий. Для каждой функции - там одно описание возможностей, например, спектроанализатора - несколько сотен страниц. Придётся разбираться и реализовывать автоматизацию самому, в зависимости от своих задач.