libosdp 3.0.6__tar.gz → 3.0.8__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 (55) hide show
  1. {libosdp-3.0.6 → libosdp-3.0.8}/PKG-INFO +1 -1
  2. {libosdp-3.0.6 → libosdp-3.0.8}/libosdp.egg-info/PKG-INFO +1 -1
  3. {libosdp-3.0.6 → libosdp-3.0.8}/libosdp.egg-info/SOURCES.txt +2 -2
  4. {libosdp-3.0.6 → libosdp-3.0.8}/osdp/__init__.py +3 -3
  5. {libosdp-3.0.6 → libosdp-3.0.8}/osdp/constants.py +9 -0
  6. {libosdp-3.0.6 → libosdp-3.0.8}/osdp/control_panel.py +32 -7
  7. {libosdp-3.0.6 → libosdp-3.0.8}/osdp/key_store.py +8 -6
  8. {libosdp-3.0.6 → libosdp-3.0.8}/osdp/peripheral_device.py +1 -1
  9. {libosdp-3.0.6 → libosdp-3.0.8}/setup.py +7 -6
  10. {libosdp-3.0.6 → libosdp-3.0.8}/vendor/include/osdp.h +84 -6
  11. {libosdp-3.0.6 → libosdp-3.0.8}/vendor/python/osdp_sys/cp.c +57 -0
  12. {libosdp-3.0.6 → libosdp-3.0.8}/vendor/python/osdp_sys/data.c +63 -3
  13. {libosdp-3.0.6 → libosdp-3.0.8}/vendor/python/osdp_sys/module.c +10 -1
  14. {libosdp-3.0.6 → libosdp-3.0.8}/vendor/python/osdp_sys/module.h +1 -0
  15. {libosdp-3.0.6 → libosdp-3.0.8}/vendor/src/osdp_common.c +2 -2
  16. {libosdp-3.0.6 → libosdp-3.0.8}/vendor/src/osdp_common.h +83 -6
  17. {libosdp-3.0.6 → libosdp-3.0.8}/vendor/src/osdp_config.h +7 -5
  18. {libosdp-3.0.6 → libosdp-3.0.8}/vendor/src/osdp_cp.c +176 -96
  19. {libosdp-3.0.6 → libosdp-3.0.8}/vendor/src/osdp_file.c +160 -61
  20. {libosdp-3.0.6 → libosdp-3.0.8}/vendor/src/osdp_file.h +7 -3
  21. {libosdp-3.0.6 → libosdp-3.0.8}/vendor/src/osdp_pd.c +32 -35
  22. {libosdp-3.0.6 → libosdp-3.0.8}/vendor/src/osdp_phy.c +37 -27
  23. {libosdp-3.0.6 → libosdp-3.0.8}/vendor/src/osdp_sc.c +4 -0
  24. {libosdp-3.0.6 → libosdp-3.0.8}/vendor/utils/include/utils/utils.h +9 -6
  25. {libosdp-3.0.6 → libosdp-3.0.8}/vendor/utils/src/logger.c +24 -25
  26. {libosdp-3.0.6 → libosdp-3.0.8}/vendor/utils/src/utils.c +36 -2
  27. {libosdp-3.0.6 → libosdp-3.0.8}/MANIFEST.in +0 -0
  28. {libosdp-3.0.6 → libosdp-3.0.8}/README.md +0 -0
  29. {libosdp-3.0.6 → libosdp-3.0.8}/libosdp.egg-info/dependency_links.txt +0 -0
  30. {libosdp-3.0.6 → libosdp-3.0.8}/libosdp.egg-info/top_level.txt +0 -0
  31. {libosdp-3.0.6 → libosdp-3.0.8}/osdp/channel.py +0 -0
  32. {libosdp-3.0.6 → libosdp-3.0.8}/osdp/helpers.py +0 -0
  33. {libosdp-3.0.6 → libosdp-3.0.8}/pyproject.toml +0 -0
  34. {libosdp-3.0.6 → libosdp-3.0.8}/setup.cfg +0 -0
  35. {libosdp-3.0.6 → libosdp-3.0.8}/vendor/python/osdp_sys/base.c +0 -0
  36. {libosdp-3.0.6 → libosdp-3.0.8}/vendor/python/osdp_sys/pd.c +0 -0
  37. {libosdp-3.0.6 → libosdp-3.0.8}/vendor/python/osdp_sys/utils.c +0 -0
  38. {libosdp-3.0.6 → libosdp-3.0.8}/vendor/src/crypto/tinyaes.c +0 -0
  39. {libosdp-3.0.6 → libosdp-3.0.8}/vendor/src/crypto/tinyaes_src.c +0 -0
  40. {libosdp-3.0.6 → libosdp-3.0.8}/vendor/src/crypto/tinyaes_src.h +0 -0
  41. /libosdp-3.0.6/vendor/src/osdp_pcap.c → /libosdp-3.0.8/vendor/src/osdp_diag.c +0 -0
  42. /libosdp-3.0.6/vendor/src/osdp_pcap.h → /libosdp-3.0.8/vendor/src/osdp_diag.h +0 -0
  43. {libosdp-3.0.6 → libosdp-3.0.8}/vendor/src/osdp_export.h +0 -0
  44. {libosdp-3.0.6 → libosdp-3.0.8}/vendor/utils/include/utils/assert.h +0 -0
  45. {libosdp-3.0.6 → libosdp-3.0.8}/vendor/utils/include/utils/disjoint_set.h +0 -0
  46. {libosdp-3.0.6 → libosdp-3.0.8}/vendor/utils/include/utils/list.h +0 -0
  47. {libosdp-3.0.6 → libosdp-3.0.8}/vendor/utils/include/utils/logger.h +0 -0
  48. {libosdp-3.0.6 → libosdp-3.0.8}/vendor/utils/include/utils/pcap_gen.h +0 -0
  49. {libosdp-3.0.6 → libosdp-3.0.8}/vendor/utils/include/utils/queue.h +0 -0
  50. {libosdp-3.0.6 → libosdp-3.0.8}/vendor/utils/include/utils/slab.h +0 -0
  51. {libosdp-3.0.6 → libosdp-3.0.8}/vendor/utils/src/disjoint_set.c +0 -0
  52. {libosdp-3.0.6 → libosdp-3.0.8}/vendor/utils/src/list.c +0 -0
  53. {libosdp-3.0.6 → libosdp-3.0.8}/vendor/utils/src/pcap_gen.c +0 -0
  54. {libosdp-3.0.6 → libosdp-3.0.8}/vendor/utils/src/queue.c +0 -0
  55. {libosdp-3.0.6 → libosdp-3.0.8}/vendor/utils/src/slab.c +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: libosdp
