Управление измерительными приборами 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-адресу измерительный прибор, она выбросит исключение.
Скачать вложения:
- Скачать библиотеку rsib32.dll (509 Скачиваний)
Поблагодарить автора:
Поделиться
Похожие материалы (по тегу)
2 комментарии
-
Лев 28.10.2024 05:46 КомментироватьДобрый день! Подскажите пожалуйста а как автоматизировать работу Rohde&Schwarz. Может у вас скрипт есть?
-
aave1 28.10.2024 19:26 КомментироватьЛев, ваш вопрос очень общий. Для каждой функции - там одно описание возможностей, например, спектроанализатора - несколько сотен страниц. Придётся разбираться и реализовывать автоматизацию самому, в зависимости от своих задач.
