libosdp 3.1.0__tar.gz → 3.2.0__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.
Files changed (58) hide show
  1. {libosdp-3.1.0 → libosdp-3.2.0}/PKG-INFO +26 -2
  2. {libosdp-3.1.0 → libosdp-3.2.0}/README.md +25 -1
  3. {libosdp-3.1.0 → libosdp-3.2.0}/libosdp.egg-info/PKG-INFO +26 -2
  4. {libosdp-3.1.0 → libosdp-3.2.0}/libosdp.egg-info/SOURCES.txt +0 -1
  5. {libosdp-3.1.0 → libosdp-3.2.0}/osdp/__init__.py +2 -2
  6. {libosdp-3.1.0 → libosdp-3.2.0}/osdp/constants.py +7 -1
  7. {libosdp-3.1.0 → libosdp-3.2.0}/osdp/control_panel.py +53 -51
  8. {libosdp-3.1.0 → libosdp-3.2.0}/osdp/helpers.py +1 -1
  9. {libosdp-3.1.0 → libosdp-3.2.0}/osdp/key_store.py +1 -1
  10. {libosdp-3.1.0 → libosdp-3.2.0}/osdp/peripheral_device.py +27 -17
  11. {libosdp-3.1.0 → libosdp-3.2.0}/setup.py +55 -19
  12. {libosdp-3.1.0 → libosdp-3.2.0}/vendor/include/osdp.h +95 -1
  13. {libosdp-3.1.0 → libosdp-3.2.0}/vendor/include/osdp_export.h +3 -3
  14. {libosdp-3.1.0 → libosdp-3.2.0}/vendor/python/osdp_sys/base.c +24 -13
  15. {libosdp-3.1.0 → libosdp-3.2.0}/vendor/python/osdp_sys/cp.c +202 -24
  16. {libosdp-3.1.0 → libosdp-3.2.0}/vendor/python/osdp_sys/data.c +2 -13
  17. {libosdp-3.1.0 → libosdp-3.2.0}/vendor/python/osdp_sys/module.c +8 -1
  18. {libosdp-3.1.0 → libosdp-3.2.0}/vendor/python/osdp_sys/module.h +18 -1
  19. {libosdp-3.1.0 → libosdp-3.2.0}/vendor/python/osdp_sys/pd.c +154 -7
  20. {libosdp-3.1.0 → libosdp-3.2.0}/vendor/python/osdp_sys/utils.c +115 -2
  21. {libosdp-3.1.0 → libosdp-3.2.0}/vendor/src/crypto/tinyaes.c +1 -1
  22. {libosdp-3.1.0 → libosdp-3.2.0}/vendor/src/osdp_common.c +1 -1
  23. {libosdp-3.1.0 → libosdp-3.2.0}/vendor/src/osdp_common.h +177 -65
  24. libosdp-3.2.0/vendor/src/osdp_config.h +102 -0
  25. {libosdp-3.1.0 → libosdp-3.2.0}/vendor/src/osdp_cp.c +253 -141
  26. {libosdp-3.1.0 → libosdp-3.2.0}/vendor/src/osdp_diag.c +1 -1
  27. {libosdp-3.1.0 → libosdp-3.2.0}/vendor/src/osdp_diag.h +1 -1
  28. {libosdp-3.1.0 → libosdp-3.2.0}/vendor/src/osdp_file.c +18 -19
  29. {libosdp-3.1.0 → libosdp-3.2.0}/vendor/src/osdp_file.h +1 -1
  30. {libosdp-3.1.0 → libosdp-3.2.0}/vendor/src/osdp_pd.c +217 -91
  31. {libosdp-3.1.0 → libosdp-3.2.0}/vendor/src/osdp_phy.c +156 -55
  32. {libosdp-3.1.0 → libosdp-3.2.0}/vendor/src/osdp_sc.c +4 -8
  33. {libosdp-3.1.0 → libosdp-3.2.0}/vendor/utils/include/utils/assert.h +1 -1
  34. {libosdp-3.1.0 → libosdp-3.2.0}/vendor/utils/include/utils/disjoint_set.h +1 -1
  35. {libosdp-3.1.0 → libosdp-3.2.0}/vendor/utils/include/utils/list.h +1 -1
  36. {libosdp-3.1.0 → libosdp-3.2.0}/vendor/utils/include/utils/logger.h +1 -1
  37. {libosdp-3.1.0 → libosdp-3.2.0}/vendor/utils/include/utils/pcap_gen.h +1 -1
  38. {libosdp-3.1.0 → libosdp-3.2.0}/vendor/utils/include/utils/queue.h +1 -1
  39. {libosdp-3.1.0 → libosdp-3.2.0}/vendor/utils/include/utils/slab.h +1 -1
  40. {libosdp-3.1.0 → libosdp-3.2.0}/vendor/utils/include/utils/utils.h +5 -5
  41. {libosdp-3.1.0 → libosdp-3.2.0}/vendor/utils/src/crc16.c +1 -1
  42. {libosdp-3.1.0 → libosdp-3.2.0}/vendor/utils/src/disjoint_set.c +1 -1
  43. {libosdp-3.1.0 → libosdp-3.2.0}/vendor/utils/src/list.c +1 -1
  44. {libosdp-3.1.0 → libosdp-3.2.0}/vendor/utils/src/logger.c +1 -1
  45. {libosdp-3.1.0 → libosdp-3.2.0}/vendor/utils/src/queue.c +1 -1
  46. {libosdp-3.1.0 → libosdp-3.2.0}/vendor/utils/src/utils.c +35 -1
  47. libosdp-3.1.0/vendor/src/osdp_config.h +0 -43
  48. libosdp-3.1.0/vendor/utils/src/slab.c +0 -64
  49. {libosdp-3.1.0 → libosdp-3.2.0}/MANIFEST.in +0 -0
  50. {libosdp-3.1.0 → libosdp-3.2.0}/libosdp.egg-info/dependency_links.txt +0 -0
  51. {libosdp-3.1.0 → libosdp-3.2.0}/libosdp.egg-info/top_level.txt +0 -0
  52. {libosdp-3.1.0 → libosdp-3.2.0}/osdp/channel.py +0 -0
  53. {libosdp-3.1.0 → libosdp-3.2.0}/pyproject.toml +0 -0
  54. {libosdp-3.1.0 → libosdp-3.2.0}/setup.cfg +0 -0
  55. {libosdp-3.1.0 → libosdp-3.2.0}/vendor/src/crypto/tinyaes_src.c +0 -0
  56. {libosdp-3.1.0 → libosdp-3.2.0}/vendor/src/crypto/tinyaes_src.h +0 -0
  57. {libosdp-3.1.0 → libosdp-3.2.0}/vendor/utils/include/utils/crc16.h +0 -0
  58. {libosdp-3.1.0 → libosdp-3.2.0}/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.1.0