3
- Version: 3.0.6
3
+ Version: 3.0.8
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
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: libosdp
3
- Version: 3.0.6
3
+ Version: 3.0.8
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
@@ -25,11 +25,11 @@ vendor/src/osdp_common.c
25
25
  vendor/src/osdp_common.h
26
26
  vendor/src/osdp_config.h
27
27
  vendor/src/osdp_cp.c
28
+ vendor/src/osdp_diag.c
29
+ vendor/src/osdp_diag.h
28
30
  vendor/src/osdp_export.h
29
31
  vendor/src/osdp_file.c
30
32
  vendor/src/osdp_file.h
31
- vendor/src/osdp_pcap.c
32
- vendor/src/osdp_pcap.h
33
33
  vendor/src/osdp_pd.c
34
34
  vendor/src/osdp_phy.c
35
35
  vendor/src/osdp_sc.c
@@ -8,10 +8,10 @@ from .control_panel import ControlPanel
8
8
  from .peripheral_device import PeripheralDevice
9
9
  from .key_store import KeyStore
10
10
  from .constants import (
11
- LibFlag, Command, CommandLEDColor, CommandFileTxFlags,
12
- Event, CardFormat, Capability, LogLevel, StatusReportType
11
+ LibFlag, Command, CommandLEDColor, CommandFileTxFlags, Event, EventNotification,
12
+ CardFormat, Capability, LogLevel, StatusReportType
13
13
  )
14
- from .helpers import PDInfo, PDCapabilities
14
+ from .helpers import PdId, PDInfo, PDCapabilities
15
15
  from .channel import Channel
16
16
 
17
17
  __author__ = 'Siddharth Chandrasekaran <sidcha.dev@gmail.com>'
@@ -10,6 +10,9 @@ class LibFlag:
10
10
  EnforceSecure = osdp_sys.FLAG_ENFORCE_SECURE
11
11
  InstallMode = osdp_sys.FLAG_INSTALL_MODE
12
12
  IgnoreUnsolicited = osdp_sys.FLAG_IGN_UNSOLICITED
13
+ EnableNotification = osdp_sys.FLAG_ENABLE_NOTIFICATION
14
+ CapturePackets = osdp_sys.FLAG_CAPTURE_PACKETS
15
+ AllowEmptyEncryptedDataBlock = osdp_sys.FLAG_ALLOW_EMPTY_ENCRYPTED_DATA_BLOCK
13
16
 
14
17
  class LogLevel:
15
18
  Emergency = osdp_sys.LOG_EMERG
@@ -51,11 +54,17 @@ class CommandLEDColor:
51
54
  class CommandFileTxFlags:
52
55
  Cancel = osdp_sys.CMD_FILE_TX_FLAG_CANCEL
53
56
 
57
+ class EventNotification:
58
+ Command = osdp_sys.EVENT_NOTIFICATION_COMMAND
59
+ SecureChannelStatus = osdp_sys.EVENT_NOTIFICATION_SC_STATUS
60
+ PeripheralDeviceStatus = osdp_sys.EVENT_NOTIFICATION_PD_STATUS
61
+
54
62
  class Event:
55
63
  CardRead = osdp_sys.EVENT_CARDREAD
56
64
  KeyPress = osdp_sys.EVENT_KEYPRESS
57
65
  ManufacturerReply = osdp_sys.EVENT_MFGREP
58
66
  Status = osdp_sys.EVENT_STATUS
67
+ Notification = osdp_sys.EVENT_NOTIFICATION
59
68
 
60
69
  class CardFormat:
61
70
  Unspecified = osdp_sys.CARD_FMT_RAW_UNSPECIFIED
@@ -3,17 +3,14 @@
3
3
  #
4
4
  # SPDX-License-Identifier: Apache-2.0
5
5
  #
6
- import sys
7
- import os
8
- import tempfile
9
6
  import osdp_sys
10
7
  import time
11
8
  import queue
12
9
  import threading
13
- from typing import Callable
10
+ from typing import Callable, Tuple
14
11
 
15
- from .helpers import PDInfo
16
- from .constants import LibFlag, LogLevel
12
+ from .helpers import PDInfo, PdId
13
+ from .constants import Capability, LibFlag, LogLevel
17
14
 
18
15
  class ControlPanel():
