Server

pybarst.core.server

Creation of a channel or server instance does not result in extra process communication. However, instance methods does, and may therefore take significant time before the method returns.

The point is that the channel exists on the server, so deleting a client instance will not delete the channel from the server, even if no client is connected to the server.

Typical usage

you open and close with open_channel, close client/server.

class pybarst.core.server.BarstPipe(pipe_name='', timeout=None, **kwargs)

Bases: object

An abstract class that provides the client / server communication functionality. This base class should not be instantiated directly.

Parameters:
pipe_name: bytes

The name of the pipe used for client / server communication. Examples are \.\pipe\TestPipe for a local pipe named TestPipe or \Jace\pipe\TestPipe for a pipe named TestPipe on a remote computer named Jace.

timeout: int

The duration (in ms) to wait before returning with a timeout when opening the pipe. If zero or None, it defaults to pybarst.core.default_server_timeout in ms. Defaults to None.

pipe_name

pipe_name: bytes

The name of the pipe used to communicate with the server for the channel. See BarstPipe description. This is read only and is automatically set by the channel.

Note

Unicode pipe names are not currently supported.

timeout

timeout: ‘DWORD’

The amount of time to wait when connecting to the server before a timeout occurs. Defaults to default_server_timeout ms. This only effects the initial connection wait.

class pybarst.core.server.BarstServer(barst_path=None, curr_dir=None, write_size=None, read_size=None, max_server_size=-1, **kwargs)

Bases: pybarst.core.server.BarstPipe

The server class that controls and provides client based access to a remote server. A Barst server provides access to devices connected to the server’s system. Using a server client, a client can open, read/write, and close those channels in the server.

If the pipe name used to communicate with the server is local and a server with that name has not been created, a new server instance will be created on this system.

Multiple clients may connect safely to a single server. However, the server’s main pipe is single threaded, therefore, reading and writing to it can only be done by a single client at any time. So while a client is e.g. creating a new channel, other clients cannot create other channels. Once a channel is created, the channel gets its own pipe. A channel pipe is fully multithreaded allowing many clients to communicate with the channel at any time. See individual channels, e.g. FTDIChannel for details.

A server can control different device types. Before each device type can be created, a manager for it must be created on the server. For example, to create a serial port channel, one first creates the server’s serial manager using get_manager(). Then, using the manager one can create new serial channels. Typically, when a new channel instance is created, its manager is automatically created first. As mentioned, each new channel created gets its own pipe, leaving the server’s main pipe for channel creation/deletion.

Parameters:
barst_path: str

The full path to the Barst executable. It only needs to be provided when the server is local and has not been created yet. If None, we look for the executable in pybarst.dep_bins and then in Program Files\Barst\ (or the x86 program files if the server is 32-bit). Defaults to None. See barst_path for details.

curr_dir: str

The working directory of the server. See curr_dir for details. Defaults to None.

write_size: int

The size of the buffer used to write to the server’s main pipe. If None it defaults to 1024 bytes. Defaults to None. See write_size for details.

read_size: int

The size of the buffer used to read from the server’s main pipe. If None it defaults to 1024 bytes. Defaults to None. See read_size for details.

max_server_size: 64-bit integer

The maximum number of bytes that the server can queue to send to clients at any time, if not -1. Defaults to -1. See max_server_size.

Warning

In cases where messages to/from the server’s main pipe are larger than 1024 bytes, the buffer sizes should be enlarged. Windows might return an error saying that all data could not be read if the buffer is too small. Channel pipe are guaranteed to be large enough to hold the data required for reading/writing, only the server’s main pipe size can not be predicted.

barst_path

barst_path: object

The full path to the Barst binary. When the server doesn’t exist yet, we launch a server instance using this binary when open_server() is called. barst_path is a string, defaults to ‘’.

clock(self)

Returns the current server time using a high precision clock on the server.

The server has a single global high precision clock that it uses for time stamping data. All channels pass some data from/to the server. For example, the MCDAQChannel channel can read and write to the channel. Each read/write is time stamped by the server with the time it occurred. This method returns the current time as measured using that clock.

Returns:a 2-tuple of (server_time, utc_time).
server_time: double
The current server time measured using the high precision clock. This clock starts running when the server is created. This is the clock used to time stamp data sent by the server.
utc_time: double
The current utc time measured by the server’s system. This clock is much less precise/accurate. By calling this many times, one can correlate time between the server time, utc time, and the time of a clients system. For example, one can call it repeatedly to try to find on average what time on a clients system corresponds to a particular time stamp of the server.

