Skip to content

Commit 64e8e66

Browse files
mgiacofelixdivo
authored andcommitted
Add a possibility to use LISTEN ONLY for the CAN Hardware. (hardbyte#235)
* add interface example definition for beginners * add a state for the bus to handle active and passive mode, currently only implemented for pcan * decode the right way * use ACTIVE state as default for getter, raise NotImplementedError on base setter
1 parent ddfac97 commit 64e8e66

4 files changed

Lines changed: 88 additions & 3 deletions

File tree

can/bus.py

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,12 +10,16 @@
1010
from abc import ABCMeta, abstractmethod
1111
import logging
1212
import threading
13+
from collections import namedtuple
1314

1415
from can.broadcastmanager import ThreadBasedCyclicSendTask
1516

1617
logger = logging.getLogger(__name__)
1718

1819

20+
BusState = namedtuple('BusState', 'ACTIVE, PASSIVE, ERROR')
21+
22+
1923
class BusABC(object):
2024
"""CAN Bus Abstract Base Class
2125
@@ -151,6 +155,23 @@ def shutdown(self):
151155
"""
152156
self.flush_tx_buffer()
153157

158+
@property
159+
def state(self):
160+
"""
161+
Return the current state of the hardware
162+
:return: ACTIVE, PASSIVE or ERROR
163+
:rtype: NamedTuple
164+
"""
165+
return BusState.ACTIVE
166+
167+
@state.setter
168+
def state(self, new_state):
169+
"""
170+
Set the new state of the hardware
171+
:param new_state: BusState.ACTIVE, BusState.PASSIVE or BusState.ERROR
172+
"""
173+
raise NotImplementedError("Property is not implemented.")
174+
154175
@staticmethod
155176
def _detect_available_configs():
156177
"""Detect all configurations/channels that this interface could

can/interfaces/pcan/pcan.py

Lines changed: 29 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111

1212
import can
1313
from can import CanError
14-
from can.bus import BusABC
14+
from can.bus import BusABC, BusState
1515
from can.message import Message
1616
from can.interfaces.pcan.PCANBasic import *
1717

@@ -67,7 +67,7 @@
6767

6868
class PcanBus(BusABC):
6969

70-
def __init__(self, channel, *args, **kwargs):
70+
def __init__(self, channel, state=BusState.ACTIVE, *args, **kwargs):
7171
"""A PCAN USB interface to CAN.
7272
7373
On top of the usual :class:`~can.Bus` methods provided,
@@ -76,10 +76,13 @@ def __init__(self, channel, *args, **kwargs):
7676
:param str channel:
7777
The can interface name. An example would be PCAN_USBBUS1
7878
79+
:param BusState state:
80+
BusState of the channel.
81+
Default is ACTIVE
82+
7983
:param int bitrate:
8084
Bitrate of channel in bit/s.
8185
Default is 500 Kbs
82-
8386
"""
8487
if channel is None or channel == '':
8588
raise ArgumentError("Must specify a PCAN channel")
@@ -96,6 +99,11 @@ def __init__(self, channel, *args, **kwargs):
9699
self.m_objPCANBasic = PCANBasic()
97100
self.m_PcanHandle = globals()[channel]
98101

102+
if state is BusState.ACTIVE or BusState.PASSIVE:
103+
self._state = state
104+
else:
105+
raise ArgumentError("BusState must be Active or Passive")
106+
99107
result = self.m_objPCANBasic.Initialize(self.m_PcanHandle, pcan_bitrate, hwtype, ioport, interrupt)
100108

101109
if result != PCAN_ERROR_OK:
@@ -262,6 +270,24 @@ def flash(self, flash):
262270
def shutdown(self):
263271
self.m_objPCANBasic.Uninitialize(self.m_PcanHandle)
264272

273+
@property
274+
def state(self):
275+
return self._state
276+
277+
@state.setter
278+
def state(self, new_state):
279+
280+
self._state = new_state
281+
282+
if new_state is BusState.ACTIVE:
283+
self.m_objPCANBasic.SetValue(self.m_PcanHandle, PCAN_LISTEN_ONLY, PCAN_PARAMETER_OFF)
284+
285+
if new_state is BusState.PASSIVE:
286+
# When this mode is set, the CAN controller does not take part on active events (eg. transmit CAN messages)
287+
# but stays in a passive mode (CAN monitor), in which it can analyse the traffic on the CAN bus used by a
288+
# PCAN channel. See also the Philips Data Sheet "SJA1000 Stand-alone CAN controller".
289+
self.m_objPCANBasic.SetValue(self.m_PcanHandle, PCAN_LISTEN_ONLY, PCAN_PARAMETER_ON)
290+
265291

266292
class PcanError(CanError):
267293
pass

can/logger.py

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
import socket
2525

2626
import can
27+
from can.bus import BusState
2728
from can.io.logger import Logger
2829

2930

@@ -57,6 +58,10 @@ def main():
5758
parser.add_argument('-b', '--bitrate', type=int,
5859
help='''Bitrate to use for the CAN bus.''')
5960

61+
group = parser.add_mutually_exclusive_group(required=False)
62+
group.add_argument('--active', action='store_true')
63+
group.add_argument('--passive', action='store_true')
64+
6065
results = parser.parse_args()
6166

6267
verbosity = results.verbosity
@@ -83,6 +88,13 @@ def main():
8388
if results.bitrate:
8489
config["bitrate"] = results.bitrate
8590
bus = can.interface.Bus(results.channel, **config)
91+
92+
if results.active:
93+
bus.state = BusState.ACTIVE
94+
95+
if results.passive:
96+
bus.state = BusState.PASSIVE
97+
8698
print('Connected to {}: {}'.format(bus.__class__.__name__, bus.channel_info))
8799
print('Can Logger (Started on {})\n'.format(datetime.datetime.now()))
88100
logger = Logger(results.log_file)

examples/receive_all.py

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
from __future__ import print_function
2+
3+
import can
4+
from can.bus import BusState
5+
6+
7+
def receive_all():
8+
9+
bus = can.interface.Bus(bustype='pcan', channel='PCAN_USBBUS1', bitrate=250000)
10+
#bus = can.interface.Bus(bustype='ixxat', channel=0, bitrate=250000)
11+
#bus = can.interface.Bus(bustype='vector', app_name='CANalyzer', channel=0, bitrate=250000)
12+
13+
bus.state = BusState.ACTIVE
14+
#bus.state = BusState.PASSIVE
15+
16+
try:
17+
while True:
18+
msg = bus.recv(1)
19+
if msg is not None:
20+
print(msg)
21+
except KeyboardInterrupt:
22+
pass
23+
24+
25+
if __name__ == "__main__":
26+
receive_all()

0 commit comments

Comments
 (0)