19
16
  def __init__(
@@ -73,6 +70,29 @@ class ControlPanel():
73
70
  pd = self.pd_addr.index(address)
74
71
  return bool(self.status() & (1 << pd))
75
72
 
73
+ def get_pd_id(self, address: int) -> PdId:
74
+ pd = self.pd_addr.index(address)
75
+ self.lock.acquire()
76
+ pd_id_dict = self.ctx.get_pd_id(pd)
77
+ self.lock.release()
78
+ if pd_id_dict:
79
+ # version: int, model: int, vendor_code: int, serial_number: int, firmware_version: int
80
+ pd_id = PdId(
81
+ pd_id_dict['version'],
82
+ pd_id_dict['model'],
83
+ pd_id_dict['vendor_code'],
84
+ pd_id_dict['serial_number'],
85
+ pd_id_dict['firmware_version']
86
+ )
87
+ return pd_id
88
+
89
+ def check_capability(self, address: int, cap: Capability) -> Tuple[int, int]:
90
+ pd = self.pd_addr.index(address)
91
+ self.lock.acquire()
92
+ compliance_level, num_items = self.ctx.check_capability(pd, cap)
93
+ self.lock.release()
94
+ return (compliance_level, num_items)
95
+
76
96
  def get_num_online(self):
77
97
  online = 0
78
98
  bitmask = self.status()
@@ -164,7 +184,7 @@ class ControlPanel():
164
184
  count += 1
165
185
  return res
166
186
 
167
- def online_wait(self, address, timeout=5):
187
+ def online_wait(self, address, timeout=8):
168
188
  count = 0
169
189
  res = False
170
190
  while count < timeout * 2:
@@ -175,6 +195,11 @@ class ControlPanel():
175
195
  count += 1
176
196
  return res
177
197
 
198
+ def offline_wait(self, address, timeout=8):
199
+ count = 0
200
+ time.sleep(timeout)
201
+ return self.is_online(address) == False
202
+
178
203
  def sc_wait(self, address, timeout=5):
179
204
  count = 0
180
205
  res = False
@@ -28,11 +28,8 @@ class KeyStore():
28
28
  key.append(random.randint(0, 255))
29
29
  return bytes(key)
30
30
 
31
- def store_key(self, name):
32
- if name not in self.keys:
33
- raise RuntimeError
34
- key = self.keys[name]
35
- with open(self.key_file(name), "w") as f:
31
+ def _store_key(self, key):
32
+ with open(self.key_file(key), "w") as f:
36
33
  f.write(key.hex())
37
34
 
38
35
  def get_key(self, name):
@@ -46,6 +43,11 @@ class KeyStore():
46
43
  self.keys[name] = self.gen_key(key_len)
47
44
  return self.keys[name]
48
45
 
46
+ def commit_key(self, name):
47
+ if name not in self.keys:
48
+ raise RuntimeError
49
+ self._store_key(self.keys[name])
50
+
49
51
  def update_key(self, name, key):
50
52
  if name not in self.keys:
51
53
  raise RuntimeError
@@ -63,4 +65,4 @@ class KeyStore():
63
65
 
64
66
  def __del__(self):
65
67
  if self.temp_dir:
66
- self.temp_dir.cleanup()
68
+ self.temp_dir.cleanup()
@@ -74,7 +74,7 @@ class PeripheralDevice():
74
74
  def is_online(self):
75
75
  return self.ctx.is_online()
76
76
 
77
- def sc_wait(self, timeout=5):
77
+ def sc_wait(self, timeout=8):
78
78
  count = 0
79
79
  res = False
80
80
  while count < timeout * 2:
@@ -11,7 +11,7 @@ import shutil
11
11
  import subprocess
12
12
 
13
13
  project_name = "libosdp"
14
- project_version = "3.0.6"
14
+ project_version = "3.0.8"
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
 
@@ -132,8 +132,8 @@ other_files = [
132
132
  "src/osdp_config.h.in",
133
133
 
134
134
  # Optional when PACKET_TRACE is enabled
135
- "src/osdp_pcap.c",
136
- "src/osdp_pcap.h",
135
+ "src/osdp_diag.c",
136
+ "src/osdp_diag.h",
137
137
  "utils/include/utils/pcap_gen.h",
138
138
  "utils/src/pcap_gen.c",
139
139
  ]
@@ -147,14 +147,15 @@ try_vendor_sources(
147
147
  )
148
148
 
149
149
  definitions = [
150
- # "CONFIG_OSDP_PACKET_TRACE",
150
+ "CONFIG_OSDP_PACKET_TRACE",
151
151
  # "CONFIG_OSDP_DATA_TRACE",
152
152
  # "CONFIG_OSDP_SKIP_MARK_BYTE",
153
153
  ]
154
154
 
155
- if "CONFIG_OSDP_PACKET_TRACE" in definitions:
155
+ if ("CONFIG_OSDP_PACKET_TRACE" in definitions or
156
+ "CONFIG_OSDP_DATA_TRACE" in definitions):
156
157
  source_files += [
157
- "src/osdp_pcap.c",
158
+ "src/osdp_diag.c",
158
159
  "utils/src/pcap_gen.c",
159
160
  ]
160
161
 
@@ -52,6 +52,37 @@ extern "C" {
52
52
  */
53
53
  #define OSDP_FLAG_IGN_UNSOLICITED 0x00040000
54
54
 
55
+ /**
56
+ * @brief Enable LibOSDP notification events - @ref osdp_event_notification - to
57
+ * be reported using the event callback method registered by the application.
58
+ *
59
+ * @note These events, unlike others, are not generated by the PD.
60
+ *
61
+ * @note This is a CP mode only flag; in PD mode this flag has no use.
62
+ */
63
+ #define OSDP_FLAG_ENABLE_NOTIFICATION 0x00080000
64
+
65
+ /**
66
+ * @brief Capture raw osdp packets as seen by this device to a pcap file.
67
+ * LibOSDP must be built with CONFIG_OSDP_PACKET_TRACE or CONFIG_OSDP_DATA_TRACE
68
+ * for this flag to be in effect.
69
+ *
70
+ * @note The app must call osdp_{cp,pd}_teardown() before existing for the
71
+ * capture file to be finalized and written to the disk.
72
+ */
73
+ #define OSDP_FLAG_CAPTURE_PACKETS 0x00100000
74
+
75
+ /**
76
+ * @brief Allow an empty encrypted data block(SCS_17 and SCS_18 packets).
77
+ * This is non-conforming to the standard. If there is no data to be
78
+ * transferred, the CP should instead use the SCS_15/SCS_16 messages.
79
+ * Some OSDP implementations are buggy and send a 0-length data block with
80
+ * the SCS_17 and SCS_18 messages, this flag accepts that buggy behavior.
81
+ *
82
+ * @note this is a PD mode only flag
83
+ */
84
+ #define OSDP_FLAG_ALLOW_EMPTY_ENCRYPTED_DATA_BLOCK 0x00200000
85
+
55
86
  /**
56
87
  * @brief Various PD capability function codes.
57
88
  */
@@ -365,7 +396,7 @@ enum osdp_status_report_type {
365
396
  /**
366
397
  * @brief Status report structure. Used by OSDP_CMD_STATUS and
367
398
  * OSDP_EVENT_STATUS. In case of command, it is used to send a query to the PD
368
- * while in the case of events, the PR responds back with this structure.
399
+ * while in the case of events, the PD responds back with this structure.
369
400
  *
370
401
  * This can is used by the PD to indicate various status change reports. Upto a
371
402
  * maximum of 32 statuses can be reported using this API.
@@ -651,8 +682,8 @@ enum osdp_cmd_e {
651
682
  OSDP_CMD_KEYSET, /**< Encryption Key Set Command */
652
683
  OSDP_CMD_COMSET, /**< PD communication configuration command */
653
684
  OSDP_CMD_MFG, /**< Manufacturer specific command */
654
- OSDP_CMD_FILE_TX, /**< File transfer comand */
655
- OSDP_CMD_STATUS, /**< Status report eommand */
685
+ OSDP_CMD_FILE_TX, /**< File transfer command */
686
+ OSDP_CMD_STATUS, /**< Status report command */
656
687
  OSDP_CMD_SENTINEL /**< Max command value */
657
688
  };
658
689
 
@@ -779,6 +810,49 @@ struct osdp_event_mfgrep {
779
810
  uint8_t data[OSDP_EVENT_MFGREP_MAX_DATALEN];
780
811
  };
781
812
 
813
+ /**
814
+ * @brief LibOSDP event notification type
815
+ */
816
+ enum osdp_event_notification_type {
817
+ /**
818
+ * Application command outcome report.
819
+ *
820
+ * arg0: The command ID
821
+ * arg1: outcome -- 0: success; -1: failure;
822
+ */
823
+ OSDP_EVENT_NOTIFICATION_COMMAND,
824
+ /**
825
+ * Secure Channel state change
826
+ *
827
+ * arg0: status -- 0: inactive; 1: active
828
+ * arg1: scbk type -- 0: scbk; 1: scbk-d
829
+ */
830
+ OSDP_EVENT_NOTIFICATION_SC_STATUS,
831
+ /**
832
+ * PD state change
833
+ *
834
+ * arg0: status -- 0: offline; 1: online
835
+ */
836
+ OSDP_EVENT_NOTIFICATION_PD_STATUS,
837
+ };
838
+
839
+ /**
840
+ * @brief LibOSDP event notification
841
+ *
842
+ * These are events generated by LibOSDP for the application to indicate various
843
+ * status such as external command outcomes, SC state change notifications, etc.
844
+ * The app can use these events to perform housekeeping activities as needed.
845
+ *
846
+ * Each notification event type can use the provided additional data members
847
+ * @a arg0, @a arg1, ... in custom ways. See @ref osdp_event_notification_type
848
+ * for documentation on how to use them.
849
+ */
850
+ struct osdp_event_notification {
851
+ enum osdp_event_notification_type type; /**< Notification type */
852
+ int arg0; /**< Additional data member */
853
+ int arg1; /**< Additional data member */
854
+ };
855
+
782
856
  /**
783
857
  * @brief OSDP PD Events
784
858
  */
@@ -787,6 +861,7 @@ enum osdp_event_type {
787
861
  OSDP_EVENT_KEYPRESS, /**< Keypad press event */
788
862
  OSDP_EVENT_MFGREP, /**< Manufacturer specific reply event */
789
863
  OSDP_EVENT_STATUS, /**< Status event */
864
+ OSDP_EVENT_NOTIFICATION, /**< LibOSDP notification event */
790
865
  OSDP_EVENT_SENTINEL /**< Max event value */
791
866
  };
792
867
 
@@ -802,8 +877,9 @@ struct osdp_event {
802
877
  union {
803
878
  struct osdp_event_keypress keypress; /**< Keypress event structure */
804
879
  struct osdp_event_cardread cardread; /**< Card read event structure */
805
- struct osdp_event_mfgrep mfgrep; /**< Manufacturer spefific response event struture */
806
- struct osdp_status_report status; /**< Status report event strcture */
880
+ struct osdp_event_mfgrep mfgrep; /**< Manufacturer specific response event struture */
881
+ struct osdp_status_report status; /**< Status report event structure */
882
+ struct osdp_event_notification notif;/**< Notification event structure */
807
883
  };
808
884
  };
809
885
 
@@ -1167,7 +1243,9 @@ void osdp_get_sc_status_mask(const osdp_t *ctx, uint8_t *bitmask);
1167
1243
  * @param arg Opaque pointer that was provided in @ref osdp_file_ops when the
1168
1244
  * ops struct was registered.
1169
1245
  * @param file_id File ID of pre-agreed file between this CP and PD
1170
- * @param size Size of the file that was opened (filled by application)
1246
+ * @param size Size of the file that was opened (to be populated by sender). In
1247
+ * case of receiver, this value is just just input to indicate the incoming file
1248
+ * size.
1171
1249
  *
1172
1250
  * @retval 0 on success
1173
1251
  * @retval -1 on errors
@@ -39,6 +39,9 @@ int pyosdp_cp_event_cb(void *data, int address, struct osdp_event *event)
39
39
  pyosdp_cp_t *self = data;
40
40
  PyObject *arglist, *result, *event_dict;
41
41
 
42
+ if (!self->event_cb)
43
+ return 0;
44
+
42
45
  if (pyosdp_make_dict_event(&event_dict, event))
43
46
  return -1;
44
47
 
@@ -86,6 +89,56 @@ static PyObject *pyosdp_cp_refresh(pyosdp_cp_t *self, pyosdp_cp_t *args)
86
89
  Py_RETURN_NONE;
87
90
  }
88
91
 
92
+ #define pyosdp_cp_get_pd_id_doc \
93
+ "Get PD_ID info as reported by the PD\n" \
94
+ "\n" \
95
+ "@param pd PD offset number\n" \
96
+ "\n" \
97
+ "@return dict with PD_ID info\n"
98
+ static PyObject *pyosdp_cp_get_pd_id(pyosdp_cp_t *self, PyObject *args)
99
+ {
100
+ int pd;
101
+ struct osdp_pd_id pd_id = {0};
102
+
103
+ if (!PyArg_ParseTuple(args, "I", &pd)) {
104
+ PyErr_SetString(PyExc_ValueError, "Invalid arguments");
105
+ Py_RETURN_NONE;
106
+ }
107
+
108
+ if (osdp_cp_get_pd_id(self->ctx, pd, &pd_id)) {
109
+ PyErr_SetString(PyExc_ValueError, "invalid PD offset");
110
+ Py_RETURN_NONE;
111
+ }
112
+
113
+ return pyosdp_make_dict_pd_id(&pd_id);
114
+ }
115
+
116
+ #define pyosdp_cp_check_capability_doc \
117
+ "Get capability associated to a function_code as reported by the PD\n" \
118
+ "\n" \
119
+ "@param pd PD offset number\n" \
120
+ "@param capability function code\n" \
121
+ "\n" \
122
+ "@return (compliance_level, num_items)\n"
123
+ static PyObject *pyosdp_cp_check_capability(pyosdp_cp_t *self, PyObject *args)
124
+ {
125
+ int pd, function_code;
126
+ struct osdp_pd_cap cap = {0};
127
+
128
+ if (!PyArg_ParseTuple(args, "II", &pd, &function_code)) {
129
+ PyErr_SetString(PyExc_ValueError, "Invalid arguments");
130
+ Py_RETURN_NONE;
131
+ }
132
+
133
+ cap.function_code = function_code;
134
+ if (osdp_cp_get_capability(self->ctx, pd, &cap)) {
135
+ PyErr_SetString(PyExc_ValueError, "invalid PD offset or function code");
136
+ Py_RETURN_NONE;
137
+ }
138
+
139
+ return Py_BuildValue("(II)", cap.compliance_level, cap.num_items);
140
+ }
141
+
89
142
  #define pyosdp_cp_send_command_doc \
90
143
  "Send an OSDP command to a PD\n" \
91
144
  "\n" \
@@ -327,6 +380,10 @@ static PyMethodDef pyosdp_cp_tp_methods[] = {
327
380
  METH_NOARGS, pyosdp_cp_set_flag_doc },
328
381
  { "clear_flag", (PyCFunction)pyosdp_cp_clear_flag,
329
382
  METH_NOARGS, pyosdp_cp_clear_flag_doc },
383
+ { "get_pd_id", (PyCFunction)pyosdp_cp_get_pd_id,
384
+ METH_VARARGS, pyosdp_cp_get_pd_id_doc },
385
+ { "check_capability", (PyCFunction)pyosdp_cp_check_capability,
386
+ METH_VARARGS, pyosdp_cp_check_capability_doc },
330
387
  { NULL, NULL, 0, NULL } /* Sentinel */
331
388
  };
