Skip to content

Commit

Permalink
Merge c7347f0 into efe3f4e
Browse files Browse the repository at this point in the history
  • Loading branch information
lilesj committed Sep 25, 2018
2 parents efe3f4e + c7347f0 commit e261e29
Show file tree
Hide file tree
Showing 7 changed files with 174 additions and 10 deletions.
2 changes: 2 additions & 0 deletions docs/examples.rst
Original file line number Diff line number Diff line change
Expand Up @@ -15,3 +15,5 @@ Examples
examples/can_lin_diff
examples/programmatic_databases
examples/dynamic_database_creation
examples/generic_synchronization

25 changes: 25 additions & 0 deletions docs/examples/generic_synchronization.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
Generic Synchronization Example
===============================

This example demonstrates how to synchronize two :any:`nixnet.session.FrameInStreamSession`
session types on different interfaces.

These principles can be extended to any session type and quantity.
Sessions are created, configured, and started for each interface sequentially.

The interfaces that will listen for a clock should be created and configured first.
Interface properties need only be set once per interface. The connect_terminals function
acts like an interface property and needs to be set only once per interface. Listening
sessions can then be started with the "Session Only" scope. The last session to be started
on a particul interface can be started with the normal scope which will cause it to start
listening for a start trigger.

The interface that will drive the master timebase clock should be created and configured
last. The master timebase is configured to be output via connect_terminals and then the
interface can be started with normal scope.

Generic Synchronization
-----------------------

.. literalinclude:: ../../nixnet_examples/generic_synchronization.py
:pyobject: main
24 changes: 24 additions & 0 deletions nixnet/_enums.py
Original file line number Diff line number Diff line change
Expand Up @@ -2209,3 +2209,27 @@ class FrameType(enum.Enum):
SPECIAL_DELAY = _cconsts.NX_FRAME_TYPE_SPECIAL_DELAY
SPECIAL_LOG_TRIGGER = _cconsts.NX_FRAME_TYPE_SPECIAL_LOG_TRIGGER
SPECIAL_START_TRIGGER = _cconsts.NX_FRAME_TYPE_SPECIAL_START_TRIGGER


class Terminal(enum.Enum):
"Terminals to import/export from the XNET device"
FRONTPANEL_0 = _cconsts.NX_TERM_FRONT_PANEL0
FRONTPANEL_1 = _cconsts.NX_TERM_FRONT_PANEL1
PXI_TRIG_0 = _cconsts.NX_TERM_PXI_TRIG0
PXI_TRIG_1 = _cconsts.NX_TERM_PXI_TRIG1
PXI_TRIG_2 = _cconsts.NX_TERM_PXI_TRIG2
PXI_TRIG_3 = _cconsts.NX_TERM_PXI_TRIG3
PXI_TRIG_4 = _cconsts.NX_TERM_PXI_TRIG4
PXI_TRIG_5 = _cconsts.NX_TERM_PXI_TRIG5
PXI_TRIG_6 = _cconsts.NX_TERM_PXI_TRIG6
PXI_TRIG_7 = _cconsts.NX_TERM_PXI_TRIG7
FRONT_PANEL_0 = _cconsts.NX_TERM_FRONT_PANEL0
FRONT_PANEL_1 = _cconsts.NX_TERM_FRONT_PANEL1
PXI_STAR = _cconsts.NX_TERM_PXI_STAR
PXI_CLK_10 = _cconsts.NX_TERM_PXI_CLK10
TIMEBASE_10_MHZ = _cconsts.NX_TERM_10_M_HZ_TIMEBASE
TIMEBASE_1_MHZ = _cconsts.NX_TERM_1_M_HZ_TIMEBASE
TIMEBASE_MASTER = _cconsts.NX_TERM_MASTER_TIMEBASE
COMM_TRIGGER = _cconsts.NX_TERM_COMM_TRIGGER
START_TRIGGER = _cconsts.NX_TERM_START_TRIGGER
LOG_TRIGGER = _cconsts.NX_TERM_LOG_TRIGGER
16 changes: 8 additions & 8 deletions nixnet/_session/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -286,7 +286,7 @@ def wait_for_intf_remote_wakeup(self, timeout=10):
_funcs.nx_wait(self._handle, constants.Condition.INTF_REMOTE_WAKEUP, 0, timeout)

