Skip to content

Commit 30d695d

Browse files
committed
Merge 'master' into feature-asyncio
2 parents 56ed224 + dc8a4ca commit 30d695d

34 files changed

+581
-337
lines changed

canopen/__init__.py

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
1-
from .network import Network, NodeScanner
2-
from .node import RemoteNode, LocalNode
3-
from .sdo import SdoCommunicationError, SdoAbortedError
4-
from .objectdictionary import import_od, export_od, ObjectDictionary, ObjectDictionaryError
5-
from .profiles.p402 import BaseNode402
1+
from canopen.network import Network, NodeScanner
2+
from canopen.node import RemoteNode, LocalNode
3+
from canopen.sdo import SdoCommunicationError, SdoAbortedError
4+
from canopen.objectdictionary import import_od, export_od, ObjectDictionary, ObjectDictionaryError
5+
from canopen.profiles.p402 import BaseNode402
66
try:
7-
from ._version import version as __version__
7+
from canopen._version import version as __version__
88
except ImportError:
99
# package is not installed
1010
__version__ = "unknown"

canopen/emcy.py

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,18 +5,19 @@
55
import asyncio
66
import time
77
from typing import Callable, List, Optional, TYPE_CHECKING
8-
from .async_guard import ensure_not_async
8+
9+
from canopen.async_guard import ensure_not_async
910

1011
if TYPE_CHECKING:
11-
from .network import Network
12+
from canopen.network import Network
1213

1314
# Error code, error register, vendor specific data
1415
EMCY_STRUCT = struct.Struct("<HB5s")
1516

1617
logger = logging.getLogger(__name__)
1718

1819

19-
class EmcyConsumer(object):
20+
class EmcyConsumer:
2021

2122
def __init__(self):
2223
#: Log of all received EMCYs for this node
@@ -114,7 +115,7 @@ def wait(
114115
return emcy
115116

116117

117-
class EmcyProducer(object):
118+
class EmcyProducer:
118119

119120
def __init__(self, cob_id: int):
120121
self.network: Optional[Network] = None

canopen/lss.py

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,10 +8,11 @@
88
import queue
99
except ImportError:
1010
import Queue as queue
11-
from .async_guard import ensure_not_async
11+
12+
from canopen.async_guard import ensure_not_async
1213

1314
if TYPE_CHECKING:
14-
from .network import Network
15+
from canopen.network import Network
1516

1617
logger = logging.getLogger(__name__)
1718

@@ -72,7 +73,7 @@
7273
]
7374

7475

75-
class LssMaster(object):
76+
class LssMaster:
7677
"""The Master of Layer Setting Services"""
7778

7879
LSS_TX_COBID = 0x7E5

canopen/network.py

Lines changed: 23 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -19,17 +19,18 @@
1919
except ImportError:
2020
# Do not fail if python-can is not installed
2121
can = None
22-
Listener = object
2322
CanError = Exception
24-
25-
from .node import RemoteNode, LocalNode
26-
from .sync import SyncProducer
27-
from .timestamp import TimeProducer
28-
from .nmt import NmtMaster
29-
from .lss import LssMaster
30-
from .objectdictionary.eds import import_from_node
31-
from .objectdictionary import ObjectDictionary
32-
from .async_guard import set_async_sentinel
23+
class Listener:
24+
""" Dummy listener """
25+
26+
from canopen.node import RemoteNode, LocalNode
27+
from canopen.sync import SyncProducer
28+
from canopen.timestamp import TimeProducer
29+
from canopen.nmt import NmtMaster
30+
from canopen.lss import LssMaster
31+
from canopen.objectdictionary.eds import import_from_node
32+
from canopen.objectdictionary import ObjectDictionary
33+
from canopen.async_guard import set_async_sentinel
3334

3435
logger = logging.getLogger(__name__)
3536

@@ -41,8 +42,8 @@ class Network(MutableMapping):
4142