332
389
 
@@ -44,9 +44,13 @@ static int pyosdp_make_struct_cmd_output(struct osdp_cmd *p, PyObject *dict)
44
44
  static int pyosdp_make_dict_cmd_led(PyObject *obj, struct osdp_cmd *cmd)
45
45
  {
46
46
  bool is_temporary = false;
47
+ bool cancel_temporary = false;
47
48
  struct osdp_cmd_led_params *p = &cmd->led.permanent;
48
49
 
49
- if (cmd->led.temporary.control_code != 0) {
50
+ if (cmd->led.temporary.control_code == 1 &&
51
+ cmd->led.permanent.control_code != 0) {
52
+ cancel_temporary = true;
53
+ } else if (cmd->led.temporary.control_code) {
50
54
  p = &cmd->led.temporary;
51
55
  is_temporary = true;
52
56
  }
@@ -66,8 +70,14 @@ static int pyosdp_make_dict_cmd_led(PyObject *obj, struct osdp_cmd *cmd)
66
70
  return -1;
67
71
  if (pyosdp_dict_add_int(obj, "off_count", p->off_count))
68
72
  return -1;
69
- if (is_temporary && pyosdp_dict_add_int(obj, "timer_count", p->timer_count))
70
- return -1;
73
+ if (is_temporary) {
74
+ if (pyosdp_dict_add_int(obj, "timer_count", p->timer_count))
75
+ return -1;
76
+ }
77
+ if (cancel_temporary) {
78
+ if (pyosdp_dict_add_bool(obj, "cancel_temporary", cancel_temporary))
79
+ return -1;
80
+ }
71
81
  return 0;
72
82
  }
73
83
 
@@ -543,6 +553,37 @@ static int pyosdp_make_struct_event_status(struct osdp_event *p, PyObject *dict)
543
553
  return 0;
544
554
  }