3
+ Version: 3.2.0
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
@@ -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
- [1]: https://libosdp.sidcha.dev/api/
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
- [1]: https://libosdp.sidcha.dev/api/
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.1.0
3
+ Version: 3.2.0
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
@@ -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
- [1]: https://libosdp.sidcha.dev/api/
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
@@ -51,5 +51,4 @@ vendor/utils/src/list.c
51
51
  vendor/utils/src/logger.c
52
52
  vendor/utils/src/pcap_gen.c
53
53
  vendor/utils/src/queue.c
54
- vendor/utils/src/slab.c
55
54
  vendor/utils/src/utils.c
@@ -1,5 +1,5 @@
1
1
  #
2
- # Copyright (c) 2021-2024 Siddharth Chandrasekaran <sidcha.dev@gmail.com>
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-2024 Siddharth Chandrasekaran <sidcha.dev@gmail.com>
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-2024 Siddharth Chandrasekaran <sidcha.dev@gmail.com>
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.acquire()
43
- ctx.refresh()
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.acquire()
77
- bitmask = self.ctx.status()
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.acquire()
88
- pd_id_dict = self.ctx.get_pd_id(pd)
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.acquire()
104
- compliance_level, num_items = self.ctx.check_capability(pd, cap)
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.acquire()
118
- bitmask = self.ctx.sc_status()
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.acquire()
137
- ret = self.ctx.submit_command(pd, cmd)
138
- self.lock.release()
139
- return ret
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.acquire()
149
- ret = self.ctx.set_flag(pd, flag)
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.acquire()
156
- ret = self.ctx.clear_flag(pd, flag)
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.acquire()
163
- ret = self.ctx.disable_pd(pd)
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.acquire()
170
- ret = self.ctx.enable_pd(pd)
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.acquire()
177
- ret = self.ctx.is_pd_enabled(pd)
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.acquire()
184
- ret = self.ctx.register_file_ops(pd, fops)
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.acquire()
191
- ret = self.ctx.get_file_tx_status(pd)
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-2024 Siddharth Chandrasekaran <sidcha.dev@gmail.com>
2
+ # Copyright (c) 2021-2026 Siddharth Chandrasekaran <sidcha.dev@gmail.com>
3
3
  #
