libosdp 3.1.2__tar.gz → 3.2.3__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.
- {libosdp-3.1.2 → libosdp-3.2.3}/PKG-INFO +27 -3
- {libosdp-3.1.2 → libosdp-3.2.3}/README.md +25 -1
- {libosdp-3.1.2 → libosdp-3.2.3}/libosdp.egg-info/PKG-INFO +27 -3
- {libosdp-3.1.2 → libosdp-3.2.3}/libosdp.egg-info/SOURCES.txt +0 -1
- {libosdp-3.1.2 → libosdp-3.2.3}/osdp/__init__.py +2 -2
- {libosdp-3.1.2 → libosdp-3.2.3}/osdp/constants.py +7 -1
- {libosdp-3.1.2 → libosdp-3.2.3}/osdp/control_panel.py +53 -51
- {libosdp-3.1.2 → libosdp-3.2.3}/osdp/helpers.py +1 -1
- {libosdp-3.1.2 → libosdp-3.2.3}/osdp/key_store.py +1 -1
- {libosdp-3.1.2 → libosdp-3.2.3}/osdp/peripheral_device.py +27 -17
- {libosdp-3.1.2 → libosdp-3.2.3}/setup.py +63 -20
- {libosdp-3.1.2 → libosdp-3.2.3}/vendor/include/osdp.h +95 -1
- {libosdp-3.1.2 → libosdp-3.2.3}/vendor/include/osdp_export.h +3 -3
- {libosdp-3.1.2 → libosdp-3.2.3}/vendor/python/osdp_sys/base.c +24 -13
- {libosdp-3.1.2 → libosdp-3.2.3}/vendor/python/osdp_sys/cp.c +202 -24
- {libosdp-3.1.2 → libosdp-3.2.3}/vendor/python/osdp_sys/data.c +2 -13
- {libosdp-3.1.2 → libosdp-3.2.3}/vendor/python/osdp_sys/module.c +8 -1
- {libosdp-3.1.2 → libosdp-3.2.3}/vendor/python/osdp_sys/module.h +18 -1
- {libosdp-3.1.2 → libosdp-3.2.3}/vendor/python/osdp_sys/pd.c +154 -7
- {libosdp-3.1.2 → libosdp-3.2.3}/vendor/python/osdp_sys/utils.c +137 -4
- {libosdp-3.1.2 → libosdp-3.2.3}/vendor/src/crypto/tinyaes.c +1 -1
- {libosdp-3.1.2 → libosdp-3.2.3}/vendor/src/osdp_common.c +1 -1
- {libosdp-3.1.2 → libosdp-3.2.3}/vendor/src/osdp_common.h +177 -64
- libosdp-3.2.3/vendor/src/osdp_config.h +102 -0
- {libosdp-3.1.2 → libosdp-3.2.3}/vendor/src/osdp_cp.c +261 -132
- {libosdp-3.1.2 → libosdp-3.2.3}/vendor/src/osdp_diag.c +1 -1
- {libosdp-3.1.2 → libosdp-3.2.3}/vendor/src/osdp_diag.h +1 -1
- {libosdp-3.1.2 → libosdp-3.2.3}/vendor/src/osdp_file.c +18 -19
- {libosdp-3.1.2 → libosdp-3.2.3}/vendor/src/osdp_file.h +1 -1
- {libosdp-3.1.2 → libosdp-3.2.3}/vendor/src/osdp_pd.c +217 -91
- {libosdp-3.1.2 → libosdp-3.2.3}/vendor/src/osdp_phy.c +183 -69
- {libosdp-3.1.2 → libosdp-3.2.3}/vendor/src/osdp_sc.c +4 -8
- {libosdp-3.1.2 → libosdp-3.2.3}/vendor/utils/include/utils/assert.h +19 -2
- {libosdp-3.1.2 → libosdp-3.2.3}/vendor/utils/include/utils/disjoint_set.h +1 -1
- {libosdp-3.1.2 → libosdp-3.2.3}/vendor/utils/include/utils/list.h +1 -1
- {libosdp-3.1.2 → libosdp-3.2.3}/vendor/utils/include/utils/logger.h +1 -1
- {libosdp-3.1.2 → libosdp-3.2.3}/vendor/utils/include/utils/pcap_gen.h +1 -1
- {libosdp-3.1.2 → libosdp-3.2.3}/vendor/utils/include/utils/queue.h +1 -1
- {libosdp-3.1.2 → libosdp-3.2.3}/vendor/utils/include/utils/slab.h +1 -1
- {libosdp-3.1.2 → libosdp-3.2.3}/vendor/utils/include/utils/utils.h +65 -10
- {libosdp-3.1.2 → libosdp-3.2.3}/vendor/utils/src/crc16.c +1 -1
- {libosdp-3.1.2 → libosdp-3.2.3}/vendor/utils/src/disjoint_set.c +1 -1
- {libosdp-3.1.2 → libosdp-3.2.3}/vendor/utils/src/list.c +1 -1
- {libosdp-3.1.2 → libosdp-3.2.3}/vendor/utils/src/logger.c +4 -4
- {libosdp-3.1.2 → libosdp-3.2.3}/vendor/utils/src/queue.c +1 -1
- {libosdp-3.1.2 → libosdp-3.2.3}/vendor/utils/src/utils.c +146 -15
- libosdp-3.1.2/vendor/src/osdp_config.h +0 -43
- libosdp-3.1.2/vendor/utils/src/slab.c +0 -64
- {libosdp-3.1.2 → libosdp-3.2.3}/MANIFEST.in +0 -0
- {libosdp-3.1.2 → libosdp-3.2.3}/libosdp.egg-info/dependency_links.txt +0 -0
- {libosdp-3.1.2 → libosdp-3.2.3}/libosdp.egg-info/top_level.txt +0 -0
- {libosdp-3.1.2 → libosdp-3.2.3}/osdp/channel.py +0 -0
- {libosdp-3.1.2 → libosdp-3.2.3}/pyproject.toml +0 -0
- {libosdp-3.1.2 → libosdp-3.2.3}/setup.cfg +0 -0
- {libosdp-3.1.2 → libosdp-3.2.3}/vendor/src/crypto/tinyaes_src.c +0 -0
- {libosdp-3.1.2 → libosdp-3.2.3}/vendor/src/crypto/tinyaes_src.h +0 -0
- {libosdp-3.1.2 → libosdp-3.2.3}/vendor/utils/include/utils/crc16.h +0 -0
- {libosdp-3.1.2 → libosdp-3.2.3}/vendor/utils/src/pcap_gen.c +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: libosdp
|
|
3
|
-
Version: 3.
|
|
3
|
+
Version: 3.2.3
|
|
4
4
|
Summary: Library implementation of IEC 60839-11-5 OSDP (Open Supervised Device Protocol)
|
|
5
5
|
Home-page: https://github.com/goToMain/libosdp
|
|
6
6
|
Author: Siddharth Chandrasekaran
|
|
@@ -8,7 +8,7 @@ Author-email: sidcha.dev@gmail.com
|
|
|
8
8
|
Classifier: Programming Language :: Python :: 3
|
|
9
9
|
Classifier: License :: OSI Approved :: Apache Software License
|
|
10
10
|
Classifier: Operating System :: OS Independent
|
|
11
|
-
Requires-Python: >=3.
|
|
11
|
+
Requires-Python: >=3.10
|
|
12
12
|
Description-Content-Type: text/markdown
|
|
13
13
|
Dynamic: author
|
|
14
14
|
Dynamic: author-email
|
|
@@ -85,6 +85,18 @@ while True:
|
|
|
85
85
|
|
|
86
86
|
see [examples/cp_app.py][2] for more details.
|
|
87
87
|
|
|
88
|
+
Optional command completion callback:
|
|
89
|
+
|
|
90
|
+
```python
|
|
91
|
+
from osdp import CompletionStatus
|
|
92
|
+
|
|
93
|
+
def on_command_complete(address, command, status):
|
|
94
|
+
if status == CompletionStatus.Ok:
|
|
95
|
+
print("command completed")
|
|
96
|
+
|
|
97
|
+
cp.set_command_completion_handler(on_command_complete)
|
|
98
|
+
```
|
|
99
|
+
|
|
88
100
|
### Peripheral Device mode:
|
|
89
101
|
|
|
90
102
|
```python
|
|
@@ -116,6 +128,18 @@ while True:
|
|
|
116
128
|
|
|
117
129
|
see [examples/pd_app.py][3] for more details.
|
|
118
130
|
|
|
119
|
-
|
|
131
|
+
Optional event completion callback:
|
|
132
|
+
|
|
133
|
+
```python
|
|
134
|
+
from osdp import CompletionStatus
|
|
135
|
+
|
|
136
|
+
def on_event_complete(event, status):
|
|
137
|
+
if status == CompletionStatus.Flushed:
|
|
138
|
+
print("event removed by flush")
|
|
139
|
+
|
|
140
|
+
pd.set_event_completion_handler(on_event_complete)
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
[1]: https://doc.osdp.dev/api/
|
|
120
144
|
[2]: https://github.com/goToMain/libosdp/blob/master/examples/python/cp_app.py
|
|
121
145
|
[3]: https://github.com/goToMain/libosdp/blob/master/examples/python/pd_app.py
|
|
@@ -64,6 +64,18 @@ while True:
|
|
|
64
64
|
|
|
65
65
|
see [examples/cp_app.py][2] for more details.
|
|
66
66
|
|
|
67
|
+
Optional command completion callback:
|
|
68
|
+
|
|
69
|
+
```python
|
|
70
|
+
from osdp import CompletionStatus
|
|
71
|
+
|
|
72
|
+
def on_command_complete(address, command, status):
|
|
73
|
+
if status == CompletionStatus.Ok:
|
|
74
|
+
print("command completed")
|
|
75
|
+
|
|
76
|
+
cp.set_command_completion_handler(on_command_complete)
|
|
77
|
+
```
|
|
78
|
+
|
|
67
79
|
### Peripheral Device mode:
|
|
68
80
|
|
|
69
81
|
```python
|
|
@@ -95,6 +107,18 @@ while True:
|
|
|
95
107
|
|
|
96
108
|
see [examples/pd_app.py][3] for more details.
|
|
97
109
|
|
|
98
|
-
|
|
110
|
+
Optional event completion callback:
|
|
111
|
+
|
|
112
|
+
```python
|
|
113
|
+
from osdp import CompletionStatus
|
|
114
|
+
|
|
115
|
+
def on_event_complete(event, status):
|
|
116
|
+
if status == CompletionStatus.Flushed:
|
|
117
|
+
print("event removed by flush")
|
|
118
|
+
|
|
119
|
+
pd.set_event_completion_handler(on_event_complete)
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
[1]: https://doc.osdp.dev/api/
|
|
99
123
|
[2]: https://github.com/goToMain/libosdp/blob/master/examples/python/cp_app.py
|
|
100
124
|
[3]: https://github.com/goToMain/libosdp/blob/master/examples/python/pd_app.py
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: libosdp
|
|
3
|
-
Version: 3.
|
|
3
|
+
Version: 3.2.3
|
|
4
4
|
Summary: Library implementation of IEC 60839-11-5 OSDP (Open Supervised Device Protocol)
|
|
5
5
|
Home-page: https://github.com/goToMain/libosdp
|
|
6
6
|
Author: Siddharth Chandrasekaran
|
|
@@ -8,7 +8,7 @@ Author-email: sidcha.dev@gmail.com
|
|
|
8
8
|
Classifier: Programming Language :: Python :: 3
|
|
9
9
|
Classifier: License :: OSI Approved :: Apache Software License
|
|
10
10
|
Classifier: Operating System :: OS Independent
|
|
11
|
-
Requires-Python: >=3.
|
|
11
|
+
Requires-Python: >=3.10
|
|
12
12
|
Description-Content-Type: text/markdown
|
|
13
13
|
Dynamic: author
|
|
14
14
|
Dynamic: author-email
|
|
@@ -85,6 +85,18 @@ while True:
|
|
|
85
85
|
|
|
86
86
|
see [examples/cp_app.py][2] for more details.
|
|
87
87
|
|
|
88
|
+
Optional command completion callback:
|
|
89
|
+
|
|
90
|
+
```python
|
|
91
|
+
from osdp import CompletionStatus
|
|
92
|
+
|
|
93
|
+
def on_command_complete(address, command, status):
|
|
94
|
+
if status == CompletionStatus.Ok:
|
|
95
|
+
print("command completed")
|
|
96
|
+
|
|
97
|
+
cp.set_command_completion_handler(on_command_complete)
|
|
98
|
+
```
|
|
99
|
+
|
|
88
100
|
### Peripheral Device mode:
|
|
89
101
|
|
|
90
102
|
```python
|
|
@@ -116,6 +128,18 @@ while True:
|
|
|
116
128
|
|
|
117
129
|
see [examples/pd_app.py][3] for more details.
|
|
118
130
|
|
|
119
|
-
|
|
131
|
+
Optional event completion callback:
|
|
132
|
+
|
|
133
|
+
```python
|
|
134
|
+
from osdp import CompletionStatus
|
|
135
|
+
|
|
136
|
+
def on_event_complete(event, status):
|
|
137
|
+
if status == CompletionStatus.Flushed:
|
|
138
|
+
print("event removed by flush")
|
|
139
|
+
|
|
140
|
+
pd.set_event_completion_handler(on_event_complete)
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
[1]: https://doc.osdp.dev/api/
|
|
120
144
|
[2]: https://github.com/goToMain/libosdp/blob/master/examples/python/cp_app.py
|
|
121
145
|
[3]: https://github.com/goToMain/libosdp/blob/master/examples/python/pd_app.py
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
#
|
|
2
|
-
# Copyright (c) 2021-
|
|
2
|
+
# Copyright (c) 2021-2026 Siddharth Chandrasekaran <sidcha.dev@gmail.com>
|
|
3
3
|
#
|
|
4
4
|
# SPDX-License-Identifier: Apache-2.0
|
|
5
5
|
#
|
|
@@ -9,7 +9,7 @@ from .peripheral_device import PeripheralDevice
|
|
|
9
9
|
from .key_store import KeyStore
|
|
10
10
|
from .constants import (
|
|
11
11
|
LibFlag, Command, CommandLEDColor, CommandFileTxFlags, Event, EventNotification,
|
|
12
|
-
CardFormat, Capability, LogLevel, StatusReportType
|
|
12
|
+
CardFormat, Capability, LogLevel, StatusReportType, CompletionStatus
|
|
13
13
|
)
|
|
14
14
|
from .helpers import PdId, PDInfo, PDCapabilities
|
|
15
15
|
from .channel import Channel
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
#
|
|
2
|
-
# Copyright (c) 2021-
|
|
2
|
+
# Copyright (c) 2021-2026 Siddharth Chandrasekaran <sidcha.dev@gmail.com>
|
|
3
3
|
#
|
|
4
4
|
# SPDX-License-Identifier: Apache-2.0
|
|
5
5
|
#
|
|
@@ -60,6 +60,12 @@ class EventNotification:
|
|
|
60
60
|
SecureChannelStatus = osdp_sys.EVENT_NOTIFICATION_SC_STATUS
|
|
61
61
|
PeripheralDeviceStatus = osdp_sys.EVENT_NOTIFICATION_PD_STATUS
|
|
62
62
|
|
|
63
|
+
class CompletionStatus:
|
|
64
|
+
Ok = getattr(osdp_sys, "COMPLETION_OK", 0)
|
|
65
|
+
Failed = getattr(osdp_sys, "COMPLETION_FAILED", 1)
|
|
66
|
+
Flushed = getattr(osdp_sys, "COMPLETION_FLUSHED", 2)
|
|
67
|
+
Aborted = getattr(osdp_sys, "COMPLETION_ABORTED", 3)
|
|
68
|
+
|
|
63
69
|
class Event:
|
|
64
70
|
CardRead = osdp_sys.EVENT_CARDREAD
|
|
65
71
|
KeyPress = osdp_sys.EVENT_KEYPRESS
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
#
|
|
2
|
-
# Copyright (c) 2021-
|
|
2
|
+
# Copyright (c) 2021-2026 Siddharth Chandrasekaran <sidcha.dev@gmail.com>
|
|
3
3
|
#
|
|
4
4
|
# SPDX-License-Identifier: Apache-2.0
|
|
5
5
|
#
|
|
@@ -17,7 +17,8 @@ class ControlPanel():
|
|
|
17
17
|
self,
|
|
18
18
|
pd_info_list: list[PDInfo],
|
|
19
19
|
log_level: LogLevel=LogLevel.Info,
|
|
20
|
-
event_handler: Callable[[int, dict], int]=None
|
|
20
|
+
event_handler: Callable[[int, dict], int]=None,
|
|
21
|
+
command_completion_handler: Callable[[int, dict, int], None]=None
|
|
21
22
|
) -> None:
|
|
22
23
|
self.pd_addr = []
|
|
23
24
|
info_list = []
|
|
@@ -27,11 +28,17 @@ class ControlPanel():
|
|
|
27
28
|
info_list.append(pd_info.get())
|
|
28
29
|
self.event_queue = [ queue.Queue() for i in self.pd_addr ]
|
|
29
30
|
self.user_event_handler = None
|
|
31
|
+
self.user_command_completion_handler = None
|
|
30
32
|
osdp_sys.set_loglevel(log_level)
|
|
31
33
|
self.ctx = osdp_sys.ControlPanel(info_list)
|
|
32
34
|
# Always use our internal handler to ensure queue functionality
|
|
33
35
|
self.ctx.set_event_callback(self._internal_event_handler)
|
|
36
|
+
if hasattr(self.ctx, "set_command_completion_callback"):
|
|
37
|
+
self.ctx.set_command_completion_callback(
|
|
38
|
+
self._internal_command_completion_handler
|
|
39
|
+
)
|
|
34
40
|
self.set_event_handler(event_handler)
|
|
41
|
+
self.set_command_completion_handler(command_completion_handler)
|
|
35
42
|
self.event = None
|
|
36
43
|
self.lock = None
|
|
37
44
|
self.thread = None
|
|
@@ -39,15 +46,18 @@ class ControlPanel():
|
|
|
39
46
|
@staticmethod
|
|
40
47
|
def refresh(event, lock, ctx):
|
|
41
48
|
while not event.is_set():
|
|
42
|
-
lock
|
|
43
|
-
|
|
44
|
-
lock.release()
|
|
49
|
+
with lock:
|
|
50
|
+
ctx.refresh()
|
|
45
51
|
time.sleep(0.020) #sleep for 20ms
|
|
46
52
|
|
|
47
53
|
def set_event_handler(self, handler: Callable[[int, dict], int]):
|
|
48
54
|
"""Set user event handler while maintaining queue functionality"""
|
|
49
55
|
self.user_event_handler = handler
|
|
50
56
|
|
|
57
|
+
def set_command_completion_handler(
|
|
58
|
+
self, handler: Callable[[int, dict, int], None]):
|
|
59
|
+
self.user_command_completion_handler = handler
|
|
60
|
+
|
|
51
61
|
def _internal_event_handler(self, pd, event) -> int:
|
|
52
62
|
"""Internal handler that manages both queue and user callback"""
|
|
53
63
|
# Always put event in queue for get_event() compatibility
|
|
@@ -63,6 +73,15 @@ class ControlPanel():
|
|
|
63
73
|
|
|
64
74
|
return 0
|
|
65
75
|
|
|
76
|
+
def _internal_command_completion_handler(self, pd, command, status) -> None:
|
|
77
|
+
if self.user_command_completion_handler:
|
|
78
|
+
try:
|
|
79
|
+
self.user_command_completion_handler(
|
|
80
|
+
self.pd_addr[pd], command, status
|
|
81
|
+
)
|
|
82
|
+
except Exception as e:
|
|
83
|
+
print(f"Error in user command completion handler: {e}")
|
|
84
|
+
|
|
66
85
|
def get_event(self, address, timeout: int=5):
|
|
67
86
|
pd = self.pd_addr.index(address)
|
|
68
87
|
block = timeout >= 0
|
|
@@ -73,10 +92,8 @@ class ControlPanel():
|
|
|
73
92
|
return event
|
|
74
93
|
|
|
75
94
|
def status(self):
|
|
76
|
-
self.lock
|
|
77
|
-
|
|
78
|
-
self.lock.release()
|
|
79
|
-
return bitmask
|
|
95
|
+
with self.lock:
|
|
96
|
+
return self.ctx.status()
|
|
80
97
|
|
|
81
98
|
def is_online(self, address):
|
|
82
99
|
pd = self.pd_addr.index(address)
|
|
@@ -84,9 +101,8 @@ class ControlPanel():
|
|
|
84
101
|
|
|
85
102
|
def get_pd_id(self, address: int) -> PdId:
|
|
86
103
|
pd = self.pd_addr.index(address)
|
|
87
|
-
self.lock
|
|
88
|
-
|
|
89
|
-
self.lock.release()
|
|
104
|
+
with self.lock:
|
|
105
|
+
pd_id_dict = self.ctx.get_pd_id(pd)
|
|
90
106
|
if pd_id_dict:
|
|
91
107
|
# version: int, model: int, vendor_code: int, serial_number: int, firmware_version: int
|
|
92
108
|
pd_id = PdId(
|
|
@@ -100,9 +116,8 @@ class ControlPanel():
|
|
|
100
116
|
|
|
101
117
|
def check_capability(self, address: int, cap: Capability) -> Tuple[int, int]:
|
|
102
118
|
pd = self.pd_addr.index(address)
|
|
103
|
-
self.lock
|
|
104
|
-
|
|
105
|
-
self.lock.release()
|
|
119
|
+
with self.lock:
|
|
120
|
+
compliance_level, num_items = self.ctx.check_capability(pd, cap)
|
|
106
121
|
return (compliance_level, num_items)
|
|
107
122
|
|
|
108
123
|
def get_num_online(self):
|
|
@@ -114,10 +129,8 @@ class ControlPanel():
|
|
|
114
129
|
return online
|
|
115
130
|
|
|
116
131
|
def sc_status(self):
|
|
117
|
-
self.lock
|
|
118
|
-
|
|
119
|
-
self.lock.release()
|
|
120
|
-
return bitmask
|
|
132
|
+
with self.lock:
|
|
133
|
+
return self.ctx.sc_status()
|
|
121
134
|
|
|
122
135
|
def is_sc_active(self, address):
|
|
123
136
|
pd = self.pd_addr.index(address)
|
|
@@ -133,10 +146,13 @@ class ControlPanel():
|
|
|
133
146
|
|
|
134
147
|
def submit_command(self, address, cmd):
|
|
135
148
|
pd = self.pd_addr.index(address)
|
|
136
|
-
self.lock
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
149
|
+
with self.lock:
|
|
150
|
+
return self.ctx.submit_command(pd, cmd)
|
|
151
|
+
|
|
152
|
+
def flush_commands(self, address):
|
|
153
|
+
pd = self.pd_addr.index(address)
|
|
154
|
+
with self.lock:
|
|
155
|
+
return self.ctx.flush_commands(pd)
|
|
140
156
|
|
|
141
157
|
def send_command(self, address, cmd):
|
|
142
158
|
from warnings import warn
|
|
@@ -145,52 +161,38 @@ class ControlPanel():
|
|
|
145
161
|
|
|
146
162
|
def set_flag(self, address, flag: LibFlag):
|
|
147
163
|
pd = self.pd_addr.index(address)
|
|
148
|
-
self.lock
|
|
149
|
-
|
|
150
|
-
self.lock.release()
|
|
151
|
-
return ret
|
|
164
|
+
with self.lock:
|
|
165
|
+
return self.ctx.set_flag(pd, flag)
|
|
152
166
|
|
|
153
167
|
def clear_flag(self, address, flag: LibFlag):
|
|
154
168
|
pd = self.pd_addr.index(address)
|
|
155
|
-
self.lock
|
|
156
|
-
|
|
157
|
-
self.lock.release()
|
|
158
|
-
return ret
|
|
169
|
+
with self.lock:
|
|
170
|
+
return self.ctx.clear_flag(pd, flag)
|
|
159
171
|
|
|
160
172
|
def disable_pd(self, address: int) -> bool:
|
|
161
173
|
pd = self.pd_addr.index(address)
|
|
162
|
-
self.lock
|
|
163
|
-
|
|
164
|
-
self.lock.release()
|
|
165
|
-
return ret
|
|
174
|
+
with self.lock:
|
|
175
|
+
return self.ctx.disable_pd(pd)
|
|
166
176
|
|
|
167
177
|
def enable_pd(self, address: int) -> bool:
|
|
168
178
|
pd = self.pd_addr.index(address)
|
|
169
|
-
self.lock
|
|
170
|
-
|
|
171
|
-
self.lock.release()
|
|
172
|
-
return ret
|
|
179
|
+
with self.lock:
|
|
180
|
+
return self.ctx.enable_pd(pd)
|
|
173
181
|
|
|
174
182
|
def is_pd_enabled(self, address: int) -> bool:
|
|
175
183
|
pd = self.pd_addr.index(address)
|
|
176
|
-
self.lock
|
|
177
|
-
|
|
178
|
-
self.lock.release()
|
|
179
|
-
return ret
|
|
184
|
+
with self.lock:
|
|
185
|
+
return self.ctx.is_pd_enabled(pd)
|
|
180
186
|
|
|
181
187
|
def register_file_ops(self, address, fops):
|
|
182
188
|
pd = self.pd_addr.index(address)
|
|
183
|
-
self.lock
|
|
184
|
-
|
|
185
|
-
self.lock.release()
|
|
186
|
-
return ret
|
|
189
|
+
with self.lock:
|
|
190
|
+
return self.ctx.register_file_ops(pd, fops)
|
|
187
191
|
|
|
188
192
|
def get_file_tx_status(self, address):
|
|
189
193
|
pd = self.pd_addr.index(address)
|
|
190
|
-
self.lock
|
|
191
|
-
|
|
192
|
-
self.lock.release()
|
|
193
|
-
return ret
|
|
194
|
+
with self.lock:
|
|
195
|
+
return self.ctx.get_file_tx_status(pd)
|
|
194
196
|
|
|
195
197
|
def start(self):
|
|
196
198
|
if self.thread:
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
#
|
|
2
|
-
# Copyright (c) 2021-
|
|
2
|
+
# Copyright (c) 2021-2026 Siddharth Chandrasekaran <sidcha.dev@gmail.com>
|
|
3
3
|
#
|
|
4
4
|
# SPDX-License-Identifier: Apache-2.0
|
|
5
5
|
#
|
|
@@ -16,15 +16,22 @@ from .constants import LogLevel
|
|
|
16
16
|
class PeripheralDevice():
|
|
17
17
|
def __init__(self, pd_info: PDInfo, pd_cap: PDCapabilities,
|
|
18
18
|
log_level: LogLevel=LogLevel.Info,
|
|
19
|
-
command_handler: Callable[[dict], Tuple[int, dict]]=None
|
|
19
|
+
command_handler: Callable[[dict], Tuple[int, dict]]=None,
|
|
20
|
+
event_completion_handler: Callable[[dict, int], None]=None):
|
|
20
21
|
self.command_queue = queue.Queue()
|
|
21
22
|
self.address = pd_info.address
|
|
22
23
|
self.user_command_handler = None
|
|
24
|
+
self.user_event_completion_handler = None
|
|
23
25
|
osdp_sys.set_loglevel(log_level)
|
|
24
26
|
self.ctx = osdp_sys.PeripheralDevice(pd_info.get(), capabilities=pd_cap.get())
|
|
25
27
|
# Always use our internal handler to ensure queue functionality
|
|
26
28
|
self.ctx.set_command_callback(self._internal_command_handler)
|
|
29
|
+
if hasattr(self.ctx, "set_event_completion_callback"):
|
|
30
|
+
self.ctx.set_event_completion_callback(
|
|
31
|
+
self._internal_event_completion_handler
|
|
32
|
+
)
|
|
27
33
|
self.set_command_handler(command_handler)
|
|
34
|
+
self.set_event_completion_handler(event_completion_handler)
|
|
28
35
|
self.event = None
|
|
29
36
|
self.lock = None
|
|
30
37
|
self.thread = None
|
|
@@ -32,9 +39,8 @@ class PeripheralDevice():
|
|
|
32
39
|
@staticmethod
|
|
33
40
|
def refresh(event, lock, ctx):
|
|
34
41
|
while not event.is_set():
|
|
35
|
-
lock
|
|
36
|
-
|
|
37
|
-
lock.release()
|
|
42
|
+
with lock:
|
|
43
|
+
ctx.refresh()
|
|
38
44
|
time.sleep(0.020) #sleep for 20ms
|
|
39
45
|
|
|
40
46
|
def _internal_command_handler(self, command) -> Tuple[int, dict]:
|
|
@@ -56,6 +62,16 @@ class PeripheralDevice():
|
|
|
56
62
|
"""Set user command handler while maintaining queue functionality"""
|
|
57
63
|
self.user_command_handler = handler
|
|
58
64
|
|
|
65
|
+
def set_event_completion_handler(self, handler: Callable[[dict, int], None]):
|
|
66
|
+
self.user_event_completion_handler = handler
|
|
67
|
+
|
|
68
|
+
def _internal_event_completion_handler(self, event, status) -> None:
|
|
69
|
+
if self.user_event_completion_handler:
|
|
70
|
+
try:
|
|
71
|
+
self.user_event_completion_handler(event, status)
|
|
72
|
+
except Exception as e:
|
|
73
|
+
print(f"Error in user event completion handler: {e}")
|
|
74
|
+
|
|
59
75
|
def get_command(self, timeout: int=5):
|
|
60
76
|
block = timeout >= 0
|
|
61
77
|
try:
|
|
@@ -65,10 +81,8 @@ class PeripheralDevice():
|
|
|
65
81
|
return cmd
|
|
66
82
|
|
|
67
83
|
def submit_event(self, event):
|
|
68
|
-
self.lock
|
|
69
|
-
|
|
70
|
-
self.lock.release()
|
|
71
|
-
return ret
|
|
84
|
+
with self.lock:
|
|
85
|
+
return self.ctx.submit_event(event)
|
|
72
86
|
|
|
73
87
|
def notify_event(self, event):
|
|
74
88
|
from warnings import warn
|
|
@@ -76,10 +90,8 @@ class PeripheralDevice():
|
|
|
76
90
|
return self.submit_event(event)
|
|
77
91
|
|
|
78
92
|
def register_file_ops(self, fops):
|
|
79
|
-
self.lock
|
|
80
|
-
|
|
81
|
-
self.lock.release()
|
|
82
|
-
return ret
|
|
93
|
+
with self.lock:
|
|
94
|
+
return self.ctx.register_file_ops(0, fops)
|
|
83
95
|
|
|
84
96
|
def is_sc_active(self):
|
|
85
97
|
return self.ctx.is_sc_active()
|
|
@@ -108,10 +120,8 @@ class PeripheralDevice():
|
|
|
108
120
|
self.thread.start()
|
|
109
121
|
|
|
110
122
|
def get_file_tx_status(self):
|
|
111
|
-
self.lock
|
|
112
|
-
|
|
113
|
-
self.lock.release()
|
|
114
|
-
return ret
|
|
123
|
+
with self.lock:
|
|
124
|
+
return self.ctx.get_file_tx_status(0)
|
|
115
125
|
|
|
116
126
|
def stop(self):
|
|
117
127
|
if not self.thread:
|
|
@@ -1,17 +1,18 @@
|
|
|
1
1
|
#
|
|
2
|
-
# Copyright (c) 2020-
|
|
2
|
+
# Copyright (c) 2020-2026 Siddharth Chandrasekaran <sidcha.dev@gmail.com>
|
|
3
3
|
#
|
|
4
4
|
# SPDX-License-Identifier: Apache-2.0
|
|
5
5
|
#
|
|
6
6
|
|
|
7
7
|
import os
|
|
8
8
|
import re
|
|
9
|
+
import sys
|
|
9
10
|
from setuptools import setup, Extension
|
|
10
11
|
import shutil
|
|
11
12
|
import subprocess
|
|
12
13
|
|
|
13
14
|
project_name = "libosdp"
|
|
14
|
-
project_version = "3.
|
|
15
|
+
project_version = "3.2.3"
|
|
15
16
|
current_dir = os.path.dirname(os.path.realpath(__file__))
|
|
16
17
|
repo_root = os.path.realpath(os.path.join(current_dir, ".."))
|
|
17
18
|
|
|
@@ -23,17 +24,47 @@ def add_prefix_to_path(src_list, path, check_files=True):
|
|
|
23
24
|
raise RuntimeError(f"Path '{path}' does not exist")
|
|
24
25
|
return paths
|
|
25
26
|
|
|
26
|
-
def exec_cmd(cmd):
|
|
27
|
-
r = subprocess.run(cmd, capture_output
|
|
28
|
-
return r.stdout.strip()
|
|
27
|
+
def exec_cmd(cmd, cwd=None):
|
|
28
|
+
r = subprocess.run(cmd, capture_output=True, text=True, cwd=cwd)
|
|
29
|
+
return r.returncode, r.stdout.strip()
|
|
29
30
|
|
|
30
31
|
def get_git_info():
|
|
31
|
-
d = {
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
32
|
+
d = {
|
|
33
|
+
"branch": "None",
|
|
34
|
+
"tag": "",
|
|
35
|
+
"diff": "",
|
|
36
|
+
"rev": "",
|
|
37
|
+
"root": repo_root,
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
rc, _ = exec_cmd(["git", "rev-parse", "--is-inside-work-tree"], cwd=repo_root)
|
|
41
|
+
if rc != 0:
|
|
42
|
+
return d
|
|
43
|
+
|
|
44
|
+
rc, root = exec_cmd(["git", "rev-parse", "--show-toplevel"], cwd=repo_root)
|
|
45
|
+
if rc == 0 and root:
|
|
46
|
+
d["root"] = root
|
|
47
|
+
|
|
48
|
+
rc, branch = exec_cmd(["git", "symbolic-ref", "--short", "-q", "HEAD"], cwd=repo_root)
|
|
49
|
+
if rc == 0 and branch:
|
|
50
|
+
d["branch"] = branch
|
|
51
|
+
else:
|
|
52
|
+
d["branch"] = "detached"
|
|
53
|
+
|
|
54
|
+
rc, rev = exec_cmd(["git", "describe", "--tags", "--long", "--always", "--abbrev=7"], cwd=repo_root)
|
|
55
|
+
if rc == 0:
|
|
56
|
+
d["rev"] = rev
|
|
57
|
+
|
|
58
|
+
rc, tag = exec_cmd(["git", "describe", "--exact-match", "--tags", "HEAD"], cwd=repo_root)
|
|
59
|
+
if rc == 0 and tag:
|
|
60
|
+
d["tag"] = tag
|
|
61
|
+
|
|
62
|
+
rc, status = exec_cmd(["git", "status", "--porcelain", "--untracked-files=normal"], cwd=repo_root)
|
|
63
|
+
if rc == 0 and status:
|
|
64
|
+
d["diff"] = "+"
|
|
65
|
+
if d["tag"]:
|
|
66
|
+
d["tag"] = d["tag"] + "+"
|
|
67
|
+
|
|
37
68
|
return d
|
|
38
69
|
|
|
39
70
|
def configure_file(file, replacements):
|
|
@@ -78,7 +109,6 @@ def try_vendor_sources(src_dir, src_files, vendor_dir):
|
|
|
78
109
|
utils_sources = [
|
|
79
110
|
"utils/src/list.c",
|
|
80
111
|
"utils/src/queue.c",
|
|
81
|
-
"utils/src/slab.c",
|
|
82
112
|
"utils/src/utils.c",
|
|
83
113
|
"utils/src/logger.c",
|
|
84
114
|
"utils/src/disjoint_set.c",
|
|
@@ -138,6 +168,19 @@ other_files = [
|
|
|
138
168
|
"utils/src/pcap_gen.c",
|
|
139
169
|
]
|
|
140
170
|
|
|
171
|
+
definitions = [
|
|
172
|
+
"OPT_OSDP_PACKET_TRACE",
|
|
173
|
+
"OPT_OSDP_RX_ZERO_COPY",
|
|
174
|
+
# "OPT_OSDP_DATA_TRACE",
|
|
175
|
+
# "OPT_OSDP_SKIP_MARK_BYTE",
|
|
176
|
+
]
|
|
177
|
+
|
|
178
|
+
app_owned_queue_data = os.getenv("OPT_OSDP_APP_OWNED_QUEUE_DATA", "").lower()
|
|
179
|
+
if app_owned_queue_data in ("0", "false", "no", "off"):
|
|
180
|
+
utils_sources.append("utils/src/slab.c")
|
|
181
|
+
else:
|
|
182
|
+
definitions.append("OPT_OSDP_APP_OWNED_QUEUE_DATA")
|
|
183
|
+
|
|
141
184
|
source_files = utils_sources + lib_sources + osdp_sys_sources
|
|
142
185
|
|
|
143
186
|
try_vendor_sources(
|
|
@@ -146,12 +189,6 @@ try_vendor_sources(
|
|
|
146
189
|
"vendor"
|
|
147
190
|
)
|
|
148
191
|
|
|
149
|
-
definitions = [
|
|
150
|
-
"OPT_OSDP_PACKET_TRACE",
|
|
151
|
-
# "OPT_OSDP_DATA_TRACE",
|
|
152
|
-
# "OPT_OSDP_SKIP_MARK_BYTE",
|
|
153
|
-
]
|
|
154
|
-
|
|
155
192
|
if ("OPT_OSDP_PACKET_TRACE" in definitions or
|
|
156
193
|
"OPT_OSDP_DATA_TRACE" in definitions):
|
|
157
194
|
source_files += [
|
|
@@ -171,9 +208,15 @@ include_dirs = [
|
|
|
171
208
|
|
|
172
209
|
compile_args = (
|
|
173
210
|
[ "-I" + path for path in include_dirs ] +
|
|
174
|
-
[ "-D" + define for define in definitions ]
|
|
211
|
+
[ "-D" + define + "=1" for define in definitions ]
|
|
175
212
|
)
|
|
176
213
|
|
|
214
|
+
# PyPI Windows wheels are built with MSVC via cibuildwheel. Its legacy
|
|
215
|
+
# preprocessor breaks the IS_ENABLED() macro in utils/include/utils/utils.h;
|
|
216
|
+
# /Zc:preprocessor switches to the C99/C11-conformant preprocessor.
|
|
217
|
+
if sys.platform == "win32":
|
|
218
|
+
compile_args.append("/Zc:preprocessor")
|
|
219
|
+
|
|
177
220
|
if os.path.exists("README.md"):
|
|
178
221
|
with open("README.md", "r") as f:
|
|
179
222
|
long_description = f.read()
|
|
@@ -205,6 +248,6 @@ setup(
|
|
|
205
248
|
],
|
|
206
249
|
long_description = long_description,
|
|
207
250
|
long_description_content_type = "text/markdown",
|
|
208
|
-
python_requires = ">=3.
|
|
251
|
+
python_requires = ">=3.10",
|
|
209
252
|
package_data = { project_name : other_files }
|
|
210
253
|
)
|