def connect_terminals(self, source, destination):
# type: (typing.Text, typing.Text) -> None
# type: (constants.Terminal, constants.Terminal) -> None
"""Connect terminals on the XNET interface.
This function connects a source terminal to a destination terminal on
Expand All @@ -301,13 +301,13 @@ def connect_terminals(self, source, destination):
pair is an internal and the other an external.
Args:
source(str): Connection source name.
destination(str): Connection destination name.
source(constants.Terminal): Connection source name.
destination(constants.Terminal): Connection destination name.
"""
_funcs.nx_connect_terminals(self._handle, source, destination)
_funcs.nx_connect_terminals(self._handle, source.value, destination.value)

def disconnect_terminals(self, source, destination):
# type: (typing.Text, typing.Text) -> None
# type: (constants.Terminal, constants.Terminal) -> None
"""Disconnect terminals on the XNET interface.
This function disconnects a specific pair of source/destination terminals
Expand All @@ -331,10 +331,10 @@ def disconnect_terminals(self, source, destination):
Attempting to disconnect a nonconnected terminal results in an error.
Args:
source(str): Connection source name.
destination(str): Connection destination name.
source(constants.Terminal): Connection source name.
destination(constants.Terminal): Connection destination name.
"""
_funcs.nx_disconnect_terminals(self._handle, source, destination)
_funcs.nx_disconnect_terminals(self._handle, source.value, destination.value)

def change_lin_schedule(self, sched_index):
# type: (int) -> None
Expand Down
99 changes: 99 additions & 0 deletions nixnet_examples/generic_synchronization.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
from __future__ import absolute_import
from __future__ import division
from __future__ import print_function

import six
import time


import nixnet
from nixnet import constants
from nixnet import types


def main():
interface1 = 'CAN1'
interface2 = 'CAN2'

# Create the sessions. ExitStack() can be used for high session counts
with nixnet.FrameInStreamSession(interface1) as interface1_input:
with nixnet.FrameInStreamSession(interface2) as interface2_input:
with nixnet.FrameOutStreamSession(interface2) as interface2_output:
# Set session and interface properties such as termination
# Note that interface properties only need to be set once per interface
interface1_input.intf.baud_rate = 125000
interface1_input.intf.can_term = constants.CanTerm.ON

# Connect the start trigger terminals for the listening interface
interface1_input.connect_terminals(constants.Terminal.PXI_TRIG_0, constants.Terminal.START_TRIGGER)

# Start the listening interface sessions
interface1_input.start()

# Set session and interface properties such as termination
# Note that interface properties only need to be set once per interface
interface2_input.intf.baud_rate = 125000
interface2_input.intf.can_term = constants.CanTerm.ON
interface2_input.intf.echo_tx = True

# Connect the start trigger terminals for the interface driving the start trigger
interface2_input.connect_terminals(constants.Terminal.START_TRIGGER, constants.Terminal.PXI_TRIG_0)

# Starting the sessions on the driving interface will trigger the start of the listening sessions
interface2_input.start(constants.StartStopScope.SESSION_ONLY)
interface2_output.start()

# Request values to transmit from user
user_value = six.moves.input('Enter payload [int, int, ...]: ')
try:
payload_list = [int(x.strip()) for x in user_value.split(",")]
except ValueError:
payload_list = [2, 4, 8, 16]
print('Unrecognized input ({}). Setting data buffer to {}'.format(user_value, payload_list))

id = types.CanIdentifier(1)
payload = bytearray(payload_list)
frame = types.CanFrame(id, constants.FrameType.CAN_DATA, payload)

print('The same values should be received. Press q to quit')
i = 0
while True:
# Apply the user input to the frame payload
for index, byte in enumerate(payload):
payload[index] = byte + i

frame.payload = payload
# Write the specified frame to the bus
interface2_output.frames.write([frame])
print('Sent frame with ID {} payload: {}'.format(id, payload))