4
4
  # SPDX-License-Identifier: Apache-2.0
5
5
  #
@@ -1,5 +1,5 @@
1
1
  #
2
- # Copyright (c) 2021-2024 Siddharth Chandrasekaran <sidcha.dev@gmail.com>
2
+ # Copyright (c) 2021-2026 Siddharth Chandrasekaran <sidcha.dev@gmail.com>
3
3
  #
4
4
  # SPDX-License-Identifier: Apache-2.0
5
5
  #
@@ -1,5 +1,5 @@
1
1
  #
2
- # Copyright (c) 2021-2024 Siddharth Chandrasekaran <sidcha.dev@gmail.com>
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.acquire()
36
- ctx.refresh()
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.acquire()
69
- ret = self.ctx.submit_event(event)
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.acquire()
80
- ret = self.ctx.register_file_ops(0, fops)
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.acquire()
112
- ret = self.ctx.get_file_tx_status(0)
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,5 +1,5 @@
1
1
  #
2
- # Copyright (c) 2020-2024 Siddharth Chandrasekaran <sidcha.dev@gmail.com>
2
+ # Copyright (c) 2020-2026 Siddharth Chandrasekaran <sidcha.dev@gmail.com>
3
3
  #
4
4
  # SPDX-License-Identifier: Apache-2.0
5
5
  #
@@ -11,7 +11,7 @@ import shutil
11
11
  import subprocess
12
12
 
13
13
  project_name = "libosdp"
14
- project_version = "3.1.0"
14
+ project_version = "3.2.0"
15
15
  current_dir = os.path.dirname(os.path.realpath(__file__))
16
16
  repo_root = os.path.realpath(os.path.join(current_dir, ".."))
17
17
 
@@ -23,17 +23,47 @@ def add_prefix_to_path(src_list, path, check_files=True):
23
23
  raise RuntimeError(f"Path '{path}' does not exist")
24
24
  return paths
25
25
 
26
- def exec_cmd(cmd):
27
- r = subprocess.run(cmd, capture_output = True, text = True)
28
- return r.stdout.strip()
26
+ def exec_cmd(cmd, cwd=None):
27
+ r = subprocess.run(cmd, capture_output=True, text=True, cwd=cwd)
28
+ return r.returncode, r.stdout.strip()
29
29
 
30
30
  def get_git_info():
