Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(API): Support lin_sched #142

Merged
merged 4 commits into from Aug 11, 2017
Merged

feat(API): Support lin_sched #142

merged 4 commits into from Aug 11, 2017

Conversation

bcornish
Copy link
Contributor

@bcornish bcornish commented Jul 25, 2017

  • This contribution adheres to CONTRIBUTING.md.
  • New tests have been created for any new features or regression tests for bugfixes.
  • tox successfully runs, including unit tests and style checks (see CONTRIBUTING.md).
  • Document example
  • Integration tests: refactor can frame parameters
  • Add integration tests: lin frame

What does this Pull Request accomplish?

Added read and write frame for LIN. Added LIN frame object.

Why should this Pull Request be merged?

Stepping stone for LIN support.

What testing has been done?

Doc tests only

@bcornish bcornish requested a review from epage July 25, 2017 23:13
@coveralls
Copy link

Coverage Status

Coverage increased (+0.02%) to 63.99% when pulling b1dfd76 on bcornish:linframe into 6af98b1 on ni:master.

1 similar comment
@coveralls
Copy link

coveralls commented Jul 25, 2017

Coverage Status

Coverage increased (+0.02%) to 63.99% when pulling b1dfd76 on bcornish:linframe into 6af98b1 on ni:master.

Copy link
Contributor

@epage epage left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for getting this together. Overall, it looks good!

def read_lin(
self,
number_to_read,
timeout=constants.TIMEOUT_NONE):
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please apply a type annotation

I'm guessing it'd be

# type: (int, float) -> typing.Iterable[types.LinFrame]

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ditto for all other functions

nixnet/types.py Outdated
payload: A byte string representing the payload.
eventid: Identifier for an event-triggered slot.
eventslot: A boolean indicating whether the frame was received within an
event-triggered slot or an unconditional or sporadic slot.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please document the expected type for each of these

nixnet/types.py Outdated

_FRAME_ID_MASK = 0x000000FF

def __init__(self, identifier, type, eventid=b"", payload=b""):
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why do you default eventid to a bytestring here but pass in an int elsewhere? What should its type be?

(also, this is the failure that Travis caught)