4243
def __init__(
4344
self,
44-
bus: Optional[BusABC] = None,
45-
loop: Optional[AbstractEventLoop] = None
45+
bus: can.BusABC | None = None,
46+
loop: AbstractEventLoop | None = None
4647
):
4748
"""
4849
:param can.BusABC bus:
@@ -137,7 +138,8 @@ def connect(self, *args, **kwargs) -> "Network":
137138
# async mode. This enables the @ensure_not_async() decorator to
138139
# work. See async_guard.py
139140
set_async_sentinel(self.is_async)
140-
self.bus = can.Bus(*args, **kwargs)
141+
if self.bus is None:
142+
self.bus = can.Bus(*args, **kwargs)
141143
logger.info("Connected to '%s'", self.bus.channel_info)
142144
self.notifier = can.Notifier(self.bus, self.listeners, 1, **kwargs_notifier)
143145
return self
@@ -307,6 +309,9 @@ def __getitem__(self, node_id: int) -> Union[RemoteNode, LocalNode]:
307309

308310
def __setitem__(self, node_id: int, node: Union[RemoteNode, LocalNode]):
309311
assert node_id == node.id
312+
if node_id in self.nodes:
313+
# Remove old callbacks
314+
self.nodes[node_id].remove_network()
310315
self.nodes[node_id] = node
311316
node.associate_network(self)
312317

@@ -321,7 +326,7 @@ def __len__(self) -> int:
321326
return len(self.nodes)
322327

323328

324-
class PeriodicMessageTask(object):
329+
class PeriodicMessageTask:
325330
"""
326331
Task object to transmit a message periodically using python-can's
327332
CyclicSendTask
@@ -399,8 +404,11 @@ def on_message_received(self, msg):
399404
# Exceptions in any callbaks should not affect CAN processing
400405
logger.error(str(e))
401406

407+
def stop(self) -> None:
408+
"""Override abstract base method to release any resources."""
409+
402410

403-
class NodeScanner(object):
411+
class NodeScanner:
404412
"""Observes which nodes are present on the bus.
405413
406414
Listens for the following messages:

canopen/nmt.py

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,11 +6,10 @@
66
import asyncio
77
from typing import Callable, Optional, TYPE_CHECKING
88

9-
from .network import CanError
10-
from .async_guard import ensure_not_async
9+
from canopen.async_guard import ensure_not_async
1110

1211
if TYPE_CHECKING:
13-
from .network import Network
12+
from canopen.network import Network
1413

1514

1615
logger = logging.getLogger(__name__)
@@ -46,7 +45,7 @@
4645
}
4746

4847

49-
class NmtBase(object):
48+
class NmtBase:
5049
"""
5150
Can set the state of the node it controls using NMT commands and monitor
5251
the current state using the heartbeat protocol.

canopen/node/__init__.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,2 @@
1-
from .remote import RemoteNode
2-
from .local import LocalNode
1+
from canopen.node.remote import RemoteNode
2+
from canopen.node.local import LocalNode

canopen/node/base.py

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,13 @@
11
from __future__ import annotations
22
from typing import TextIO, Union, Optional, TYPE_CHECKING
3-
from .. import objectdictionary
3+
4+
from canopen.objectdictionary import ObjectDictionary, import_od
45

56
if TYPE_CHECKING:
6-
from ..network import Network
7+
from canopen.network import Network
78

89