The value represents the number of second that has passed since 12:00 A.M. January 1, 1601 Coordinated Universal Time (UTC). This is commonly called Windows file time (http://msdn.microsoft.com/en-us/library/windows/desktop/ms724284%28v=vs.85%29.aspx).

For example:

>>> import time
>>> server = BarstServer(barst_path=path, pipe_name=r'\\.\pipe\TestPipe')
>>> server.open_server()
>>> print(server.clock())
(0.027729689422222512, 13045704696.357197)
>>> print(server.clock())
(0.02788367253417604, 13045704696.357197)
>>> time.sleep(1.5)
>>> print(server.clock())
(1.528171928919753, 13045704697.857283)
close_manager(self, str manager)

Closes a manager. If the manager has not been created yet by this instance of the server’s client, we will create the manager and then close it. The reason is that another client elsewhere could have created the manager, even if it has not been created locally. So we need to ensure we close it on the server.

If the manager had any open channels, those channels will also be closed by the server.

close_server(self)

Notifies the server to shut down.

Shuts down the server and all its open managers and channels. Afterwards, the server process should have closed. To open the server again, call open_server().

connected

connected: ‘int’

Whether the instance opened it’s connection with the server. If False, open_server() must be called. Closing the server sets this to False. Read only.

curr_dir

curr_dir: object

When we launch the binary at barst_path, which creates the server, curr_dir is the directory used by the binary as the current directory. Defaults to barst_path if None or empty.

get_manager(self, str manager)

Creates a manager in the server if it has not been created yet.

As described in the class description, a server is constructed from a single main pipe through which you create managers which in turn manage and create specific channels, e.g. a serial port channel. Once the manager is created, we can create channels using that driver. By default, creating a channel will automatically create its manager.

For example:

>>> server = BarstServer(barst_path=r'path_to_barst',
... pipe_name=r'\\.\pipe\TestPipe')
>>> print(server)
<pybarst.barst_core.BarstServer object at 0x02C77F30>
>>> print(server.get_version())
20000
>>> print(server.get_manager('ftdi'))
{'version': 197127L, 'chan': 0, 'chan_id': 'FTDIMan'}
Parameters:
manager: str

The name of the manager to create. Can be one of ‘ftdi’, ‘rtv’, ‘serial’, or ‘mcdaq’.

Returns:

a dict describing the manager. See managers.

get_version(self) → DWORD

Returns Barst’s version.

Returns:int. The version in the form where e.g. 10000 means 1.00.00.
managers

managers: dict

A dictionary containing the managers opened with this server instance. Other managers can be open on the server, even if not contained here. Read only. See get_manager().

For example, after the FTDI manager is opened:

>>> server.open_server()
>>> server.get_manager('ftdi')
>>> print(server.managers)
{'ftdi': {'version': 197127L, 'chan': 0, 'chan_id': 'FTDIMan'}}

For each manager, the values in the dict is:

version: int
The version of that manager’s driver.
chan: int
The channel number of the manager in the server.
chan_id: str
The string ID given to that manager by barst.
max_server_size

max_server_size: ‘long long’

The maximum number of bytes that the server can queue to send to clients at any time. If -1, it’s unlimited. There are many channels which when requested, the server will continuously send data to clients, e.g. RTV channels. When -1, if the client never reads, the server will still continuously queue more data, exhausting its RAM after some time. Using this value, once the server has exceeded max_server_size bytes in its queue, new data waiting to be sent will simply be discarded.

Note

This is a global server wide value. That is, the write queues of all the channels are combined when checking if the size is too large. Therefore, once exceeded, no channel will be able to send data to a client until the client resolves the waiting data. Also, while some channels will resume sending data once the value is not exceeded anymore, other channels might disable their pipes. So once exceeded, the server should be thought of as being in a unrecoverable error state.

open_server(self)

Opens the server with the settings specified when creating the BarstServer instance. If a server with this pipe name doesn’t exist yet, one will be created, provided the pipe is local and barst_path was provided.

read_size

read_size: ‘DWORD’

The maximum buffer size used by the client for reading from the server’s main pipe. The default value should be large enough for all the messages, however, if there errors indicating that the whole messages was not read, this value should be increased.

Note

The value only affects the server’s main pipe, not the pipes of the individual channels. Individual channels will always create pipes large enough for their data. If there are issues, errors would arise when creating/opening a channel. This parameter is only used when the server is launched by the client, not when the server already exists.

write_size

write_size: ‘DWORD’

The maximum buffer size used by the client for writing to the server’s main pipe. The default value should be large enough for all the messages, however, if there errors indicating that the whole messages was not written, this value should be increased.

Note

The value only affects the server’s main pipe, not the pipes of the individual channels. Individual channels will always create pipes large enough for their data. If there are issues, errors would arise when creating/opening a channel. This parameter is only used when the server is launched by the client, not when the server already exists.

class pybarst.core.server.BarstChannel

Bases: pybarst.core.server.BarstPipe

An abstract representation class of a client connected to a channel on the server. This class is never instantiated directly.

See derived classes, e.g. RTVChannel for examples.

The class provides methods commonly used by the client classes.

barst_chan_type

barst_chan_type: str

The string ID given to the channel type by the server. Each channel type has a unique string assigned by barst. Read only.

cancel_read(self, flush=False)

Cancels a continuous read.

This method is only implemented for for the classes that indicate that e.g. MCDAQChannel. For other classes, it doesn’t do anything.

Some classes offer an option where the server continuously sends data read back to the client. For those classes, one can stop the read operation by setting the state to inactive with set_state(), which will affect all the clients connected, or by calling this method. With this method, the read operation is only canceled for this client.

Parameters:
flush: bool

Whether any data already waiting to be read by the client will be discarded. This forces a disconnection and reconnection with the server for this client. flush defaults to False.

After canceling, the server will not queue any new data to be sent to the client. However, the server might have already queued data to be sent to the client. This parameter controls whether that data will sill be sent.

If flush is False, that data will be available to the client when it calls read, until the server has no more data available and read will then return an error once. Calling read after the error, will trigger the server to start sending new data again.

If flush is True, then all data waiting to be sent will be discarded. In addition, no error will be raised upon a subsequent call to read, but instead it will trigger the server to start sending data to the client again.

Note

Calling this method while a read operation is not ongoing may result in an exception.

chan

chan: ‘int’

The channel number assigned to this channel by the server. For example, an FTDI channel may be one channel among many in the FTDI manager - each channel gets its own channel number. Read only.

close_channel_client(self)

Closes this client’s connection to the channel without affecting the channel on the server. Other clients are not affected by this.

After this is called, the channel will still exist on the server, but this instance won’t be connected to it. Therefore, calling other channel methods will likely raise an exception until open_channel() is called again.

If a class method, e.g. a read or write operation got stuck communicating with the server, calling this method from another thread will force the waiting method to return, possibly with an error.

close_channel_server(self)

Closes the channel on the server. This deletes the channel from the server. Therefore any other clients that may be connected to the channel will return an error when they try to communicate with it after this method has been called.

This method internally also calls close_channel_client().

To only close the connection of this client without affecting the state of the channel on the server, call close_channel_client().

connected

connected: ‘int’

Whether the instance opened it’s connection with the server. If False, open_channel() must be called. Closing the channel sets this to False. Read only.

open_channel(self)

Opens the client’s connection to this channel on the server. If the channel doesn’t exist yet it creates it first, otherwise it just opens a new client for the channel.

Before any other operations can be done on the channel, this method must be called.

All channels are designed such that when the class instance is created, no client/server communication occurs. Then, to actually create/open the channel, this method must be called.

Similarly, after closing a channel with close_channel_server() or close_channel_client() one can recreate or reopen the client’s connection to the channel using this method.

parent_chan

parent_chan: ‘int’

The channel number of this channel’s parent, e.g. if this is a FTDI channel then it’s parent channel is the FTDI manager and this value will represent the FTDI manager’s channel number in the server. Read only.

server

server: pybarst.core.server.BarstServer

A BarstServer instance in which this channel exists / will exist.

set_state(self, int state, flush=False)

Sets the state of the channel to active or inactive (True or False). The activation state of a channel is global, and therefore affects all the clients of a channel.

For most channels, after the channel is created on the server with open_channel(), before you can read/write to it, the channel must be activated. Because the state is global, once activated, further clients opening the channel will already be in a activate state.

Similarly, to stop an active channel from reading or writing data, you set the channel into an inactive state. Typically, the channel uses less resource when inactive because e.g. sampling is disabled etc. so it is preferred to deactivate channels that are not used. Again, once deactivated, the channel will be inactive for all the clients.

When deactivating, all the read or write requests being performed will be canceled. Also, reading or writing data to an inactive channel will result in an error. Typically, one sets the state to active/inactive in cycles as they are needed.

Parameters:
state: bool

The state to set the channel in. Can be either True for activation and False for inactivation.

flush: bool

Whether any data waiting to be sent, or read by the client will be discarded. This forces a disconnection and reconnection with the server for this client.

Typically, this is only used for channels that continuously send data back to clients, e.g. RTVChannel. Always, when deactivating, the server will not queue any new data to be sent to a client. However, the server might have already queued data to be sent to the client. This parameter controls whether that data will sill be sent.

If flush is False, that data will be available to the client when it calls read, until the server has no more data available and read will return an error. For channels that support that, the channel will only be considered inactive after the last read once that error is raised.

If flush is True, then all data waiting to be sent will be discarded. In addition, the channel will instantly become inactive. If the channel is in a read or write, then that method will return with an exception.

flush is only used when state is False. flush defaults to False.

See cancel_read() for an alternative method to cancel ongoing server reads.