Skip to content

Commit 696af28

Browse files
committed
initial commit
0 parents  commit 696af28

37 files changed

+3148
-0
lines changed

.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
*.DS_Store
2+
*__pycache__

README.md

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
2+
A Python implementation of [OpenLCB](http://www.openlcb.org)/[LCC](https://www.nmra.org/lcc) based on the [LccTools](https://apps.apple.com/sr/app/lcctools/id1640295587) app's [Swift implementation](https://github.com/bobjacobsen/OpenlcbLibrary) as of January 2024.
3+
4+
Requires Python 3.10 or later.
5+
6+
To run the unit test suite:
7+
```
8+
python3.10 pythonolcb/all_test.py
9+
```
10+
11+
There are examples for using the code at various levels of integration:
12+
```
13+
python3.10 pythonolcb/example_string_interface.py
14+
python3.10 pythonolcb/example_frame_interface.py
15+
python3.10 pythonolcb/example_message_interface.py
16+
python3.10 pythonolcb/example_datagram_transfer.py
17+
python3.10 pythonolcb/example_memory_transfer.py
18+
```
19+
20+
These will require editing to have the right host name, port number, and in some cases the right remote node ID for your hardware configuration. See the top of the files.
21+
22+
For an overview of the structure, see [this diagram](doc/Overview.png) of the example programs

doc/Overview.graffle

243 KB
Binary file not shown.

doc/Overview.png

58.5 KB
Loading

pythonolcb/all_test.py

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
import unittest
2+
3+
# WARNING is normal during testing, but ERROR is not
4+
import logging
5+
logging.basicConfig(level=logging.ERROR, format='%(name)s %(levelname)s %(message)s')
6+
7+
from eventid_test import *
8+
from nodeid_test import *
9+
10+
from canframe_test import *
11+
12+
from physicallayer_test import *
13+
from canphysicallayer_test import *
14+
from canphysicallayergridconnect_test import *
15+
16+
from mti_test import *
17+
from message_test import *
18+
19+
from linklayer_test import *
20+
from canlink_test import *
21+
22+
from datagramservice_test import *
23+
24+
from memoryservice_test import *
25+
26+
if __name__ == '__main__':
27+
unittest.main()

pythonolcb/canframe.py

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
from nodeid import NodeID
2+
3+
class CanFrame :
4+
header = 0
5+
data = []
6+
7+
def __str__(self) :
8+
return "CanFrame header: 0x{:08X} {}".format(self.header, self.data)
9+
10+
# there are three ctor forms
11+
12+
def __init__(self, arg1, arg2, arg3=[]) :
13+
# three arguments as N_cid, nodeID, alias
14+
if isinstance(arg2, NodeID) :
15+
# cid must be 4 to 7 inclusive
16+
# precondition(4 <= cid && cid <= 7)
17+
cid = arg1
18+
nodeID = arg2
19+
alias = arg3
20+
21+
nodeCode = ( ( nodeID.nodeId >> ((cid-4)*12) ) & 0xFFF )
22+
self.header = ((cid << 12) | nodeCode) << 12 | (alias & 0xFFF) | 0x10_000_000
23+
self.data = []
24+
25+
# two arguments as header, data
26+
elif isinstance(arg2, list) :
27+
self.header = arg1
28+
self.data = arg2
29+
30+
# three arguments as control, alias, data
31+
elif isinstance(arg2, int) :
32+
control = arg1
33+
alias = arg2
34+
self.header = (control << 12) | (alias & 0xFFF) | 0x10_000_000
35+
self.data = arg3
36+
37+
else :
38+
print("could not decode NodeID ctor arguments")
39+
40+
def __eq__(self, other):
41+
if other == None : return False
42+
43+
if self.header != other.header:
44+
return False
45+
if self.data != other.data:
46+
return False
47+
return True

pythonolcb/canframe_test.py

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
import unittest
2+
3+
from canframe import CanFrame
4+
from nodeid import NodeID
5+
6+
class TestCanFrameClass(unittest.TestCase) :
7+
8+
def testInit(self) :
9+
frame1 = CanFrame(0, [])
10+
self.assertEqual(frame1.header, 0x0_000_000)
11+
self.assertEqual(frame1.data, [])
12+
13+
frame2 = CanFrame(0x1234, [])
14+
self.assertEqual(frame2.header, 0x1234)
15+
self.assertEqual(frame2.data, [])
16+
17+
frame3 = CanFrame(0x123456, [1,2,3])
18+
self.assertEqual(frame3.header, 0x123456)
19+
self.assertEqual(frame3.data, [1,2,3])
20+
21+
def testCID(self) :
22+
cidFrame40 = CanFrame(4, NodeID(0x00_00_00_00_00_00), 0)
23+
self.assertEqual(cidFrame40.header, 0x14_000_000)
24+
self.assertEqual(cidFrame40.data, [])
25+
26+
cidFrame4ABC = CanFrame(4, NodeID(0x00_00_00_00_00_00), 0xABC)
27+
self.assertEqual(cidFrame4ABC.header, 0x14_000_ABC)
28+
self.assertEqual(cidFrame4ABC.data, [])
29+
30+
cidFrame4 = CanFrame(4, NodeID(0x12_34_56_78_9A_BC), 0x123)
31+
self.assertEqual(cidFrame4.header, 0x14_ABC_123)
32+
self.assertEqual(cidFrame4.data, [])
33+
34+
cidFrame5 = CanFrame(5, NodeID(0x12_34_56_78_9A_BC), 0x321)
35+
self.assertEqual(cidFrame5.header, 0x15_789_321)
36+
self.assertEqual(cidFrame5.data, [])
37+
38+
cidFrame7 = CanFrame(7, NodeID(0x12_34_56_78_9A_BC), 0x010)
39+
self.assertEqual(cidFrame7.header, 0x17_123_010)
40+
self.assertEqual(cidFrame7.data, [])
41+
42+
def testControlFrame(self) :
43+
frame0703 = CanFrame(0x0701, 0x123)
44+
self.assertEqual(frame0703.header, 0x10701123)
45+
self.assertEqual(frame0703.data, [])
46+
47+
if __name__ == '__main__':
48+
unittest.main()

0 commit comments

Comments
 (0)