Port manager: Difference between revisions
(40 intermediate revisions by 3 users not shown) | |||
Line 1: | Line 1: | ||
SweepMe! supports and simplifies communication to devices via RS232 ([[COM]] port), [[GPIB]], [[USB]] and [[TCPIP]] by using the SweepMe! [[Port manager]]. | SweepMe! supports and simplifies communication to devices via RS232/RS485 ([[COM]] port), [[GPIB]], [[USB]] and [[TCPIP]] by using the SweepMe!'s [[Port manager]]. | ||
==Introduction== | ==Introduction== | ||
Line 6: | Line 6: | ||
== Supported protocols == | == Supported protocols == | ||
* [[COM]]: standard PC serial port using RS-232 protocol | * [[COM]]: standard PC serial port using RS-232 or RS-485 protocol | ||
* [[GPIB]]: an IEEE-488-Bus | * [[GPIB]]: a standardized communication/interface via an IEEE-488-Bus | ||
* [[TCPIP]]: | * [[TCPIP]]: communication via a network, e.g. ethernet | ||
* [[USB]]: plug and play USB test and measurement device as supported by pyvisa | * [[USB]]: plug and play USB test and measurement device as supported by pyvisa | ||
* [[VB]]: a National Instrument VirtualBench device | * ([[VB]]: a National Instrument VirtualBench device -> deprecated from 1.5.5: please find and create port objects yourself) | ||
== Usage == | == Usage == | ||
===Configuration=== | ===Configuration=== | ||
The following variables have to be set within the ''__init__'' function of a Device Class: | The following variables have to be set within the ''__init__'' function of a Device Class: | ||
In order to get the available ports listed in the GUI of the corresponding [[ | In order to get the available ports listed in the GUI of the corresponding [[Modules|Module]], choose desired port types by: | ||
{{syntaxhighlight|lang=python|code= | {{syntaxhighlight|lang=python|code= | ||
self.port_types = ["COM", "GPIB", "USB", " | self.port_types = ["COM", "GPIB", "USB", "TCPIP"] | ||
}} | }} | ||
Line 25: | Line 26: | ||
self.port_manager = True | self.port_manager = True | ||
}} | }} | ||
=== Port properties === | === Port properties === | ||
You can set port properties during __init__ of the Device Class or before connect is called by modifying the self.port_properties dictionary. | You can set port properties during __init__ of the Device Class or before [[connect()]] is called by modifying the self.port_properties dictionary. | ||
In order to see all keys of the dictionary, use | In order to see all keys of the dictionary, use | ||
{{syntaxhighlight|lang=python|code= | {{syntaxhighlight|lang=python|code= | ||
print self.port_properties | print(self.port_properties) | ||
}} | }} | ||
Line 62: | Line 61: | ||
|- | |- | ||
| EOLread || COM || String || None || replace the character which defines the end of each message read by self.port.read() | | EOLread || COM || String || None || replace the character which defines the end of each message read by self.port.read() | ||
|- | |||
| GPIB_EOLwrite || GPIB || String || None || sets the character which will be added to each command sent by self.port.write() | |||
|- | |||
| GPIB_EOLread || GPIB || String || None || sets the character which defines the end of each message read by self.port.read() | |||
|- | |||
| TCPIP_EOLwrite || TCPIP || String || None || sets the character which will be added to each command sent by self.port.write() | |||
|- | |||
| TCPIP_EOLread || TCPIP || String || None || sets the character which defines the end of each message read by self.port.read() | |||
|- | |- | ||
| baudrate || COM || Integer || 9600 || The [https://en.wikipedia.org/wiki/Baud Baudrate] defines the speed of the COM port communication, must be identical to the value of the instrument | | baudrate || COM || Integer || 9600 || The [https://en.wikipedia.org/wiki/Baud Baudrate] defines the speed of the COM port communication, must be identical to the value of the instrument | ||
Line 67: | Line 74: | ||
| bytesize || COM || Integer || 8 || length of one byte, must be identical to value of the instrument | | bytesize || COM || Integer || 8 || length of one byte, must be identical to value of the instrument | ||
|- | |- | ||
| | | stopbits || COM || Integer || 1 || | ||
|- | |||
| parity || COM || String || "N" || None = "N", Odd = "O", Even = "E", Mark = "M", Space = "S" | |||
|- | |||
| xonxoff || COM || Bool || False || | |||
|- | |||
| rtscts || COM || Bool || False || | |||
|- | |- | ||
| | | dsrdtr || COM || Bool || False || | ||
|- | |- | ||
| | | rts || COM || Bool || True || | ||
|- | |- | ||
| | | dtr || COM || Bool || True || | ||
|- | |- | ||
| | | raw_write|| COM || Bool || False || send the argument as is without further encoding, an eol/terminator-character is still added if specified. | ||
|- | |||
| raw_read || COM || Bool || False || receive the answer as is without further decoding | |||
|- | |||
| rstrip || COM || Bool || True || strips trailing characters such as whitespaces, line feeds, carriage return or tab character. | |||
|- | |- | ||
| timeout || COM, USB, GPIB || Float || 1.0 || time in seconds before a timeout error is raised | | timeout || COM, USB, GPIB || Float || 1.0 || time in seconds before a timeout error is raised | ||
|- | |||
| clear || all || Bool || True || Send a clear command to the port after opening the port (SweepMe! 1.5.6.15+ / pysweepme 1.5.6.10+) | |||
|- | |- | ||
| delay || COM, GPIB || Float || 0.0 || delay time in seconds after writing a command to allow an instrument to process the current command. | | delay || COM, GPIB || Float || 0.0 || delay time in seconds after writing a command to allow an instrument to process the current command. | ||
|- | |||
| encoding || COM || String || 'latin-1' || encoding used to encode and decode byte based messages | |||
|- | |||
| Exception || COM, GPIB, USB, TCPIP || bool || True || If an error occurs, the measurement is stopped. Set to False to be able to catch communications errors with try-except. | |||
|} | |} | ||
Line 89: | Line 112: | ||
}} | }} | ||
A message can be sent | A message can be sent by using: | ||
{{syntaxhighlight|lang=python|code= | {{syntaxhighlight|lang=python|code= | ||
self.port.write("string of the message without end-of-line/terminator character") | self.port.write("string of the message without end-of-line/terminator character") | ||
Line 102: | Line 125: | ||
The returned object is typically a string, so please do not forget to change the type if needed by using e.g. int() or float(). | The returned object is typically a string, so please do not forget to change the type if needed by using e.g. int() or float(). | ||
In case you need direct access to the port object created by the port manager, use: | In case you need direct access to the port object created by the port manager, use: | ||
Line 109: | Line 131: | ||
}} | }} | ||
Thus, you can use commmands as defined by pyserial for COM port communication or pyvisa for GPIB/USB communication. | Thus, you can use commmands as defined by [http://pyserial.readthedocs.io/en/latest/pyserial.html pyserial] for COM port communication or [http://pyvisa.readthedocs.io/en/stable/ pyvisa] for GPIB/USB communication. | ||
For example, one can manipulate the termination character, e.g.: | |||
{{syntaxhighlight|lang=python|code= | |||
self.port.port.write_termination = "\r\n" | |||
self.port.port.read_termination = "\r\n" | |||
# "\r\n" is here one example for using Carriage Return (CR) and Line Feed (LF) as terminator | |||
}} | |||
However, it is recommended to do this using self.port_properties and the keys 'GPIB_EOLwrite' and 'GPIB_EOLread'. Otherwise, the solution only works for pyyvisa related GPIB port and would break when using other GPIB port such as the one created for a Prologix GPIB controller. | |||
=== COM port === | |||
In order to check the number of already received bytes, you can use: | |||
{{syntaxhighlight|lang=python|code= | |||
number_of_received_bytes = self.port.in_waiting() | |||
}} | |||
As SweepMe! is based on python 3, all strings that are send via self.port.write() are actually unicode strings. The Port Manager automatically converts them to bytes before sending them using the library pyserial. Similarly, received bytes are automatically converted back to unicode strings. If you like to have raw access to the bytes that are sent and received, please use the port properties 'raw_read' and 'raw_write'. | |||
Sometimes it is needed to only read the raw answers (i.e. bytes) of a few commands. In that case you can use the functions like 'read_raw' and 'write_raw' | |||
{{syntaxhighlight|lang=python|code= | |||
self.port.write_raw(...) # make sure that you send a byte string | |||
answer = self.port.read_raw() # answer will be a byte string that you need to decode or process yourself. | |||
answer = self.port.read_raw(10) # example to read 10 bytes | |||
}} | |||
=== Exceptions === | |||
If during port communication, an exception occurs, SweepMe! will stop the run and print the message in the [[Debug]] widget. If you like to catch the exception yourself, please add the key 'Exception' to the port properties and set it to 'False'. | |||
{{syntaxhighlight|lang=python|code= | |||
self.port_properties = { | |||
... # all other properties | |||
"Exception": "False", | |||
} | |||
}} | |||
Then, you can use try-except to handle the exception, e.g. to send a command again if a checksum was incorrect or an instrument did not answer in the given timeout. | |||
{{syntaxhighlight|lang=python|code= | |||
self.port.write("*IDN?") | |||
try: | |||
self.port.read() # We try to read the answer | |||
except: | |||
self.port.write("*IDN?") # If reading the answer fails, e.g. resulting in a timeout error, we write again to the instrument | |||
self.port.read() # and we check the answer again. This example can be done multiple times in a loop if you like to implement multiple retries | |||
} | |||
}} | |||
== pysweepme == | |||
The port manager of SweepMe! uses the module 'Ports' of the open-source pysweepme package. If you like to see how the exact communication is done, please feel free to download [https://pypi.org/project/pysweepme/ pysweepme] and see the source code. |
Latest revision as of 11:30, 24 April 2024
SweepMe! supports and simplifies communication to devices via RS232/RS485 (COM port), GPIB, USB and TCPIP by using the SweepMe!'s Port manager.
Introduction
The communication with the hardware is usually done in each Device Class. In order to simplify the process of creating the communication channel, i.e. establish a connection, SweepMe! provides the port manager for easy handling.
Supported protocols
- COM: standard PC serial port using RS-232 or RS-485 protocol
- GPIB: a standardized communication/interface via an IEEE-488-Bus
- TCPIP: communication via a network, e.g. ethernet
- USB: plug and play USB test and measurement device as supported by pyvisa
- (VB: a National Instrument VirtualBench device -> deprecated from 1.5.5: please find and create port objects yourself)
Usage
Configuration
The following variables have to be set within the __init__ function of a Device Class:
In order to get the available ports listed in the GUI of the corresponding Module, choose desired port types by:
self.port_types = ["COM", "GPIB", "USB", "TCPIP"]
A port object is automatically created by
self.port_manager = True
Port properties
You can set port properties during __init__ of the Device Class or before connect() is called by modifying the self.port_properties dictionary. In order to see all keys of the dictionary, use
print(self.port_properties)
These parameters can be changed through
self.port_properties = {
"baudrate" : 9600,
"EOL": "\n",
...
}
or change a parameter of self.port_properties as done in the the following example
self.port_properties["EOL"] = "\r"
Some important and commonly used parameters are explained here:
Command | Interface | Type | Default value | Explanation |
---|---|---|---|---|
EOL | COM | String | "\n" | "End of line"-character, will be added to each command sent by self.port.write() and defines the end of each message read by self.port.read() |
EOLwrite | COM | String | None | replaces the character which will be added to each command sent by self.port.write() |
EOLread | COM | String | None | replace the character which defines the end of each message read by self.port.read() |
GPIB_EOLwrite | GPIB | String | None | sets the character which will be added to each command sent by self.port.write() |
GPIB_EOLread | GPIB | String | None | sets the character which defines the end of each message read by self.port.read() |
TCPIP_EOLwrite | TCPIP | String | None | sets the character which will be added to each command sent by self.port.write() |
TCPIP_EOLread | TCPIP | String | None | sets the character which defines the end of each message read by self.port.read() |
baudrate | COM | Integer | 9600 | The Baudrate defines the speed of the COM port communication, must be identical to the value of the instrument |
bytesize | COM | Integer | 8 | length of one byte, must be identical to value of the instrument |
stopbits | COM | Integer | 1 | |
parity | COM | String | "N" | None = "N", Odd = "O", Even = "E", Mark = "M", Space = "S" |
xonxoff | COM | Bool | False | |
rtscts | COM | Bool | False | |
dsrdtr | COM | Bool | False | |
rts | COM | Bool | True | |
dtr | COM | Bool | True | |
raw_write | COM | Bool | False | send the argument as is without further encoding, an eol/terminator-character is still added if specified. |
raw_read | COM | Bool | False | receive the answer as is without further decoding |
rstrip | COM | Bool | True | strips trailing characters such as whitespaces, line feeds, carriage return or tab character. |
timeout | COM, USB, GPIB | Float | 1.0 | time in seconds before a timeout error is raised |
clear | all | Bool | True | Send a clear command to the port after opening the port (SweepMe! 1.5.6.15+ / pysweepme 1.5.6.10+) |
delay | COM, GPIB | Float | 0.0 | delay time in seconds after writing a command to allow an instrument to process the current command. |
encoding | COM | String | 'latin-1' | encoding used to encode and decode byte based messages |
Exception | COM, GPIB, USB, TCPIP | bool | True | If an error occurs, the measurement is stopped. Set to False to be able to catch communications errors with try-except. |
Communication
If the port manager is activated, the port is automatically available within all functions of the sequencer procedure as the variable:
self.port
A message can be sent by using:
self.port.write("string of the message without end-of-line/terminator character")
The end-of-line character ("EOL") will be set by changing the port properties
The answer of a device is acquired by:
var = self.port.read()
The returned object is typically a string, so please do not forget to change the type if needed by using e.g. int() or float().
In case you need direct access to the port object created by the port manager, use:
self.port.port
Thus, you can use commmands as defined by pyserial for COM port communication or pyvisa for GPIB/USB communication.
For example, one can manipulate the termination character, e.g.:
self.port.port.write_termination = "\r\n"
self.port.port.read_termination = "\r\n"
# "\r\n" is here one example for using Carriage Return (CR) and Line Feed (LF) as terminator
However, it is recommended to do this using self.port_properties and the keys 'GPIB_EOLwrite' and 'GPIB_EOLread'. Otherwise, the solution only works for pyyvisa related GPIB port and would break when using other GPIB port such as the one created for a Prologix GPIB controller.
COM port
In order to check the number of already received bytes, you can use:
number_of_received_bytes = self.port.in_waiting()
As SweepMe! is based on python 3, all strings that are send via self.port.write() are actually unicode strings. The Port Manager automatically converts them to bytes before sending them using the library pyserial. Similarly, received bytes are automatically converted back to unicode strings. If you like to have raw access to the bytes that are sent and received, please use the port properties 'raw_read' and 'raw_write'.
Sometimes it is needed to only read the raw answers (i.e. bytes) of a few commands. In that case you can use the functions like 'read_raw' and 'write_raw'
self.port.write_raw(...) # make sure that you send a byte string
answer = self.port.read_raw() # answer will be a byte string that you need to decode or process yourself.
answer = self.port.read_raw(10) # example to read 10 bytes
Exceptions
If during port communication, an exception occurs, SweepMe! will stop the run and print the message in the Debug widget. If you like to catch the exception yourself, please add the key 'Exception' to the port properties and set it to 'False'.
self.port_properties = {
... # all other properties
"Exception": "False",
}
Then, you can use try-except to handle the exception, e.g. to send a command again if a checksum was incorrect or an instrument did not answer in the given timeout.
self.port.write("*IDN?")
try:
self.port.read() # We try to read the answer
except:
self.port.write("*IDN?") # If reading the answer fails, e.g. resulting in a timeout error, we write again to the instrument
self.port.read() # and we check the answer again. This example can be done multiple times in a loop if you like to implement multiple retries
}
pysweepme
The port manager of SweepMe! uses the module 'Ports' of the open-source pysweepme package. If you like to see how the exact communication is done, please feel free to download pysweepme and see the source code.