31
- d = {}
32
- d["branch"] = exec_cmd(["git", "rev-parse", "--abbrev-ref", "HEAD"])
33
- d["tag"] = exec_cmd([ "git", "describe", "--exact-match", "--tags" ])
34
- d["diff"] = exec_cmd([ "git", "diff", "--quiet", "--exit-code" ])
35
- d["rev"] = exec_cmd(["git", "log", "--pretty=format:%h", "-n", "1"])
36
- d["root"] = exec_cmd(["git", "rev-parse", "--show-toplevel"])
31
+ d = {
32
+ "branch": "None",
33
+ "tag": "",
34
+ "diff": "",
35
+ "rev": "",
36
+ "root": repo_root,
37
+ }
38
+
39
+ rc, _ = exec_cmd(["git", "rev-parse", "--is-inside-work-tree"], cwd=repo_root)
40
+ if rc != 0:
41
+ return d
42
+
43
+ rc, root = exec_cmd(["git", "rev-parse", "--show-toplevel"], cwd=repo_root)
44
+ if rc == 0 and root:
45
+ d["root"] = root
46
+
47
+ rc, branch = exec_cmd(["git", "symbolic-ref", "--short", "-q", "HEAD"], cwd=repo_root)
48
+ if rc == 0 and branch:
49
+ d["branch"] = branch
50
+ else:
51
+ d["branch"] = "detached"
52
+
53
+ rc, rev = exec_cmd(["git", "describe", "--tags", "--long", "--always", "--abbrev=7"], cwd=repo_root)
54
+ if rc == 0:
55
+ d["rev"] = rev
56
+
57
+ rc, tag = exec_cmd(["git", "describe", "--exact-match", "--tags", "HEAD"], cwd=repo_root)
58
+ if rc == 0 and tag:
59
+ d["tag"] = tag
60
+
61
+ rc, status = exec_cmd(["git", "status", "--porcelain", "--untracked-files=normal"], cwd=repo_root)
62
+ if rc == 0 and status:
63
+ d["diff"] = "+"
64
+ if d["tag"]:
65
+ d["tag"] = d["tag"] + "+"
66
+
37
67
  return d
38
68
 
39
69
  def configure_file(file, replacements):
@@ -78,7 +108,6 @@ def try_vendor_sources(src_dir, src_files, vendor_dir):
78
108
  utils_sources = [
79
109
  "utils/src/list.c",
80
110
  "utils/src/queue.c",
81
- "utils/src/slab.c",
82
111
  "utils/src/utils.c",
83
112
  "utils/src/logger.c",
84
113
  "utils/src/disjoint_set.c",
@@ -138,6 +167,19 @@ other_files = [
138
167
  "utils/src/pcap_gen.c",
139
168
  ]
140
169
 
170
+ definitions = [
171
+ "OPT_OSDP_PACKET_TRACE",
172
+ "OPT_OSDP_RX_ZERO_COPY",
173
+ # "OPT_OSDP_DATA_TRACE",
174
+ # "OPT_OSDP_SKIP_MARK_BYTE",
175
+ ]
176
+
177
+ app_owned_queue_data = os.getenv("OPT_OSDP_APP_OWNED_QUEUE_DATA", "").lower()
178
+ if app_owned_queue_data in ("0", "false", "no", "off"):
179
+ utils_sources.append("utils/src/slab.c")
180
+ else:
181
+ definitions.append("OPT_OSDP_APP_OWNED_QUEUE_DATA")
182
+
141
183
  source_files = utils_sources + lib_sources + osdp_sys_sources
142
184
 
143
185
  try_vendor_sources(
@@ -146,12 +188,6 @@ try_vendor_sources(
146
188
  "vendor"
147
189
  )
148
190
 
149
- definitions = [
150
- "OPT_OSDP_PACKET_TRACE",
151
- # "OPT_OSDP_DATA_TRACE",
152
- # "OPT_OSDP_SKIP_MARK_BYTE",
153
- ]
154
-
155
191
  if ("OPT_OSDP_PACKET_TRACE" in definitions or
156
192
  "OPT_OSDP_DATA_TRACE" in definitions):
157
193
  source_files += [
@@ -171,7 +207,7 @@ include_dirs = [
171
207
 
172
208
  compile_args = (
173
209
  [ "-I" + path for path in include_dirs ] +
174
- [ "-D" + define for define in definitions ]
210
+ [ "-D" + define + "=1" for define in definitions ]
175
211
  )
176
212
 
177
213
  if os.path.exists("README.md"):