545
555
 
556
+ static int pyosdp_make_dict_event_notif(PyObject *obj, struct osdp_event *event)
557
+ {
558
+ if (pyosdp_dict_add_int(obj, "type", event->notif.type))
559
+ return -1;
560
+ if (pyosdp_dict_add_int(obj, "arg0", event->notif.arg0))
561
+ return -1;
562
+ if (pyosdp_dict_add_int(obj, "arg1", event->notif.arg1))
563
+ return -1;
564
+ return 0;
565
+ }
566
+
567
+ static int pyosdp_make_struct_event_notif(struct osdp_event *p, PyObject *dict)
568
+ {
569
+ int type, arg0, arg1;
570
+ struct osdp_event_notification *ev = &p->notif;
571
+
572
+ if (pyosdp_dict_get_int(dict, "type", &type))
573
+ return -1;
574
+
575
+ if (pyosdp_dict_get_int(dict, "arg0", &arg0))
576
+ return -1;
577
+
578
+ if (pyosdp_dict_get_int(dict, "arg1", &arg1))
579
+ return -1;
580
+
581
+ ev->type = type;
582
+ ev->arg0 = arg0;
583
+ ev->arg1 = arg1;
584
+ return 0;
585
+ }
586
+
546
587
  static struct {
547
588
  int (*dict_to_struct)(struct osdp_cmd *, PyObject *);
548
589
  int (*struct_to_dict)(PyObject *, struct osdp_cmd *);
@@ -605,6 +646,10 @@ static struct {
605
646
  .struct_to_dict = pyosdp_make_dict_event_status,
606
647
  .dict_to_struct = pyosdp_make_struct_event_status,
607
648
  },
649
+ [OSDP_EVENT_NOTIFICATION] = {
650
+ .struct_to_dict = pyosdp_make_dict_event_notif,
651
+ .dict_to_struct = pyosdp_make_struct_event_notif,
652
+ },
608
653
  };