nixnet/types.py Outdated
eventid=0x0, eventslot=False, payload=...)
"""
return """LinFrame(identifier=0x{:x}, echo={}, type={}, timestamp=0x{:x},
eventid=0x{:x}, eventslot={}, payload=...)""".format(
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should probably not have a multi-line repr

nixnet/types.py Outdated
"eventslot",
"payload"]

_FRAME_ID_MASK = 0x000000FF
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this mask correct?

When Type specifies a LIN frame, this element contains a number in the range 0–63 (inclusive). This number is the LIN frame's ID (unprotected).

http://zone.ni.com/reference/en-XX/help/372841L-01/nixnet/rawframeformat_c/

nixnet/types.py Outdated
lin_frame = LinFrame(identifier, constants.FrameType(frame.type), frame.payload)
lin_frame.timestamp = frame.timestamp
lin_frame.echo = bool(frame.flags & _cconsts.NX_FRAME_FLAGS_TRANSMIT_ECHO)
lin_frame.eventid = frame.info
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Shouldn't you only read from frame.info if eventslot is true?

For LIN frames, if bit 0 of the Flags element is clear, the Info element is unused (0). If bit 0 of the Flags element is set (event-triggered entry), the Info element contains the event-triggered frame ID, and the Identifier element contains the Unconditional ID from the first payload byte.

nixnet/types.py Outdated
"timestamp",
"eventid",
"eventslot",
"payload"]
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reading the documentation, it seems like eventslot impacts the meaning of identifier and eventid

We should at least re-order it so eventslot is always referenced before eventsid to communicate this. I'd suggest putting it before identifier but that'll mess up __init__s defaulting of parameters.

http://zone.ni.com/reference/en-XX/help/372841L-01/nixnet/rawframeformat_c/

nixnet/types.py Outdated
self.type = type
self.timestamp = 0 # Used only for Read
self.eventid = eventid # Used only for Read
self.eventslot = False # Used only for Read
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

eventid is allowed to be passed in but not eventslot? If eventid has anything, then eventslot should be True.

Maybe not include eventid in the parameter list and hard code it to None so that it works well for people creating a LinFrame for writing (where they'll want a payload)

@epage
Copy link
Contributor

epage commented Jul 26, 2017

Note: I made fixes to __eq__ and __ne__ in #143. Please reflect this in your PR.

@coveralls
Copy link

coveralls commented Jul 28, 2017

Coverage Status

Coverage increased (+0.09%) to 64.327% when pulling 2bcbf0f on bcornish:linframe into 13a2757 on ni:master.

@epage
Copy link
Contributor

epage commented Jul 28, 2017

./nixnet/__init__.py:10:1: F403 'from nixnet.session import *' used; unable to detect undefined names
from nixnet.session import *  # NOQA: F401, F403
^
ERROR: InvocationError: '/home/travis/build/ni/nixnet-python/.tox/flake8/bin/flake8'

I submitted a PR that should fix that. Rebase and re-push.

Also, when you rewrite the history for your PR, we don't get a notification on push so you'll have to let us know when there are changes you want us to look over.

@coveralls
Copy link

coveralls commented Jul 28, 2017

Coverage Status

Coverage increased (+0.09%) to 64.327% when pulling ef41eb8 on bcornish:linframe into cce79f2 on ni:master.

@bcornish
Copy link
Contributor Author

Rebased and repushed as requested.

nixnet/types.py Outdated
@@ -6,6 +6,8 @@
import collections
import typing # NOQA: F401

# flake8: NOQA: E501

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should isolate suppressions to the lines they impact

  1. So we know if they can be removed
  2. So we still get reports on other lines

@@ -222,7 +222,7 @@ def write(
frames,
timeout=10):
# type: (typing.Iterable[types.Frame], float) -> None
"""Write raw CAN frame data.
"""Write raw CAN or LIN frame data.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Most of these comments are out of date, sorry for that.

Please change them to be "Read frames" (no reference to "raw", "CAN", or "LIN").

nixnet/types.py Outdated
}.get(frame.type)
if frame_type is None:
raise NotImplementedError("Unsupported frame type", frame.type)
return frame_type.from_raw(frame)


class LinFrame(object):
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Organizationally, I'd move LinFrame before the XnetFrame

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I moved LinFrame before XnetFrame and all of the special frames.

nixnet/types.py Outdated
@@ -388,7 +391,115 @@ def from_raw(cls, frame):
constants.FrameType.CANFD_DATA: CanFrame,
constants.FrameType.CANFDBRS_DATA: CanFrame,
constants.FrameType.CAN_REMOTE: CanFrame,
constants.FrameType.LIN_DATA: LinFrame,
constants.FrameType.LIN_BUS_ERROR: LinFrame,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looking at the documentation for LIN_BUS_ERROR, it seems like we should create a custom frame for it.
http://zone.ni.com/reference/en-XX/help/372841L-01/nixnet/specialframes_c/

Like CAN, it might be reasonable to defer it.

nixnet/types.py Outdated
@@ -388,7 +391,115 @@ def from_raw(cls, frame):
constants.FrameType.CANFD_DATA: CanFrame,
constants.FrameType.CANFDBRS_DATA: CanFrame,
constants.FrameType.CAN_REMOTE: CanFrame,
constants.FrameType.LIN_DATA: LinFrame,
constants.FrameType.LIN_BUS_ERROR: LinFrame,
constants.FrameType.LIN_NO_RESPONSE: LinFrame,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Where is LIN_NO_RESPONSE documented? Trying to decide if it makes sense to map it to a LinFrame

Copy link
Contributor Author

@bcornish bcornish Jul 31, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's also a special frame:
http://zone.ni.com/reference/en-XX/help/372841N-01/nixnet/specialframes/

Should it be deferred with the rest of the special frame types?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Didn't scroll far enough :)

Let's defer it to a future PR.

@coveralls
Copy link

coveralls commented Aug 2, 2017

Coverage Status

Coverage increased (+0.08%) to 65.235% when pulling 8a2c948 on bcornish:linframe into e1bf22e on ni:master.

@epage
Copy link
Contributor

epage commented Aug 2, 2017

Thinking some more about it, if you add equality tests and increased your to/from raw coverage, this becomes sufficiently tested for what is being added that we might be able to submit it now.

(these tests will need to be added anyways).

nixnet/types.py Outdated
else:
return NotImplemented

def __repr__(self):
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

FYI in #170, I changed the other frame reprs based on feedback.

@bcornish
Copy link
Contributor Author

bcornish commented Aug 8, 2017

Added lin_sched and diagnostic_lin_sched functions. Submitting updates to reprs and equality tests in separate commits.

@coveralls
Copy link

coveralls commented Aug 8, 2017

Coverage Status

Coverage increased (+0.03%) to 64.204% when pulling 3fcdedb on bcornish:linframe into 5590c92 on ni:master.

1 similar comment
@coveralls
Copy link

Coverage Status

Coverage increased (+0.03%) to 64.204% when pulling 3fcdedb on bcornish:linframe into 5590c92 on ni:master.

Copy link
Contributor

@epage epage left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Glad to see how well you were able to look at the other code and API and figure out what to do

@@ -335,6 +335,37 @@ def disconnect_terminals(self, source, destination):
"""
_funcs.nx_disconnect_terminals(self._handle, source, destination)