time.sleep(0.2)

# Read frames back from both input sessions
frames_to_read = 1
received_frames = interface1_input.frames.read(frames_to_read)
echoed_frames = interface2_input.frames.read(frames_to_read)
rx_frame_list = list(received_frames)
echo_frame_list = list(echoed_frames)
for frame in rx_frame_list:
print('Received frame: {}'.format(rx_frame_list[0]))
print(' payload={}'.format(list(six.iterbytes(rx_frame_list[0].payload))))
print('Echoed frame: {}'.format(echo_frame_list[0]))
print(' payload={}'.format(list(six.iterbytes(echo_frame_list[0].payload))))

# Subtract the timestamp from first frame in each list to obtain delta
delta_t = rx_frame_list[0].timestamp - echo_frame_list[0].timestamp
print('The delta between received timestamp and echo is: {}', delta_t)

i += 1
if max(payload) + i > 0xFF:
i = 0
inp = six.moves.input('Hit enter to continue (q to quit): ')
if inp.lower() == 'q':
break

print('Data acquisition stopped.')


if __name__ == '__main__':
main()
14 changes: 14 additions & 0 deletions tests/test_examples.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
from nixnet_examples import can_frame_stream_io
from nixnet_examples import can_signal_conversion
from nixnet_examples import can_signal_single_point_io
from nixnet_examples import generic_synchronization
from nixnet_examples import lin_dynamic_database_creation
from nixnet_examples import lin_frame_stream_io
from nixnet_examples import programmatic_database_usage
Expand Down Expand Up @@ -42,6 +43,8 @@
MockXnetLibrary.nxdb_close_database.return_value = _ctypedefs.u32(0)
MockXnetLibrary.nxdb_create_object.return_value = _ctypedefs.u32(0)
MockXnetLibrary.nxdb_set_property.return_value = _ctypedefs.u32(0)
MockXnetLibrary.nx_connect_terminals.return_value = _ctypedefs.u32(0)
MockXnetLibrary.nx_disconnect_terminals.return_value = _ctypedefs.u32(0)


def six_input(queue):
Expand Down Expand Up @@ -161,3 +164,14 @@ def test_lin_frame_stream_empty_session(input_values):
def test_programmatic_database_usage(input_values):
with mock.patch('six.moves.input', six_input(input_values)):
programmatic_database_usage.main()


@pytest.mark.parametrize("input_values", [
['1, 2', 'q'],
['255, 0', 'q'],
])
@mock.patch('nixnet._cfuncs.lib', MockXnetLibrary)
@mock.patch('time.sleep', lambda time: None)
def test_generic_synchronization(input_values):
with mock.patch('six.moves.input', six_input(input_values)):
generic_synchronization.main()
4 changes: 2 additions & 2 deletions tests/test_session.py
Original file line number Diff line number Diff line change
Expand Up @@ -445,7 +445,7 @@ def test_connect_terminals_failures(can_in_interface):
cluster_name,
frame_name) as input_session:
with pytest.raises(errors.XnetError) as excinfo:
input_session.connect_terminals("FrontPanel0", "FrontPanel1")
input_session.connect_terminals(constants.Terminal.FRONT_PANEL_0, constants.Terminal.FRONT_PANEL_1)
assert excinfo.value.error_type in [
constants.Err.SYNCHRONIZATION_NOT_ALLOWED,
constants.Err.INVALID_SYNCHRONIZATION_COMBINATION]
Expand All @@ -464,7 +464,7 @@ def test_disconnect_terminals_failures(can_in_interface):
cluster_name,
frame_name) as input_session:
with pytest.raises(errors.XnetError) as excinfo:
input_session.disconnect_terminals("FrontPanel0", "FrontPanel1")
input_session.disconnect_terminals(constants.Terminal.FRONT_PANEL_0, constants.Terminal.FRONT_PANEL_1)
assert excinfo.value.error_type in [
constants.Err.SYNCHRONIZATION_NOT_ALLOWED,
constants.Err.INVALID_SYNCHRONIZATION_COMBINATION]

0 comments on commit e261e29

Please sign in to comment.