609
654
 
610
655
  /* --- Exposed Methods --- */
@@ -679,3 +724,18 @@ int pyosdp_make_dict_event(PyObject **dict, struct osdp_event *event)
679
724
  *dict = obj;
680
725
  return 0;
681
726
  }
727
+
728
+ PyObject *pyosdp_make_dict_pd_id(struct osdp_pd_id *pd_id)
729
+ {
730
+ PyObject *obj = PyDict_New();
731
+ if (obj == NULL)
732
+ return NULL;
733
+
734
+ pyosdp_dict_add_int(obj, "version", pd_id->version);
735
+ pyosdp_dict_add_int(obj, "model", pd_id->model);
736
+ pyosdp_dict_add_int(obj, "vendor_code", pd_id->vendor_code);
737
+ pyosdp_dict_add_int(obj, "serial_number", pd_id->serial_number);
738
+ pyosdp_dict_add_int(obj, "firmware_version", pd_id->firmware_version);
739
+
740
+ return obj;
741
+ }
@@ -22,6 +22,9 @@ void pyosdp_add_module_constants(PyObject *module)
22
22
  ADD_CONST("FLAG_ENFORCE_SECURE", OSDP_FLAG_ENFORCE_SECURE);
23
23
  ADD_CONST("FLAG_INSTALL_MODE", OSDP_FLAG_INSTALL_MODE);
