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
Conversation
1 similar comment
There was a problem hiding this 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!
nixnet/_session/frames.py
Outdated
def read_lin( | ||
self, | ||
number_to_read, | ||
timeout=constants.TIMEOUT_NONE): |
There was a problem hiding this comment.
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]
There was a problem hiding this comment.
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. |
There was a problem hiding this comment.
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""): |
There was a problem hiding this comment.
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( |
There was a problem hiding this comment.
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 |
There was a problem hiding this comment.
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 |
There was a problem hiding this comment.
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"] |
There was a problem hiding this comment.
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 |
There was a problem hiding this comment.
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)
Note: I made fixes to |
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. |
Rebased and repushed as requested. |
nixnet/types.py
Outdated
@@ -6,6 +6,8 @@ | |||
import collections | |||
import typing # NOQA: F401 | |||
|
|||
# flake8: NOQA: E501 | |||
|
There was a problem hiding this comment.
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
- So we know if they can be removed
- So we still get reports on other lines
nixnet/_session/frames.py
Outdated
@@ -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. |
There was a problem hiding this comment.
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): |
There was a problem hiding this comment.
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
There was a problem hiding this comment.
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, |
There was a problem hiding this comment.
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, |
There was a problem hiding this comment.
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
There was a problem hiding this comment.
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?
There was a problem hiding this comment.
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.
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): |
There was a problem hiding this comment.
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.
Added lin_sched and diagnostic_lin_sched functions. Submitting updates to reprs and equality tests in separate commits. |
1 similar comment
There was a problem hiding this 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
nixnet/_session/base.py
Outdated
@@ -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 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
# type: (typing.Text) -> None
nixnet/_session/base.py
Outdated
because it cannot change to master while running. | ||
|
||
Args: | ||
state_value(str): Writes the desired state. |
There was a problem hiding this comment.
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/
nixnet/_session/base.py
Outdated
Args: | ||
state_value(str): Writes the desired state. | ||
""" | ||
_funcs.nx_write_state(self._handle, constants.WriteState.LIN_SCHEDULE_CHANGE, state_value) |
There was a problem hiding this comment.
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))
nixnet/_session/base.py
Outdated
|
||
Args: | ||
state_value(str): Writes the desired state. | ||
""" |
There was a problem hiding this comment.
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.
nixnet/_session/base.py
Outdated
_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 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
# type: (constants.LinDiagnosticSchedule) -> None
There was a problem hiding this comment.
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.
nixnet/_session/base.py
Outdated
Args: | ||
state_value(str): Writes the desired state. | ||
""" | ||
_funcs.nx_write_state(self._handle, constants.WriteState.LIN_DIAGNOSTIC_SCHEDULE_CHANGE, state_value) |
There was a problem hiding this comment.
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)
nixnet/_session/base.py
Outdated
the diagnostic schedule. | ||
|
||
Args: | ||
state_value(str): Writes the desired state. |
There was a problem hiding this comment.
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
nixnet/_session/base.py
Outdated
@@ -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): |
There was a problem hiding this comment.
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?
There was a problem hiding this comment.
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?
There was a problem hiding this comment.
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.
nixnet/_session/base.py
Outdated
""" | ||
_funcs.nx_write_state(self._handle, constants.WriteState.LIN_SCHEDULE_CHANGE, state_value) | ||
|
||
def write_state_lin_diagnostic_schedule_change(self, state_value): |
There was a problem hiding this comment.
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.
Related to ni#142 Updated repr and added equality tests
Add linframe in types ni#142 Added coverage Add LinFrame equality test
Add linframe in types ni#142 Added more test coverage Added LinFrame equality test
Updated test_examples
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? |
Yep. You answered my questions for next steps on this. |
Made Can specific
tox-integration.ini
Outdated
@@ -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}} |
There was a problem hiding this comment.
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
nixnet/_session/base.py
Outdated
@@ -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 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
# type: (int) -> None
nixnet/_session/intf.py
Outdated
@@ -776,6 +776,26 @@ def lin_break_length(self, value): | |||
|
|||
@property | |||
def lin_master(self): | |||
'''boolean: LIN Master? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
# type: () -> bool
tox
successfully runs, including unit tests and style checks (see CONTRIBUTING.md).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