def write_state_lin_schedule_change(self, state_value):
# type: () -> None
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

# type: (typing.Text) -> None

because it cannot change to master while running.

Args:
state_value(str): Writes the desired state.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You have state_value documented as a str but the nxWriteState documentation says that it is an int`

http://zone.ni.com/reference/en-XX/help/372841L-01/nixnet/nxwritestate/

Args:
state_value(str): Writes the desired state.
"""
_funcs.nx_write_state(self._handle, constants.WriteState.LIN_SCHEDULE_CHANGE, state_value)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nx_write_state is expecting state_value to be to one of the types defined in _ctypedefs.

So

_funcs.nx_write_state(self._handle, constants.WriteState.LIN_SCHEDULE_CHANGE, _ctypedefs.u32(state_value))


Args:
state_value(str): Writes the desired state.
"""
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

state_value(str): Writes the desired state.

I feel like the parameter name and documentation could be improved.

From the nxWriteState documentation

index to the schedule table that the LIN master executes. The schedule tables are sorted the way they are returned from the database with the XNET Cluster Schedules property.

So my recommendation

sched_index(int): Index to the schedule table that the LIN master executes.

    The schedule tables are sorted the way they are returned from the database with the XNET Cluster Schedules property.

_funcs.nx_write_state(self._handle, constants.WriteState.LIN_SCHEDULE_CHANGE, state_value)

def write_state_lin_diagnostic_schedule_change(self, state_value):
# type: () -> None
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

# type: (constants.LinDiagnosticSchedule) -> None

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also, since this will be using a yet-to-be-documented enum, this change should also include documenting the enum.

You can take the documentation from nxWriteState for the values and document the LinDiagnosticSchedule class similarly to how we documented the other enums.

Args:
state_value(str): Writes the desired state.
"""
_funcs.nx_write_state(self._handle, constants.WriteState.LIN_DIAGNOSTIC_SCHEDULE_CHANGE, state_value)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ditto about making it a u32

_ctypedefs.u32(state_value.value)
(.value to convert from enum to int)

the diagnostic schedule.

Args:
state_value(str): Writes the desired state.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Again, I think we can do better about the parameter name. One reason this is important is the parameter names are part of the API definition and changing them breaks compatibility

For example, you can do

session.write_state_lin_diagnostic_schedule_change(state_value=constants.NULL)

From reading the documentation, my recommendation

schedule(:any:`nixnet._enums.LinDiagnosticSchedule`):  diagnostic schedule that the LIN master executes

@@ -335,6 +335,37 @@ def disconnect_terminals(self, source, destination):
"""
_funcs.nx_disconnect_terminals(self._handle, source, destination)

def write_state_lin_schedule_change(self, state_value):
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Like the other functions, I don't think we need "write_state" in the name.

So the question is what is a name that makes sense for just this function?

Would change_lin_schedule work?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

change_lin_schedule makes sense and still conveys the essence of the function (at least from my understanding of it). @lilesj any thoughts?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

change_lin_schedule or something similar sounds good to me.

"""
_funcs.nx_write_state(self._handle, constants.WriteState.LIN_SCHEDULE_CHANGE, state_value)

def write_state_lin_diagnostic_schedule_change(self, state_value):
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Like the other functions, I don't think we need "write_state" in the name.

So the question is what is a name that makes sense for just this function?

Would change_lin_diagnostic_schedule work? My main concern is that is a similar name to change_lin_schedule but they take completely different types of parameters.

bcornish added a commit to bcornish/nixnet-python that referenced this pull request Aug 8, 2017
Related to ni#142

Updated repr and added equality tests
@epage epage mentioned this pull request Aug 8, 2017
3 tasks
bcornish added a commit to bcornish/nixnet-python that referenced this pull request Aug 9, 2017
Add linframe in types ni#142

Added coverage

Add LinFrame equality test
bcornish added a commit to bcornish/nixnet-python that referenced this pull request Aug 9, 2017
Add linframe in types ni#142

Added more test coverage

Added LinFrame equality test
@coveralls
Copy link

coveralls commented Aug 11, 2017

Coverage Status

Coverage decreased (-0.06%) to 64.447% when pulling d1f7cf9 on bcornish:linframe into 67976b6 on ni:master.

@bcornish
Copy link
Contributor Author

The addition of LIN examples looks like it's going to require a slight restructuring of the examples.rst so that the CAN and LIN examples are clearly differentiated and can have their own headers. Thoughts?

@coveralls
Copy link

coveralls commented Aug 11, 2017

Coverage Status

Coverage increased (+0.5%) to 65.033% when pulling cd67ed0 on bcornish:linframe into 67976b6 on ni:master.

@epage epage changed the title feat(API): Implement reading and writing LIN frames feat(API): Support lin_sched Aug 11, 2017
@epage
Copy link
Contributor

epage commented Aug 11, 2017

The addition of LIN examples looks like it's going to require a slight restructuring of the examples.rst so that the CAN and LIN examples are clearly differentiated and can have their own headers. Thoughts?

Was this question from before we talked in person and I suggested us having the CAN/LIN examples in the same files?

Yep. You answered my questions for next steps on this.

@coveralls
Copy link

coveralls commented Aug 11, 2017

Coverage Status

Coverage increased (+0.5%) to 65.033% when pulling 7d25789 on bcornish:linframe into 67976b6 on ni:master.

@coveralls
Copy link

coveralls commented Aug 11, 2017

Coverage Status

Coverage increased (+0.5%) to 65.033% when pulling 3b1fef9 on bcornish:linframe into 67976b6 on ni:master.

@coveralls
Copy link

coveralls commented Aug 11, 2017

Coverage Status

Coverage increased (+0.5%) to 65.033% when pulling 215b767 on bcornish:linframe into 67976b6 on ni:master.

@coveralls
Copy link

coveralls commented Aug 11, 2017

Coverage Status

Coverage increased (+0.5%) to 65.033% when pulling c98072d on bcornish:linframe into 67976b6 on ni:master.

@coveralls
Copy link

coveralls commented Aug 11, 2017

Coverage Status

Coverage increased (+0.5%) to 65.033% when pulling 8ba8702 on bcornish:linframe into 67976b6 on ni:master.

@@ -9,12 +9,14 @@ skip_missing_interpreters=True
[testenv]
description = Run tests
commands =
test: pytest --junit-xml=junit/{envname}.xml --junit-prefix={envname} {posargs: --nixnet-in-interface {env:NIXNET_FIXTURE_IN_INTERFACE:CAN1} --nixnet-out-interface {env:NIXNET_FIXTURE_OUT_INTERFACE:CAN2}}
test: pytest --junit-xml=junit/{envname}.xml --junit-prefix={envname} {posargs: --can-in-interface {env:CAN_FIXTURE_IN_INTERFACE:CAN1} --can-out-interface {env:CAN_FIXTURE_OUT_INTERFACE:CAN2}}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LIN interfaces aren't being passed in on the command line

@@ -335,6 +335,41 @@ def disconnect_terminals(self, source, destination):
"""
_funcs.nx_disconnect_terminals(self._handle, source, destination)

def change_lin_schedule(self, sched_index):
# type: (typing.Text) -> None
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

# type: (int) -> None

@@ -776,6 +776,26 @@ def lin_break_length(self, value):

@property
def lin_master(self):
'''boolean: LIN Master?
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

# type: () -> bool

@coveralls
Copy link

coveralls commented Aug 11, 2017

Coverage Status

Coverage increased (+0.5%) to 65.033% when pulling e7795f1 on bcornish:linframe into 67976b6 on ni:master.

@coveralls
Copy link

coveralls commented Aug 11, 2017

Coverage Status

Coverage increased (+0.5%) to 65.033% when pulling 81f3850 on bcornish:linframe into 67976b6 on ni:master.

@epage epage merged commit e25b721 into ni:master Aug 11, 2017
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

4 participants