plin-linux 0.0.2__tar.gz → 0.0.4__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,6 +1,6 @@
1
- Metadata-Version: 2.1
1
+ Metadata-Version: 2.4
2
2
  Name: plin-linux
3
- Version: 0.0.2
3
+ Version: 0.0.4
4
4
  Summary: The python-plin package is a Python wrapper for the chardev API provided by the PEAK LIN Linux Beta.
5
5
  Author-email: William Zhang <williamzhang@rivian.com>
6
6
  Project-URL: Homepage, https://github.com/rivian/python-plin
@@ -11,9 +11,11 @@ Classifier: Operating System :: POSIX :: Linux
11
11
  Requires-Python: >=3.7
12
12
  Description-Content-Type: text/markdown
13
13
  License-File: LICENSE
14
+ Requires-Dist: ioctl_opt
15
+ Dynamic: license-file
14
16
 
15
17
  # Python PLIN library
16
- This library provides a Python interface for interacting with PEAK devices such as the PCAN-USB Pro and PLIN-USB on Linux using the chardev API provided by the PEAK LIN Linux Beta. The PEAK Linux beta driver is required to use this library and is available [here](https://forum.peak-system.com/viewtopic.php?t=5875).
18
+ This library provides a Python interface for interacting with PEAK devices such as the PCAN-USB Pro and PLIN-USB on Linux using the chardev API provided by the PEAK LIN Linux Driver. The PEAK LIN Linux driver is required to use this library and is available [here](https://www.peak-system.com/fileadmin/media/linux/lin.php).
17
19
 
18
20
  ## Installation
19
21
  The `plin-linux` package is available on [PyPI](https://pypi.org/project/plin-linux/) and can be directly installed with `pip install plin-linux`.
@@ -23,7 +25,7 @@ Runnable examples are located in the `examples/` directory.
23
25
 
24
26
  ### Master Example
25
27
  ```python
26
- from plin.plin import PLIN
28
+ from plin.device import PLIN
27
29
  from plin.enums import (PLINFrameChecksumType, PLINFrameDirection,
28
30
  PLINFrameFlag, PLINMode)
29
31
 
@@ -74,7 +76,7 @@ while True:
74
76
 
75
77
  ### Slave Example
76
78
  ```python
77
- from plin.plin import PLIN
79
+ from plin.device import PLIN
78
80
  from plin.enums import PLINMode
79
81
 
80
82
  # Initializes /dev/plin0 as a LIN slave
@@ -93,11 +95,13 @@ while True:
93
95
  ```
94
96
 
95
97
  ## Unit Tests
96
- Unit tests are located in the `unit_tests/` directory and require a PEAK LIN device connected to run.
98
+ * Unit tests are located in the `unit_tests/` directory.
99
+ * Tests in `unit_tests/integration/` require a PEAK LIN device connected to run.
100
+ * Can be run with `pytest`.
97
101
 
98
102
  ## License
99
103
 
100
- Copyright 2023 Rivian Automotive, Inc.
104
+ Copyright 2024 Rivian Automotive, Inc.
101
105
 
102
106
  Licensed under the Apache License, Version 2.0 (the "License");
103
107
  you may not use this file except in compliance with the License.
@@ -1,5 +1,5 @@
1
1
  # Python PLIN library
2
- This library provides a Python interface for interacting with PEAK devices such as the PCAN-USB Pro and PLIN-USB on Linux using the chardev API provided by the PEAK LIN Linux Beta. The PEAK Linux beta driver is required to use this library and is available [here](https://forum.peak-system.com/viewtopic.php?t=5875).
2
+ This library provides a Python interface for interacting with PEAK devices such as the PCAN-USB Pro and PLIN-USB on Linux using the chardev API provided by the PEAK LIN Linux Driver. The PEAK LIN Linux driver is required to use this library and is available [here](https://www.peak-system.com/fileadmin/media/linux/lin.php).
3
3
 
4
4
  ## Installation
5
5
  The `plin-linux` package is available on [PyPI](https://pypi.org/project/plin-linux/) and can be directly installed with `pip install plin-linux`.
@@ -9,7 +9,7 @@ Runnable examples are located in the `examples/` directory.
9
9
 
10
10
  ### Master Example
11
11
  ```python
12
- from plin.plin import PLIN
12
+ from plin.device import PLIN
13
13
  from plin.enums import (PLINFrameChecksumType, PLINFrameDirection,
14
14
  PLINFrameFlag, PLINMode)
15
15
 
@@ -60,7 +60,7 @@ while True:
60
60
 
61
61
  ### Slave Example
62
62
  ```python
63
- from plin.plin import PLIN
63
+ from plin.device import PLIN
64
64
  from plin.enums import PLINMode
65
65
 
66
66
  # Initializes /dev/plin0 as a LIN slave
@@ -79,11 +79,13 @@ while True:
79
79
  ```
80
80
 
81
81
  ## Unit Tests
82
- Unit tests are located in the `unit_tests/` directory and require a PEAK LIN device connected to run.
82
+ * Unit tests are located in the `unit_tests/` directory.
83
+ * Tests in `unit_tests/integration/` require a PEAK LIN device connected to run.
84
+ * Can be run with `pytest`.
83
85
 
84
86
  ## License
85
87
 
86
- Copyright 2023 Rivian Automotive, Inc.
88
+ Copyright 2024 Rivian Automotive, Inc.
87
89
 
88
90
  Licensed under the Apache License, Version 2.0 (the "License");
89
91
  you may not use this file except in compliance with the License.
@@ -41,6 +41,10 @@ PLIOSETGETRSPMAP = IOWR(ord('u'), 39, PLINUSBResponseRemap)
41
41
  PLIOSETLEDSTATE = IOW(ord('u'), 40, PLINUSBLEDState)
42
42
 
43
43
 
44
+ class PLINException(Exception):
45
+ pass
46
+
47
+
44
48
  class PLIN:
45
49
  def __init__(self, interface: str):
46
50
  self.interface = interface
@@ -72,12 +76,13 @@ class PLIN:
72
76
  self.mode = mode
73
77
  self.baudrate = baudrate
74
78
 
75
- if not self.fd:
79
+ if self.fd:
80
+ raise PLINException("Already connected to PLIN device!")
81
+ else:
76
82
  self.fd = os.open(self.interface, os.O_RDWR)
77
-
78
- self.reset()
79
- buffer = PLINUSBInitHardware(self.baudrate, self.mode, 0)
80
- self._ioctl(PLIOHWINIT, buffer)
83
+ self.reset()
84
+ buffer = PLINUSBInitHardware(self.baudrate, self.mode, 0)
85
+ self._ioctl(PLIOHWINIT, buffer)
81
86
 
82
87
  def stop(self):
83
88
  '''
@@ -85,6 +90,9 @@ class PLIN:
85
90
  '''
86
91
  if self.fd:
87
92
  os.close(self.fd)
93
+ self.fd = None
94
+ else:
95
+ raise PLINException("Not connected to PLIN device!")
88
96
 
89
97
  def set_frame_entry(self,
90
98
  id: int,
@@ -99,10 +107,11 @@ class PLIN:
99
107
  IMPORTANT NOTE: For a publisher frame, the flag PLINFrameFlag.RSP_ENABLE must be set in order to allow a slave response.
100
108
  This flag is set by default if the frame direction is publisher for convenience.
101
109
  '''
102
- buffer = PLINUSBFrameEntry(
103
- id=id, direction=direction, checksum=checksum_type)
104
110
  if direction == PLINFrameDirection.PUBLISHER:
105
- buffer.flags = flags & PLINFrameFlag.RSP_ENABLE
111
+ flags |= PLINFrameFlag.RSP_ENABLE
112
+
113
+ buffer = PLINUSBFrameEntry(
114
+ id=id, direction=direction, checksum=checksum_type, flags=flags)
106
115
  if data:
107
116
  buffer.d = data
108
117
  if len > 0:
@@ -505,23 +514,29 @@ class PLIN:
505
514
 
506
515
  def read(self, block=True) -> Union[PLINMessage, None]:
507
516
  '''
508
- Reads a PLINMessage from the LIN bus with an optional timeout in milliseconds.
517
+ Reads the next PLINMessage the driver has queued.
509
518
 
510
- A timeout value of 0 blocks until data is read. If the timeout is reached before data is read, None is returned.
519
+ Every record is returned as the device reported it, including frames whose data is all 0xFF:
520
+ that is what an unanswered header looks like (flags carry SLV_NOT_RSP / TIMEOUT), and it is
521
+ indistinguishable from a slave that answered with recessive bytes, so the caller must decide
522
+ from the flags, not the data. Non-FRAME records (SLEEP, WAKEUP, OVERRUN, ...) are returned
523
+ too; check message.type.
524
+
525
+ Returns None when a non-blocking read finds nothing queued.
511
526
  '''
512
527
  if self.fd:
513
528
  blocking = os.get_blocking(self.fd)
514
529
  os.set_blocking(self.fd, block)
515
530
  try:
516
531
  result = os.read(self.fd, PLINMessage.buffer_length)
517
- message = PLINMessage.from_buffer_copy(result)
518
- # If bytes read was invalid.
519
- if bytes(message.data) == PLIN_EMPTY_DATA:
520
- message = None
521
- except:
522
- message = None
523
- os.set_blocking(self.fd, blocking)
524
- return message
532
+ except BlockingIOError:
533
+ return None
534
+ finally:
535
+ os.set_blocking(self.fd, blocking)
536
+
537
+ if len(result) < PLINMessage.buffer_length:
538
+ return None
539
+ return PLINMessage.from_buffer_copy(result)
525
540
  else:
526
541
  raise Exception("PLIN not connected!")
527
542
 
@@ -1,6 +1,6 @@
1
- Metadata-Version: 2.1
1
+ Metadata-Version: 2.4
2
2
  Name: plin-linux
3
- Version: 0.0.2
3
+ Version: 0.0.4
4
4
  Summary: The python-plin package is a Python wrapper for the chardev API provided by the PEAK LIN Linux Beta.
5
5
  Author-email: William Zhang <williamzhang@rivian.com>
6
6
  Project-URL: Homepage, https://github.com/rivian/python-plin
@@ -11,9 +11,11 @@ Classifier: Operating System :: POSIX :: Linux
11
11
  Requires-Python: >=3.7
12
12
  Description-Content-Type: text/markdown
13
13
  License-File: LICENSE
14
+ Requires-Dist: ioctl_opt
15
+ Dynamic: license-file
14
16
 
15
17
  # Python PLIN library
16
- This library provides a Python interface for interacting with PEAK devices such as the PCAN-USB Pro and PLIN-USB on Linux using the chardev API provided by the PEAK LIN Linux Beta. The PEAK Linux beta driver is required to use this library and is available [here](https://forum.peak-system.com/viewtopic.php?t=5875).
18
+ This library provides a Python interface for interacting with PEAK devices such as the PCAN-USB Pro and PLIN-USB on Linux using the chardev API provided by the PEAK LIN Linux Driver. The PEAK LIN Linux driver is required to use this library and is available [here](https://www.peak-system.com/fileadmin/media/linux/lin.php).
17
19
 
18
20
  ## Installation
19
21
  The `plin-linux` package is available on [PyPI](https://pypi.org/project/plin-linux/) and can be directly installed with `pip install plin-linux`.
@@ -23,7 +25,7 @@ Runnable examples are located in the `examples/` directory.
23
25
 
24
26
  ### Master Example
25
27
  ```python
26
- from plin.plin import PLIN
28
+ from plin.device import PLIN
27
29
  from plin.enums import (PLINFrameChecksumType, PLINFrameDirection,
28
30
  PLINFrameFlag, PLINMode)
29
31
 
@@ -74,7 +76,7 @@ while True:
74
76
 
75
77
  ### Slave Example
76
78
  ```python
77
- from plin.plin import PLIN
79
+ from plin.device import PLIN
78
80
  from plin.enums import PLINMode
79
81
 
80
82
  # Initializes /dev/plin0 as a LIN slave
@@ -93,11 +95,13 @@ while True:
93
95
  ```
94
96
 
95
97
  ## Unit Tests
96
- Unit tests are located in the `unit_tests/` directory and require a PEAK LIN device connected to run.
98
+ * Unit tests are located in the `unit_tests/` directory.
99
+ * Tests in `unit_tests/integration/` require a PEAK LIN device connected to run.
100
+ * Can be run with `pytest`.
97
101
 
98
102
  ## License
99
103
 
100
- Copyright 2023 Rivian Automotive, Inc.
104
+ Copyright 2024 Rivian Automotive, Inc.
101
105
 
102
106
  Licensed under the Apache License, Version 2.0 (the "License");
103
107
  you may not use this file except in compliance with the License.
@@ -9,6 +9,4 @@ plin_linux.egg-info/PKG-INFO
9
9
  plin_linux.egg-info/SOURCES.txt
10
10
  plin_linux.egg-info/dependency_links.txt
11
11
  plin_linux.egg-info/requires.txt
12
- plin_linux.egg-info/top_level.txt
13
- tests/test_message.py
14
- tests/test_plin.py
12
+ plin_linux.egg-info/top_level.txt
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "plin-linux"
7
- version = "0.0.2"
7
+ version = "0.0.4"
8
8
  authors = [
9
9
  { name="William Zhang", email="williamzhang@rivian.com" },
10
10
  ]
@@ -1,10 +0,0 @@
1
- import pytest
2
- from plin.structs import PLINMessage
3
-
4
- @pytest.fixture
5
- def test_message():
6
- return PLINMessage()
7
-
8
- def test_set_message_data(test_message):
9
- test_message.data = bytearray([0xff])
10
- assert bytearray(test_message.data) == bytearray([0xff] + [0] * 7)
@@ -1,146 +0,0 @@
1
- import pytest
2
- from plin.device import PLIN
3
- from plin.enums import PLINMode, PLINMessageType, PLINFrameDirection, PLINFrameChecksumType
4
- from plin.structs import *
5
-
6
- @pytest.fixture
7
- def plin_interface():
8
- return "/dev/plin0"
9
-
10
-
11
- @pytest.fixture
12
- def plin(plin_interface):
13
- return PLIN(plin_interface)
14
-
15
-
16
- @pytest.fixture
17
- def plin_slave_1000(plin):
18
- plin.start(mode=PLINMode.SLAVE, baudrate=1000)
19
- yield plin
20
- plin.stop()
21
-
22
-
23
- @pytest.fixture
24
- def plin_master_19200(plin):
25
- plin.start(mode=PLINMode.MASTER, baudrate=19200)
26
- yield plin
27
- plin.stop()
28
-
29
-
30
- @pytest.fixture
31
- def master_request_frame():
32
- return PLINMessage(type=PLINMessageType.FRAME,
33
- id=0x3c,
34
- len=8,
35
- dir=PLINFrameDirection.PUBLISHER,
36
- cs_type=PLINFrameChecksumType.CLASSIC,
37
- data=bytearray([0x7f, 0x6, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff]))
38
-
39
-
40
- def test_start(plin_interface, plin):
41
- expected_baudrate = 1000
42
- expected_mode = PLINMode.SLAVE
43
-
44
- plin.start(mode=expected_mode, baudrate=expected_baudrate)
45
- assert plin.get_baudrate() == expected_baudrate
46
- assert plin.get_mode() == expected_mode
47
- plin.stop()
48
-
49
-
50
- def test_read_nonblocking(plin_master_19200):
51
- assert None == plin_master_19200.read(block=False)
52
-
53
-
54
- def test_write_master_request_frame(plin_master_19200, master_request_frame):
55
- plin_master_19200.write(master_request_frame)
56
-
57
-
58
- def test_reset(plin_slave_1000):
59
- expected_baudrate = 0
60
- expected_mode = PLINMode.NONE
61
-
62
- plin_slave_1000.reset()
63
- assert plin_slave_1000.get_baudrate() == expected_baudrate
64
- assert plin_slave_1000.get_mode() == expected_mode
65
-
66
-
67
- def test_set_id_filter(plin_slave_1000):
68
- expected_id_filter = bytearray([0xff] * 8)
69
-
70
- plin_slave_1000.set_id_filter(expected_id_filter)
71
- assert plin_slave_1000.get_id_filter() == expected_id_filter
72
-
73
-
74
- def test_block_id(plin_slave_1000):
75
- expected_id_filter = bytearray([0xf0] + [0xff] * 7)
76
-
77
- plin_slave_1000.set_id_filter(bytearray([0xff] * 8))
78
- plin_slave_1000.block_id(0)
79
- plin_slave_1000.block_id(1)
80
- plin_slave_1000.block_id(2)
81
- plin_slave_1000.block_id(3)
82
- assert plin_slave_1000.get_id_filter() == expected_id_filter
83
-
84
-
85
- def test_register_id(plin_slave_1000):
86
- expected_id_filter = bytearray([0x0f] + [0x0] * 7)
87
-
88
- plin_slave_1000.set_id_filter(bytearray([0x0] * 8))
89
- plin_slave_1000.register_id(0)
90
- plin_slave_1000.register_id(1)
91
- plin_slave_1000.register_id(2)
92
- plin_slave_1000.register_id(3)
93
- print(plin_slave_1000.get_id_filter())
94
- assert plin_slave_1000.get_id_filter() == expected_id_filter
95
-
96
-
97
- def test_clear_id_filter_allow_all(plin_slave_1000):
98
- expected_id_filter = bytearray([0xff] * 8)
99
-
100
- plin_slave_1000.clear_id_filter(allow_all=True)
101
- assert plin_slave_1000.get_id_filter() == expected_id_filter
102
-
103
-
104
- def test_clear_id_filter_block_all(plin_slave_1000):
105
- expected_id_filter = bytearray([0x0] * 8)
106
-
107
- plin_slave_1000.clear_id_filter(allow_all=False)
108
- assert plin_slave_1000.get_id_filter() == expected_id_filter
109
-
110
-
111
- def test_set_id_string(plin_slave_1000):
112
- expected_id_string = "test ID"
113
-
114
- plin_slave_1000.set_id_string(expected_id_string)
115
- assert plin_slave_1000.get_id_string() == expected_id_string
116
-
117
-
118
- def test_identify(plin_slave_1000):
119
- plin_slave_1000.identify()
120
-
121
-
122
- def test_get_firmware_version(plin_slave_1000):
123
- expected_num_subversions = 3
124
-
125
- version = plin_slave_1000.get_firmware_version()
126
- assert len(version.split('.')) == expected_num_subversions
127
-
128
-
129
- def test_get_status(plin_slave_1000):
130
- expected_baudrate = 1000
131
- expected_mode = PLINMode.SLAVE
132
-
133
- status = plin_slave_1000.get_status()
134
- assert status["mode"] == expected_mode
135
- assert status["baudrate"] == expected_baudrate
136
-
137
-
138
- def test_set_response_remap(plin_slave_1000):
139
- expected_remap = {1: 2}
140
- plin_slave_1000.set_response_remap(expected_remap)
141
- assert plin_slave_1000.response_remap[1] == 2
142
- assert plin_slave_1000.get_response_remap() == expected_remap
143
-
144
-
145
- def test_set_led_state(plin_slave_1000):
146
- plin_slave_1000.set_led_state(enable=True)
File without changes
File without changes
File without changes
File without changes
File without changes