24
24
  ADD_CONST("FLAG_IGN_UNSOLICITED", OSDP_FLAG_IGN_UNSOLICITED);
25
+ ADD_CONST("FLAG_ENABLE_NOTIFICATION", OSDP_FLAG_ENABLE_NOTIFICATION);
26
+ ADD_CONST("FLAG_CAPTURE_PACKETS", OSDP_FLAG_CAPTURE_PACKETS);
27
+ ADD_CONST("FLAG_ALLOW_EMPTY_ENCRYPTED_DATA_BLOCK", OSDP_FLAG_ALLOW_EMPTY_ENCRYPTED_DATA_BLOCK);
25
28
 
26
29
  ADD_CONST("LOG_EMERG", OSDP_LOG_EMERG);
27
30
  ADD_CONST("LOG_ALERT", OSDP_LOG_ALERT);
@@ -49,14 +52,20 @@ void pyosdp_add_module_constants(PyObject *module)
49
52
  ADD_CONST("STATUS_REPORT_OUTPUT", OSDP_STATUS_REPORT_OUTPUT)
50
53
  ADD_CONST("STATUS_REPORT_REMOTE", OSDP_STATUS_REPORT_REMOTE)
51
54
 
52
- /* For `struct osdp_cmd_file_tx`::flags */
55
+ /* For `struct osdp_cmd_file_tx::flags` */
53
56
  ADD_CONST("CMD_FILE_TX_FLAG_CANCEL", OSDP_CMD_FILE_TX_FLAG_CANCEL);
54
57
 
58
+ /* For `struct osdp_event_notification::type` */
59
+ ADD_CONST("EVENT_NOTIFICATION_COMMAND", OSDP_EVENT_NOTIFICATION_COMMAND);
60
+ ADD_CONST("EVENT_NOTIFICATION_SC_STATUS", OSDP_EVENT_NOTIFICATION_SC_STATUS);
61
+ ADD_CONST("EVENT_NOTIFICATION_PD_STATUS", OSDP_EVENT_NOTIFICATION_PD_STATUS);
62
+
55
63
  /* enum osdp_event_type */
56
64
  ADD_CONST("EVENT_CARDREAD", OSDP_EVENT_CARDREAD);
57
65
  ADD_CONST("EVENT_KEYPRESS", OSDP_EVENT_KEYPRESS);
58
66
  ADD_CONST("EVENT_MFGREP", OSDP_EVENT_MFGREP);
59
67
  ADD_CONST("EVENT_STATUS", OSDP_EVENT_STATUS);
68
+ ADD_CONST("EVENT_NOTIFICATION", OSDP_EVENT_NOTIFICATION);
60
69
 
61
70
  /* enum osdp_led_color_e */
62
71
  ADD_CONST("LED_COLOR_NONE", OSDP_LED_COLOR_NONE);
@@ -91,5 +91,6 @@ int pyosdp_make_struct_cmd(struct osdp_cmd *cmd, PyObject *dict);
91
91
  int pyosdp_make_dict_cmd(PyObject **dict, struct osdp_cmd *cmd);
92
92
  int pyosdp_make_dict_event(PyObject **dict, struct osdp_event *event);
93
93
  int pyosdp_make_struct_event(struct osdp_event *event, PyObject *dict);
94
+ PyObject *pyosdp_make_dict_pd_id(struct osdp_pd_id *pd_id);
94
95
 
95
96
  #endif /* _PYOSDP_H_ */
@@ -32,7 +32,7 @@ uint16_t osdp_compute_crc16(const uint8_t *buf, size_t len)
32
32
  return crc16_itu_t(0x1D0F, buf, len);
33
33
  }
34
34
 
35
- int64_t osdp_millis_now(void)
35
+ __weak int64_t osdp_millis_now(void)
36
36
  {
37
37
  return millis_now();
38
38
  }
@@ -100,7 +100,7 @@ const char *osdp_reply_name(int reply_id)
100
100
  [REPLY_RSTATR - REPLY_ACK] = "RSTATR",
101
101
  [REPLY_RAW - REPLY_ACK] = "RAW",
102
102
  [REPLY_FMT - REPLY_ACK] = "FMT",
103
- [REPLY_KEYPPAD - REPLY_ACK] = "KEYPPAD",
103
+ [REPLY_KEYPAD - REPLY_ACK] = "KEYPAD",
104
104
  [REPLY_COM - REPLY_ACK] = "COM",
105
105
  [REPLY_BIOREADR - REPLY_ACK] = "BIOREADR",
106
106
  [REPLY_BIOMATCHR - REPLY_ACK] = "BIOMATCHR",