9-
class BaseNode(object):
10+
class BaseNode:
1011
"""A CANopen node.
1112
1213
:param node_id:
@@ -19,14 +20,12 @@ class BaseNode(object):
1920
def __init__(
2021
self,
2122
node_id: int,
22-
object_dictionary: Union[objectdictionary.ObjectDictionary, str, TextIO],
23+
object_dictionary: Union[ObjectDictionary, str, TextIO],
2324
):
2425
self.network: Optional[Network] = None
2526

26-
if not isinstance(object_dictionary,
27-
objectdictionary.ObjectDictionary):
28-
object_dictionary = objectdictionary.import_od(
29-
object_dictionary, node_id)
27+
if not isinstance(object_dictionary, ObjectDictionary):
28+
object_dictionary = import_od(object_dictionary, node_id)
3029
self.object_dictionary = object_dictionary
3130

3231
self.id = node_id or self.object_dictionary.node_id

canopen/node/local.py

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2,15 +2,16 @@
22
import logging
33
from typing import Dict, Union, TYPE_CHECKING
44

5-
from .base import BaseNode
6-
from ..sdo import SdoServer, SdoAbortedError
7-
from ..pdo import PDO, TPDO, RPDO
8-
from ..nmt import NmtSlave
9-
from ..emcy import EmcyProducer
10-
from .. import objectdictionary
5+
from canopen.node.base import BaseNode
6+
from canopen.sdo import SdoServer, SdoAbortedError
7+
from canopen.pdo import PDO, TPDO, RPDO
8+
from canopen.nmt import NmtSlave
9+
from canopen.emcy import EmcyProducer
10+
from canopen.objectdictionary import ObjectDictionary
11+
from canopen import objectdictionary
1112

1213
if TYPE_CHECKING:
13-
from ..network import Network
14+
from canopen.network import Network
1415

1516
logger = logging.getLogger(__name__)
1617

@@ -20,7 +21,7 @@ class LocalNode(BaseNode):
2021
def __init__(
2122
self,
2223
node_id: int,
23-
object_dictionary: Union[objectdictionary.ObjectDictionary, str],
24+
object_dictionary: Union[ObjectDictionary, str],
2425
):
2526
super(LocalNode, self).__init__(node_id, object_dictionary)
2627

@@ -132,7 +133,7 @@ def _find_object(self, index, subindex):
132133
# Index does not exist
133134
raise SdoAbortedError(0x06020000)
134135
obj = self.object_dictionary[index]
135-
if not isinstance(obj, objectdictionary.Variable):
136+
if not isinstance(obj, objectdictionary.ODVariable):
136137
# Group or array
137138
if subindex not in obj:
138139
# Subindex does not exist

canopen/node/remote.py

Lines changed: 13 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -2,19 +2,15 @@
22
import logging
33
from typing import Union, TextIO, TYPE_CHECKING
44

5-
from ..sdo import SdoClient
6-
from ..nmt import NmtMaster
7-
from ..emcy import EmcyConsumer
8-
from ..pdo import TPDO, RPDO, PDO
9-
from ..objectdictionary import Record, Array, Variable, List
10-
from .base import BaseNode
11-
12-
import canopen
13-
14-
from canopen import objectdictionary
5+
from canopen.sdo import SdoClient, SdoCommunicationError, SdoAbortedError
6+
from canopen.nmt import NmtMaster
7+
from canopen.emcy import EmcyConsumer
8+
from canopen.pdo import TPDO, RPDO, PDO
9+
from canopen.objectdictionary import ODRecord, ODArray, ODVariable, ObjectDictionary
10+
from canopen.node.base import BaseNode
1511

1612
if TYPE_CHECKING:
17-
from ..network import Network
13+
from canopen.network import Network
1814

1915
logger = logging.getLogger(__name__)
2016

@@ -35,7 +31,7 @@ class RemoteNode(BaseNode):
3531
def __init__(
3632
self,
3733
node_id: int,
38-
object_dictionary: Union[objectdictionary.ObjectDictionary, str, TextIO],
34+
object_dictionary: Union[ObjectDictionary, str, TextIO],
3935
load_od: bool = False,
4036
):
4137
super(RemoteNode, self).__init__(node_id, object_dictionary)
@@ -160,9 +156,9 @@ def __load_configuration_helper(self, index, subindex, name, value):
160156
index=index,
161157
name=name,
162158
value=value)))
163-
except canopen.SdoCommunicationError as e:
159+
except SdoCommunicationError as e:
164160
logger.warning(str(e))
165-
except canopen.SdoAbortedError as e:
161+
except SdoAbortedError as e:
166162
# WORKAROUND for broken implementations: the SDO is set but the error
167163
# "Attempt to write a read-only object" is raised any way.
168164
if e.code != 0x06010002:
@@ -174,10 +170,10 @@ def __load_configuration_helper(self, index, subindex, name, value):
174170
def load_configuration(self):
175171
''' Load the configuration of the node from the object dictionary.'''
176172
for obj in self.object_dictionary.values():
177-
if isinstance(obj, Record) or isinstance(obj, Array):
173+
if isinstance(obj, ODRecord) or isinstance(obj, ODArray):
178174
for subobj in obj.values():
179-
if isinstance(subobj, Variable) and subobj.writable and (subobj.value is not None):
175+
if isinstance(subobj, ODVariable) and subobj.writable and (subobj.value is not None):
180176
self.__load_configuration_helper(subobj.index, subobj.subindex, subobj.name, subobj.value)
181-
elif isinstance(obj, Variable) and obj.writable and (obj.value is not None):
177+
elif isinstance(obj, ODVariable) and obj.writable and (obj.value is not None):
182178
self.__load_configuration_helper(obj.index, None, obj.name, obj.value)
183179
self.pdo.read() # reads the new configuration from the driver

0 commit comments

Comments
 (0)