libosdp 2.4.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.
- libosdp-2.4.0/PKG-INFO +131 -0
- libosdp-2.4.0/README.md +118 -0
- libosdp-2.4.0/libosdp.egg-info/PKG-INFO +131 -0
- libosdp-2.4.0/libosdp.egg-info/SOURCES.txt +43 -0
- libosdp-2.4.0/libosdp.egg-info/dependency_links.txt +1 -0
- libosdp-2.4.0/libosdp.egg-info/top_level.txt +2 -0
- libosdp-2.4.0/osdp/__init__.py +18 -0
- libosdp-2.4.0/osdp/constants.py +71 -0
- libosdp-2.4.0/osdp/control_panel.py +193 -0
- libosdp-2.4.0/osdp/helpers.py +78 -0
- libosdp-2.4.0/osdp/key_store.py +66 -0
- libosdp-2.4.0/osdp/peripheral_device.py +85 -0
- libosdp-2.4.0/pyproject.toml +3 -0
- libosdp-2.4.0/setup.cfg +4 -0
- libosdp-2.4.0/setup.py +203 -0
libosdp-2.4.0/PKG-INFO
ADDED
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
Metadata-Version: 2.1
|
|
2
|
+
Name: libosdp
|
|
3
|
+
Version: 2.4.0
|
|
4
|
+
Summary: Library implementation of IEC 60839-11-5 OSDP (Open Supervised Device Protocol)
|
|
5
|
+
Home-page: https://github.com/goToMain/libosdp
|
|
6
|
+
Author: Siddharth Chandrasekaran
|
|
7
|
+
Author-email: sidcha.dev@gmail.com
|
|
8
|
+
Classifier: Programming Language :: Python :: 3
|
|
9
|
+
Classifier: License :: OSI Approved :: Apache Software License
|
|
10
|
+
Classifier: Operating System :: OS Independent
|
|
11
|
+
Requires-Python: >=3.8
|
|
12
|
+
Description-Content-Type: text/markdown
|
|
13
|
+
|
|
14
|
+
# Python3 Bindings for LibOSDP
|
|
15
|
+
|
|
16
|
+
This is an initial effort at enabling python3 support for LibOSDP. This document
|
|
17
|
+
assumes that you are already familiar with [LibOSDP API][1] and device life
|
|
18
|
+
cycle management.
|
|
19
|
+
|
|
20
|
+
## Build/Install
|
|
21
|
+
|
|
22
|
+
A python module `osdp` and classes `ControlPanel` and `PeripheralDevice` are
|
|
23
|
+
made available when the sources of this directory is built and installed.
|
|
24
|
+
|
|
25
|
+
After cloning this repo (with `--recurse-submodules`), you can do the following
|
|
26
|
+
(from the repo root) to build the python module.
|
|
27
|
+
|
|
28
|
+
```bash
|
|
29
|
+
mkdir build && cd build
|
|
30
|
+
cmake ..
|
|
31
|
+
make python
|
|
32
|
+
make python_install
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
If you want to undo this install, you can run `make python_uninstall`.
|
|
36
|
+
|
|
37
|
+
## How to use this module?
|
|
38
|
+
|
|
39
|
+
### Control Panel Mode
|
|
40
|
+
|
|
41
|
+
```python
|
|
42
|
+
import osdp
|
|
43
|
+
|
|
44
|
+
## Master key for secure channel
|
|
45
|
+
key = '01020304050607080910111213141516'
|
|
46
|
+
|
|
47
|
+
## populate osdp_pd_info_t from python
|
|
48
|
+
pd_info = [
|
|
49
|
+
{
|
|
50
|
+
"address": 101,
|
|
51
|
+
"channel_type": "uart",
|
|
52
|
+
"channel_speed": 115200,
|
|
53
|
+
"channel_device": '/dev/ttyUSB0',
|
|
54
|
+
},
|
|
55
|
+
{
|
|
56
|
+
"address": 102,
|
|
57
|
+
"channel_type": "uart",
|
|
58
|
+
"channel_speed": 115200,
|
|
59
|
+
"channel_device": '/dev/ttyUSB1',
|
|
60
|
+
}
|
|
61
|
+
]
|
|
62
|
+
|
|
63
|
+
## Setup OSDP device in Control Panel mode
|
|
64
|
+
cp = osdp.ControlPanel(pd_info, master_key=key)
|
|
65
|
+
|
|
66
|
+
## call this refresh method once every 50ms
|
|
67
|
+
cp.refresh()
|
|
68
|
+
|
|
69
|
+
## create and output command
|
|
70
|
+
output_cmd = {
|
|
71
|
+
"command": osdp.CMD_OUTPUT,
|
|
72
|
+
"output_no": 0,
|
|
73
|
+
"control_code": 1,
|
|
74
|
+
"timer_count": 10
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
## send a output command to PD-1
|
|
78
|
+
cp.send_command(1, output_cmd)
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
see [samples/cp_app.py][2] for more details.
|
|
82
|
+
|
|
83
|
+
### Peripheral Device mode:
|
|
84
|
+
|
|
85
|
+
```python
|
|
86
|
+
## Describe the PD
|
|
87
|
+
pd_info = {
|
|
88
|
+
"address": 101,
|
|
89
|
+
"channel_type": "uart",
|
|
90
|
+
"channel_speed": 115200,
|
|
91
|
+
"channel_device": '/dev/ttyUSB0',
|
|
92
|
+
|
|
93
|
+
"version": 1,
|
|
94
|
+
"model": 1,
|
|
95
|
+
"vendor_code": 0xCAFEBABE,
|
|
96
|
+
"serial_number": 0xDEADBEAF,
|
|
97
|
+
"firmware_version": 0x0000F00D
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
## Indicate the PD's capabilities to LibOSDP.
|
|
101
|
+
pd_cap = [
|
|
102
|
+
{
|
|
103
|
+
# PD is capable of handling output commands
|
|
104
|
+
"function_code": osdp.CAP_OUTPUT_CONTROL,
|
|
105
|
+
"compliance_level": 1,
|
|
106
|
+
"num_items": 1
|
|
107
|
+
},
|
|
108
|
+
]
|
|
109
|
+
|
|
110
|
+
## Setup OSDP device in Peripheral Device mode
|
|
111
|
+
pd = osdp.PeripheralDevice(pd_info, capabilities=pd_cap)
|
|
112
|
+
|
|
113
|
+
## call this refresh method periodically (at lease once every 50ms)
|
|
114
|
+
pd.refresh()
|
|
115
|
+
|
|
116
|
+
## Define a callback handler. Must return 0 on success, -ve on failures.
|
|
117
|
+
def handle_command(address, command):
|
|
118
|
+
if address != pd_info['address']:
|
|
119
|
+
return { "return_code": -1 }
|
|
120
|
+
print("PD received command: ", command)
|
|
121
|
+
return { "return_code": 0 }
|
|
122
|
+
|
|
123
|
+
## Set a handler for incoming commands from CP
|
|
124
|
+
pd.set_command_callback(handle_command)
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
see [samples/pd_app.py][3] for more details.
|
|
128
|
+
|
|
129
|
+
[1]: https://libosdp.sidcha.dev/api/
|
|
130
|
+
[2]: https://github.com/goToMain/libosdp/blob/master/samples/python/cp_app.py
|
|
131
|
+
[3]: https://github.com/goToMain/libosdp/blob/master/samples/python/pd_app.py
|
libosdp-2.4.0/README.md
ADDED
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
# Python3 Bindings for LibOSDP
|
|
2
|
+
|
|
3
|
+
This is an initial effort at enabling python3 support for LibOSDP. This document
|
|
4
|
+
assumes that you are already familiar with [LibOSDP API][1] and device life
|
|
5
|
+
cycle management.
|
|
6
|
+
|
|
7
|
+
## Build/Install
|
|
8
|
+
|
|
9
|
+
A python module `osdp` and classes `ControlPanel` and `PeripheralDevice` are
|
|
10
|
+
made available when the sources of this directory is built and installed.
|
|
11
|
+
|
|
12
|
+
After cloning this repo (with `--recurse-submodules`), you can do the following
|
|
13
|
+
(from the repo root) to build the python module.
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
mkdir build && cd build
|
|
17
|
+
cmake ..
|
|
18
|
+
make python
|
|
19
|
+
make python_install
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
If you want to undo this install, you can run `make python_uninstall`.
|
|
23
|
+
|
|
24
|
+
## How to use this module?
|
|
25
|
+
|
|
26
|
+
### Control Panel Mode
|
|
27
|
+
|
|
28
|
+
```python
|
|
29
|
+
import osdp
|
|
30
|
+
|
|
31
|
+
## Master key for secure channel
|
|
32
|
+
key = '01020304050607080910111213141516'
|
|
33
|
+
|
|
34
|
+
## populate osdp_pd_info_t from python
|
|
35
|
+
pd_info = [
|
|
36
|
+
{
|
|
37
|
+
"address": 101,
|
|
38
|
+
"channel_type": "uart",
|
|
39
|
+
"channel_speed": 115200,
|
|
40
|
+
"channel_device": '/dev/ttyUSB0',
|
|
41
|
+
},
|
|
42
|
+
{
|
|
43
|
+
"address": 102,
|
|
44
|
+
"channel_type": "uart",
|
|
45
|
+
"channel_speed": 115200,
|
|
46
|
+
"channel_device": '/dev/ttyUSB1',
|
|
47
|
+
}
|
|
48
|
+
]
|
|
49
|
+
|
|
50
|
+
## Setup OSDP device in Control Panel mode
|
|
51
|
+
cp = osdp.ControlPanel(pd_info, master_key=key)
|
|
52
|
+
|
|
53
|
+
## call this refresh method once every 50ms
|
|
54
|
+
cp.refresh()
|
|
55
|
+
|
|
56
|
+
## create and output command
|
|
57
|
+
output_cmd = {
|
|
58
|
+
"command": osdp.CMD_OUTPUT,
|
|
59
|
+
"output_no": 0,
|
|
60
|
+
"control_code": 1,
|
|
61
|
+
"timer_count": 10
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
## send a output command to PD-1
|
|
65
|
+
cp.send_command(1, output_cmd)
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
see [samples/cp_app.py][2] for more details.
|
|
69
|
+
|
|
70
|
+
### Peripheral Device mode:
|
|
71
|
+
|
|
72
|
+
```python
|
|
73
|
+
## Describe the PD
|
|
74
|
+
pd_info = {
|
|
75
|
+
"address": 101,
|
|
76
|
+
"channel_type": "uart",
|
|
77
|
+
"channel_speed": 115200,
|
|
78
|
+
"channel_device": '/dev/ttyUSB0',
|
|
79
|
+
|
|
80
|
+
"version": 1,
|
|
81
|
+
"model": 1,
|
|
82
|
+
"vendor_code": 0xCAFEBABE,
|
|
83
|
+
"serial_number": 0xDEADBEAF,
|
|
84
|
+
"firmware_version": 0x0000F00D
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
## Indicate the PD's capabilities to LibOSDP.
|
|
88
|
+
pd_cap = [
|
|
89
|
+
{
|
|
90
|
+
# PD is capable of handling output commands
|
|
91
|
+
"function_code": osdp.CAP_OUTPUT_CONTROL,
|
|
92
|
+
"compliance_level": 1,
|
|
93
|
+
"num_items": 1
|
|
94
|
+
},
|
|
95
|
+
]
|
|
96
|
+
|
|
97
|
+
## Setup OSDP device in Peripheral Device mode
|
|
98
|
+
pd = osdp.PeripheralDevice(pd_info, capabilities=pd_cap)
|
|
99
|
+
|
|
100
|
+
## call this refresh method periodically (at lease once every 50ms)
|
|
101
|
+
pd.refresh()
|
|
102
|
+
|
|
103
|
+
## Define a callback handler. Must return 0 on success, -ve on failures.
|
|
104
|
+
def handle_command(address, command):
|
|
105
|
+
if address != pd_info['address']:
|
|
106
|
+
return { "return_code": -1 }
|
|
107
|
+
print("PD received command: ", command)
|
|
108
|
+
return { "return_code": 0 }
|
|
109
|
+
|
|
110
|
+
## Set a handler for incoming commands from CP
|
|
111
|
+
pd.set_command_callback(handle_command)
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
see [samples/pd_app.py][3] for more details.
|
|
115
|
+
|
|
116
|
+
[1]: https://libosdp.sidcha.dev/api/
|
|
117
|
+
[2]: https://github.com/goToMain/libosdp/blob/master/samples/python/cp_app.py
|
|
118
|
+
[3]: https://github.com/goToMain/libosdp/blob/master/samples/python/pd_app.py
|
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
Metadata-Version: 2.1
|
|
2
|
+
Name: libosdp
|
|
3
|
+
Version: 2.4.0
|
|
4
|
+
Summary: Library implementation of IEC 60839-11-5 OSDP (Open Supervised Device Protocol)
|
|
5
|
+
Home-page: https://github.com/goToMain/libosdp
|
|
6
|
+
Author: Siddharth Chandrasekaran
|
|
7
|
+
Author-email: sidcha.dev@gmail.com
|
|
8
|
+
Classifier: Programming Language :: Python :: 3
|
|
9
|
+
Classifier: License :: OSI Approved :: Apache Software License
|
|
10
|
+
Classifier: Operating System :: OS Independent
|
|
11
|
+
Requires-Python: >=3.8
|
|
12
|
+
Description-Content-Type: text/markdown
|
|
13
|
+
|
|
14
|
+
# Python3 Bindings for LibOSDP
|
|
15
|
+
|
|
16
|
+
This is an initial effort at enabling python3 support for LibOSDP. This document
|
|
17
|
+
assumes that you are already familiar with [LibOSDP API][1] and device life
|
|
18
|
+
cycle management.
|
|
19
|
+
|
|
20
|
+
## Build/Install
|
|
21
|
+
|
|
22
|
+
A python module `osdp` and classes `ControlPanel` and `PeripheralDevice` are
|
|
23
|
+
made available when the sources of this directory is built and installed.
|
|
24
|
+
|
|
25
|
+
After cloning this repo (with `--recurse-submodules`), you can do the following
|
|
26
|
+
(from the repo root) to build the python module.
|
|
27
|
+
|
|
28
|
+
```bash
|
|
29
|
+
mkdir build && cd build
|
|
30
|
+
cmake ..
|
|
31
|
+
make python
|
|
32
|
+
make python_install
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
If you want to undo this install, you can run `make python_uninstall`.
|
|
36
|
+
|
|
37
|
+
## How to use this module?
|
|
38
|
+
|
|
39
|
+
### Control Panel Mode
|
|
40
|
+
|
|
41
|
+
```python
|
|
42
|
+
import osdp
|
|
43
|
+
|
|
44
|
+
## Master key for secure channel
|
|
45
|
+
key = '01020304050607080910111213141516'
|
|
46
|
+
|
|
47
|
+
## populate osdp_pd_info_t from python
|
|
48
|
+
pd_info = [
|
|
49
|
+
{
|
|
50
|
+
"address": 101,
|
|
51
|
+
"channel_type": "uart",
|
|
52
|
+
"channel_speed": 115200,
|
|
53
|
+
"channel_device": '/dev/ttyUSB0',
|
|
54
|
+
},
|
|
55
|
+
{
|
|
56
|
+
"address": 102,
|
|
57
|
+
"channel_type": "uart",
|
|
58
|
+
"channel_speed": 115200,
|
|
59
|
+
"channel_device": '/dev/ttyUSB1',
|
|
60
|
+
}
|
|
61
|
+
]
|
|
62
|
+
|
|
63
|
+
## Setup OSDP device in Control Panel mode
|
|
64
|
+
cp = osdp.ControlPanel(pd_info, master_key=key)
|
|
65
|
+
|
|
66
|
+
## call this refresh method once every 50ms
|
|
67
|
+
cp.refresh()
|
|
68
|
+
|
|
69
|
+
## create and output command
|
|
70
|
+
output_cmd = {
|
|
71
|
+
"command": osdp.CMD_OUTPUT,
|
|
72
|
+
"output_no": 0,
|
|
73
|
+
"control_code": 1,
|
|
74
|
+
"timer_count": 10
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
## send a output command to PD-1
|
|
78
|
+
cp.send_command(1, output_cmd)
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
see [samples/cp_app.py][2] for more details.
|
|
82
|
+
|
|
83
|
+
### Peripheral Device mode:
|
|
84
|
+
|
|
85
|
+
```python
|
|
86
|
+
## Describe the PD
|
|
87
|
+
pd_info = {
|
|
88
|
+
"address": 101,
|
|
89
|
+
"channel_type": "uart",
|
|
90
|
+
"channel_speed": 115200,
|
|
91
|
+
"channel_device": '/dev/ttyUSB0',
|
|
92
|
+
|
|
93
|
+
"version": 1,
|
|
94
|
+
"model": 1,
|
|
95
|
+
"vendor_code": 0xCAFEBABE,
|
|
96
|
+
"serial_number": 0xDEADBEAF,
|
|
97
|
+
"firmware_version": 0x0000F00D
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
## Indicate the PD's capabilities to LibOSDP.
|
|
101
|
+
pd_cap = [
|
|
102
|
+
{
|
|
103
|
+
# PD is capable of handling output commands
|
|
104
|
+
"function_code": osdp.CAP_OUTPUT_CONTROL,
|
|
105
|
+
"compliance_level": 1,
|
|
106
|
+
"num_items": 1
|
|
107
|
+
},
|
|
108
|
+
]
|
|
109
|
+
|
|
110
|
+
## Setup OSDP device in Peripheral Device mode
|
|
111
|
+
pd = osdp.PeripheralDevice(pd_info, capabilities=pd_cap)
|
|
112
|
+
|
|
113
|
+
## call this refresh method periodically (at lease once every 50ms)
|
|
114
|
+
pd.refresh()
|
|
115
|
+
|
|
116
|
+
## Define a callback handler. Must return 0 on success, -ve on failures.
|
|
117
|
+
def handle_command(address, command):
|
|
118
|
+
if address != pd_info['address']:
|
|
119
|
+
return { "return_code": -1 }
|
|
120
|
+
print("PD received command: ", command)
|
|
121
|
+
return { "return_code": 0 }
|
|
122
|
+
|
|
123
|
+
## Set a handler for incoming commands from CP
|
|
124
|
+
pd.set_command_callback(handle_command)
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
see [samples/pd_app.py][3] for more details.
|
|
128
|
+
|
|
129
|
+
[1]: https://libosdp.sidcha.dev/api/
|
|
130
|
+
[2]: https://github.com/goToMain/libosdp/blob/master/samples/python/cp_app.py
|
|
131
|
+
[3]: https://github.com/goToMain/libosdp/blob/master/samples/python/pd_app.py
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
README.md
|
|
2
|
+
pyproject.toml
|
|
3
|
+
setup.py
|
|
4
|
+
/Users/sidcha/work/osdp/libosdp/python/osdp_sys/base.c
|
|
5
|
+
/Users/sidcha/work/osdp/libosdp/python/osdp_sys/cp.c
|
|
6
|
+
/Users/sidcha/work/osdp/libosdp/python/osdp_sys/data.c
|
|
7
|
+
/Users/sidcha/work/osdp/libosdp/python/osdp_sys/module.c
|
|
8
|
+
/Users/sidcha/work/osdp/libosdp/python/osdp_sys/pd.c
|
|
9
|
+
/Users/sidcha/work/osdp/libosdp/python/osdp_sys/utils.c
|
|
10
|
+
/Users/sidcha/work/osdp/libosdp/src/osdp_common.c
|
|
11
|
+
/Users/sidcha/work/osdp/libosdp/src/osdp_cp.c
|
|
12
|
+
/Users/sidcha/work/osdp/libosdp/src/osdp_file.c
|
|
13
|
+
/Users/sidcha/work/osdp/libosdp/src/osdp_pd.c
|
|
14
|
+
/Users/sidcha/work/osdp/libosdp/src/osdp_phy.c
|
|
15
|
+
/Users/sidcha/work/osdp/libosdp/src/osdp_sc.c
|
|
16
|
+
/Users/sidcha/work/osdp/libosdp/src/crypto/tinyaes.c
|
|
17
|
+
/Users/sidcha/work/osdp/libosdp/src/crypto/tinyaes_src.c
|
|
18
|
+
/Users/sidcha/work/osdp/libosdp/utils/src/bus_server.c
|
|
19
|
+
/Users/sidcha/work/osdp/libosdp/utils/src/channel.c
|
|
20
|
+
/Users/sidcha/work/osdp/libosdp/utils/src/disjoint_set.c
|
|
21
|
+
/Users/sidcha/work/osdp/libosdp/utils/src/event.c
|
|
22
|
+
/Users/sidcha/work/osdp/libosdp/utils/src/fdutils.c
|
|
23
|
+
/Users/sidcha/work/osdp/libosdp/utils/src/hashmap.c
|
|
24
|
+
/Users/sidcha/work/osdp/libosdp/utils/src/list.c
|
|
25
|
+
/Users/sidcha/work/osdp/libosdp/utils/src/logger.c
|
|
26
|
+
/Users/sidcha/work/osdp/libosdp/utils/src/memory.c
|
|
27
|
+
/Users/sidcha/work/osdp/libosdp/utils/src/queue.c
|
|
28
|
+
/Users/sidcha/work/osdp/libosdp/utils/src/serial.c
|
|
29
|
+
/Users/sidcha/work/osdp/libosdp/utils/src/slab.c
|
|
30
|
+
/Users/sidcha/work/osdp/libosdp/utils/src/sockutils.c
|
|
31
|
+
/Users/sidcha/work/osdp/libosdp/utils/src/strutils.c
|
|
32
|
+
/Users/sidcha/work/osdp/libosdp/utils/src/utils.c
|
|
33
|
+
/Users/sidcha/work/osdp/libosdp/utils/src/workqueue.c
|
|
34
|
+
libosdp.egg-info/PKG-INFO
|
|
35
|
+
libosdp.egg-info/SOURCES.txt
|
|
36
|
+
libosdp.egg-info/dependency_links.txt
|
|
37
|
+
libosdp.egg-info/top_level.txt
|
|
38
|
+
osdp/__init__.py
|
|
39
|
+
osdp/constants.py
|
|
40
|
+
osdp/control_panel.py
|
|
41
|
+
osdp/helpers.py
|
|
42
|
+
osdp/key_store.py
|
|
43
|
+
osdp/peripheral_device.py
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
#
|
|
2
|
+
# Copyright (c) 2021-2023 Siddharth Chandrasekaran <sidcha.dev@gmail.com>
|
|
3
|
+
#
|
|
4
|
+
# SPDX-License-Identifier: Apache-2.0
|
|
5
|
+
#
|
|
6
|
+
|
|
7
|
+
from .control_panel import ControlPanel
|
|
8
|
+
from .peripheral_device import PeripheralDevice
|
|
9
|
+
from .key_store import KeyStore
|
|
10
|
+
from .constants import (
|
|
11
|
+
LibFlag, Command, CommandLEDColor, CommandFileTxFlags,
|
|
12
|
+
Event, CardFormat, Capability, LogLevel
|
|
13
|
+
)
|
|
14
|
+
from .helpers import PDInfo, PDCapabilities
|
|
15
|
+
|
|
16
|
+
__author__ = 'Siddharth Chandrasekaran <sidcha.dev@gmail.com>'
|
|
17
|
+
__copyright__ = 'Copyright 2021-2023 Siddharth Chandrasekaran'
|
|
18
|
+
__license__ = 'Apache License, Version 2.0 (Apache-2.0)'
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
#
|
|
2
|
+
# Copyright (c) 2021-2023 Siddharth Chandrasekaran <sidcha.dev@gmail.com>
|
|
3
|
+
#
|
|
4
|
+
# SPDX-License-Identifier: Apache-2.0
|
|
5
|
+
#
|
|
6
|
+
|
|
7
|
+
import osdp_sys
|
|
8
|
+
|
|
9
|
+
class LibFlag:
|
|
10
|
+
EnforceSecure = osdp_sys.FLAG_ENFORCE_SECURE
|
|
11
|
+
InstallMode = osdp_sys.FLAG_INSTALL_MODE
|
|
12
|
+
IgnoreUnsolicited = osdp_sys.FLAG_IGN_UNSOLICITED
|
|
13
|
+
|
|
14
|
+
class LogLevel:
|
|
15
|
+
Emergency = osdp_sys.LOG_EMERG
|
|
16
|
+
Alert = osdp_sys.LOG_ALERT
|
|
17
|
+
Critical = osdp_sys.LOG_CRIT
|
|
18
|
+
Error = osdp_sys.LOG_ERROR
|
|
19
|
+
Warning = osdp_sys.LOG_WARNING
|
|
20
|
+
Notice = osdp_sys.LOG_NOTICE
|
|
21
|
+
Info = osdp_sys.LOG_INFO
|
|
22
|
+
Debug = osdp_sys.LOG_DEBUG
|
|
23
|
+
|
|
24
|
+
class Command:
|
|
25
|
+
Output = osdp_sys.CMD_OUTPUT
|
|
26
|
+
Buzzer = osdp_sys.CMD_BUZZER
|
|
27
|
+
LED = osdp_sys.CMD_LED
|
|
28
|
+
Comset = osdp_sys.CMD_COMSET
|
|
29
|
+
Text = osdp_sys.CMD_TEXT
|
|
30
|
+
Manufacturer = osdp_sys.CMD_MFG
|
|
31
|
+
Keyset = osdp_sys.CMD_KEYSET
|
|
32
|
+
FileTransfer = osdp_sys.CMD_FILE_TX
|
|
33
|
+
|
|
34
|
+
class CommandLEDColor:
|
|
35
|
+
Black = osdp_sys.LED_COLOR_NONE
|
|
36
|
+
Red = osdp_sys.LED_COLOR_RED
|
|
37
|
+
Green = osdp_sys.LED_COLOR_GREEN
|
|
38
|
+
Amber = osdp_sys.LED_COLOR_AMBER
|
|
39
|
+
Blue = osdp_sys.LED_COLOR_BLUE
|
|
40
|
+
|
|
41
|
+
class CommandFileTxFlags:
|
|
42
|
+
Cancel = osdp_sys.CMD_FILE_TX_FLAG_CANCEL
|
|
43
|
+
|
|
44
|
+
class Event:
|
|
45
|
+
CardRead = osdp_sys.EVENT_CARDREAD
|
|
46
|
+
KeyPress = osdp_sys.EVENT_KEYPRESS
|
|
47
|
+
ManufacturerReply = osdp_sys.EVENT_MFGREP
|
|
48
|
+
InputOutput = osdp_sys.EVENT_IO
|
|
49
|
+
Status = osdp_sys.EVENT_STATUS
|
|
50
|
+
|
|
51
|
+
class CardFormat:
|
|
52
|
+
Unspecified = osdp_sys.CARD_FMT_RAW_UNSPECIFIED
|
|
53
|
+
Wiegand = osdp_sys.CARD_FMT_RAW_WIEGAND
|
|
54
|
+
ASCII = osdp_sys.CARD_FMT_ASCII
|
|
55
|
+
|
|
56
|
+
class Capability:
|
|
57
|
+
Unused = osdp_sys.CAP_UNUSED
|
|
58
|
+
ContactStatusMonitoring = osdp_sys.CAP_CONTACT_STATUS_MONITORING
|
|
59
|
+
OutputControl = osdp_sys.CAP_OUTPUT_CONTROL
|
|
60
|
+
CardDataFormat = osdp_sys.CAP_CARD_DATA_FORMAT
|
|
61
|
+
LEDControl = osdp_sys.CAP_READER_LED_CONTROL
|
|
62
|
+
AudibleControl = osdp_sys.CAP_READER_AUDIBLE_OUTPUT
|
|
63
|
+
TextOutput = osdp_sys.CAP_READER_TEXT_OUTPUT
|
|
64
|
+
TimeKeeping = osdp_sys.CAP_TIME_KEEPING
|
|
65
|
+
CheckCharacter = osdp_sys.CAP_CHECK_CHARACTER_SUPPORT
|
|
66
|
+
CommunicationSecurity = osdp_sys.CAP_COMMUNICATION_SECURITY
|
|
67
|
+
ReceiveBufferSize = osdp_sys.CAP_RECEIVE_BUFFERSIZE
|
|
68
|
+
CombinedMessageSize = osdp_sys.CAP_LARGEST_COMBINED_MESSAGE_SIZE
|
|
69
|
+
SmartCard = osdp_sys.CAP_SMART_CARD_SUPPORT
|
|
70
|
+
Readers = osdp_sys.CAP_READERS
|
|
71
|
+
Biometrics = osdp_sys.CAP_BIOMETRICS
|
|
@@ -0,0 +1,193 @@
|
|
|
1
|
+
#
|
|
2
|
+
# Copyright (c) 2021-2023 Siddharth Chandrasekaran <sidcha.dev@gmail.com>
|
|
3
|
+
#
|
|
4
|
+
# SPDX-License-Identifier: Apache-2.0
|
|
5
|
+
#
|
|
6
|
+
import sys
|
|
7
|
+
import os
|
|
8
|
+
import tempfile
|
|
9
|
+
import osdp_sys
|
|
10
|
+
import time
|
|
11
|
+
import queue
|
|
12
|
+
import threading
|
|
13
|
+
|
|
14
|
+
from .helpers import PDInfo
|
|
15
|
+
from .constants import LibFlag, LogLevel
|
|
16
|
+
|
|
17
|
+
class ControlPanel():
|
|
18
|
+
def __init__(self, pd_info_list, log_level: LogLevel=LogLevel.Info,
|
|
19
|
+
master_key: bytes=None):
|
|
20
|
+
self.pd_addr = []
|
|
21
|
+
info_list = []
|
|
22
|
+
self.num_pds = len(pd_info_list)
|
|
23
|
+
for pd_info in pd_info_list:
|
|
24
|
+
self.pd_addr.append(pd_info.address)
|
|
25
|
+
info_list.append(pd_info.get())
|
|
26
|
+
self.event_queue = [ queue.Queue() for i in self.pd_addr ]
|
|
27
|
+
if master_key:
|
|
28
|
+
self.ctx = osdp_sys.ControlPanel(info_list, master_key=master_key)
|
|
29
|
+
else:
|
|
30
|
+
self.ctx = osdp_sys.ControlPanel(info_list)
|
|
31
|
+
self.ctx.set_event_callback(self.event_handler)
|
|
32
|
+
self.ctx.set_loglevel(log_level)
|
|
33
|
+
self.event = None
|
|
34
|
+
self.lock = None
|
|
35
|
+
self.thread = None
|
|
36
|
+
|
|
37
|
+
@staticmethod
|
|
38
|
+
def refresh(event, lock, ctx):
|
|
39
|
+
while not event.is_set():
|
|
40
|
+
lock.acquire()
|
|
41
|
+
ctx.refresh()
|
|
42
|
+
lock.release()
|
|
43
|
+
time.sleep(0.020) #sleep for 20ms
|
|
44
|
+
|
|
45
|
+
def event_handler(self, pd, event):
|
|
46
|
+
self.event_queue[pd].put(event)
|
|
47
|
+
|
|
48
|
+
def get_event(self, address, timeout: int=5):
|
|
49
|
+
pd = self.pd_addr.index(address)
|
|
50
|
+
try:
|
|
51
|
+
event = self.event_queue[pd].get(timeout=timeout)
|
|
52
|
+
except queue.Empty:
|
|
53
|
+
return None
|
|
54
|
+
return event
|
|
55
|
+
|
|
56
|
+
def status(self):
|
|
57
|
+
self.lock.acquire()
|
|
58
|
+
bitmask = self.ctx.status()
|
|
59
|
+
self.lock.release()
|
|
60
|
+
return bitmask
|
|
61
|
+
|
|
62
|
+
def is_online(self, address):
|
|
63
|
+
pd = self.pd_addr.index(address)
|
|
64
|
+
return bool(self.status() & (1 << pd))
|
|
65
|
+
|
|
66
|
+
def get_num_online(self):
|
|
67
|
+
online = 0
|
|
68
|
+
bitmask = self.status()
|
|
69
|
+
for i in range(len(self.pd_addr)):
|
|
70
|
+
if bitmask & (1 << i):
|
|
71
|
+
online += 1
|
|
72
|
+
return online
|
|
73
|
+
|
|
74
|
+
def sc_status(self):
|
|
75
|
+
self.lock.acquire()
|
|
76
|
+
bitmask = self.ctx.sc_status()
|
|
77
|
+
self.lock.release()
|
|
78
|
+
return bitmask
|
|
79
|
+
|
|
80
|
+
def is_sc_active(self, address):
|
|
81
|
+
pd = self.pd_addr.index(address)
|
|
82
|
+
return bool(self.sc_status() & (1 << pd))
|
|
83
|
+
|
|
84
|
+
def get_num_sc_active(self):
|
|
85
|
+
sc_active = 0
|
|
86
|
+
bitmask = self.sc_status()
|
|
87
|
+
for i in range(len(self.pd_addr)):
|
|
88
|
+
if bitmask & (1 << i):
|
|
89
|
+
sc_active += 1
|
|
90
|
+
return sc_active
|
|
91
|
+
|
|
92
|
+
def send_command(self, address, cmd):
|
|
93
|
+
pd = self.pd_addr.index(address)
|
|
94
|
+
self.lock.acquire()
|
|
95
|
+
ret = self.ctx.send_command(pd, cmd)
|
|
96
|
+
self.lock.release()
|
|
97
|
+
return ret
|
|
98
|
+
|
|
99
|
+
def set_flag(self, address, flag: LibFlag):
|
|
100
|
+
pd = self.pd_addr.index(address)
|
|
101
|
+
self.lock.acquire()
|
|
102
|
+
ret = self.ctx.set_flag(pd, flag)
|
|
103
|
+
self.lock.release()
|
|
104
|
+
return ret
|
|
105
|
+
|
|
106
|
+
def clear_flag(self, address, flag: LibFlag):
|
|
107
|
+
pd = self.pd_addr.index(address)
|
|
108
|
+
self.lock.acquire()
|
|
109
|
+
ret = self.ctx.clear_flag(pd, flag)
|
|
110
|
+
self.lock.release()
|
|
111
|
+
return ret
|
|
112
|
+
|
|
113
|
+
def register_file_ops(self, address, fops):
|
|
114
|
+
pd = self.pd_addr.index(address)
|
|
115
|
+
self.lock.acquire()
|
|
116
|
+
ret = self.ctx.register_file_ops(pd, fops)
|
|
117
|
+
self.lock.release()
|
|
118
|
+
return ret
|
|
119
|
+
|
|
120
|
+
def get_file_tx_status(self, address):
|
|
121
|
+
pd = self.pd_addr.index(address)
|
|
122
|
+
self.lock.acquire()
|
|
123
|
+
ret = self.ctx.get_file_tx_status(pd)
|
|
124
|
+
self.lock.release()
|
|
125
|
+
return ret
|
|
126
|
+
|
|
127
|
+
def start(self):
|
|
128
|
+
if self.thread:
|
|
129
|
+
raise RuntimeError("Thread already running!")
|
|
130
|
+
self.event = threading.Event()
|
|
131
|
+
self.lock = threading.Lock()
|
|
132
|
+
args=(self.event, self.lock, self.ctx)
|
|
133
|
+
self.thread = threading.Thread(name='cp', target=self.refresh, args=args)
|
|
134
|
+
self.thread.start()
|
|
135
|
+
|
|
136
|
+
def stop(self):
|
|
137
|
+
if not self.thread:
|
|
138
|
+
raise RuntimeError("Thread not running!")
|
|
139
|
+
while self.thread.is_alive():
|
|
140
|
+
self.event.set()
|
|
141
|
+
self.thread.join(2)
|
|
142
|
+
if not self.thread.is_alive():
|
|
143
|
+
self.thread = None
|
|
144
|
+
break
|
|
145
|
+
|
|
146
|
+
def online_wait_all(self, timeout=10):
|
|
147
|
+
count = 0
|
|
148
|
+
res = False
|
|
149
|
+
while count < timeout * 2:
|
|
150
|
+
time.sleep(0.5)
|
|
151
|
+
if self.get_num_online() == len(self.pd_addr):
|
|
152
|
+
res = True
|
|
153
|
+
break
|
|
154
|
+
count += 1
|
|
155
|
+
return res
|
|
156
|
+
|
|
157
|
+
def online_wait(self, address, timeout=5):
|
|
158
|
+
count = 0
|
|
159
|
+
res = False
|
|
160
|
+
while count < timeout * 2:
|
|
161
|
+
time.sleep(0.5)
|
|
162
|
+
if self.is_online(address):
|
|
163
|
+
res = True
|
|
164
|
+
break
|
|
165
|
+
count += 1
|
|
166
|
+
return res
|
|
167
|
+
|
|
168
|
+
def sc_wait(self, address, timeout=5):
|
|
169
|
+
count = 0
|
|
170
|
+
res = False
|
|
171
|
+
while count < timeout * 2:
|
|
172
|
+
time.sleep(0.5)
|
|
173
|
+
if self.is_sc_active(address):
|
|
174
|
+
res = True
|
|
175
|
+
break
|
|
176
|
+
count += 1
|
|
177
|
+
return res
|
|
178
|
+
|
|
179
|
+
def sc_wait_all(self, timeout=5):
|
|
180
|
+
count = 0
|
|
181
|
+
res = False
|
|
182
|
+
all_pd_mask = (1 << self.num_pds) - 1
|
|
183
|
+
while count < timeout * 2:
|
|
184
|
+
time.sleep(0.5)
|
|
185
|
+
if self.sc_status() == all_pd_mask:
|
|
186
|
+
res = True
|
|
187
|
+
break
|
|
188
|
+
count += 1
|
|
189
|
+
return res
|
|
190
|
+
|
|
191
|
+
def teardown(self):
|
|
192
|
+
self.stop()
|
|
193
|
+
self.ctx = None
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
#
|
|
2
|
+
# Copyright (c) 2021-2023 Siddharth Chandrasekaran <sidcha.dev@gmail.com>
|
|
3
|
+
#
|
|
4
|
+
# SPDX-License-Identifier: Apache-2.0
|
|
5
|
+
#
|
|
6
|
+
|
|
7
|
+
import os
|
|
8
|
+
from .constants import Capability, LibFlag
|
|
9
|
+
|
|
10
|
+
class PDInfo:
|
|
11
|
+
def __init__(self, address: int, scbk: bytes=None, name: str='chn', flags=[],
|
|
12
|
+
channel_type: str='fifo'):
|
|
13
|
+
self.address = address
|
|
14
|
+
self.flags = flags
|
|
15
|
+
self.scbk = scbk
|
|
16
|
+
self.name = name
|
|
17
|
+
self.channel_device = '/tmp/pyosdp-' + name
|
|
18
|
+
self.channel_speed = 115200
|
|
19
|
+
self.channel_type = channel_type
|
|
20
|
+
self.version= 1
|
|
21
|
+
self.model= 1
|
|
22
|
+
self.vendor_code= 0xCAFEBABE
|
|
23
|
+
self.serial_number= 0xDEADBEAF
|
|
24
|
+
self.firmware_version= 0x0000F00D
|
|
25
|
+
|
|
26
|
+
if self.channel_type == 'unix_bus' and os.path.exists(self.channel_device):
|
|
27
|
+
os.remove(self.channel_device)
|
|
28
|
+
|
|
29
|
+
def get_flags(self) -> int:
|
|
30
|
+
ret = 0
|
|
31
|
+
for flag in self.flags:
|
|
32
|
+
ret |= flag
|
|
33
|
+
return ret
|
|
34
|
+
|
|
35
|
+
def get(self) -> dict:
|
|
36
|
+
return {
|
|
37
|
+
'name': self.name,
|
|
38
|
+
'address': self.address,
|
|
39
|
+
'flags': self.get_flags(),
|
|
40
|
+
'scbk': self.scbk,
|
|
41
|
+
'channel_type': self.channel_type,
|
|
42
|
+
'channel_speed': self.channel_speed,
|
|
43
|
+
'channel_device': self.channel_device,
|
|
44
|
+
|
|
45
|
+
# Following are needed only for PD. For CP these are don't cares
|
|
46
|
+
'version': self.version,
|
|
47
|
+
'model': self.model,
|
|
48
|
+
'vendor_code': self.vendor_code,
|
|
49
|
+
'serial_number': self.serial_number,
|
|
50
|
+
'firmware_version': self.firmware_version
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
class _PDCapEntity:
|
|
54
|
+
def __init__(self, function_code: Capability,
|
|
55
|
+
compliance_level: int=1, num_items: int=1):
|
|
56
|
+
self.function_code = function_code
|
|
57
|
+
self.compliance_level = compliance_level
|
|
58
|
+
self.num_items = num_items
|
|
59
|
+
|
|
60
|
+
def get(self) -> dict:
|
|
61
|
+
return {
|
|
62
|
+
'function_code': self.function_code,
|
|
63
|
+
'compliance_level': self.compliance_level,
|
|
64
|
+
'num_items': self.num_items
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
class PDCapabilities:
|
|
68
|
+
def __init__(self, cap_list=[]):
|
|
69
|
+
self.capabilities = {}
|
|
70
|
+
for cap in cap_list:
|
|
71
|
+
(fc, cl, ni) = cap
|
|
72
|
+
self.capabilities[fc] = _PDCapEntity(fc, cl, ni)
|
|
73
|
+
|
|
74
|
+
def get(self):
|
|
75
|
+
ret = []
|
|
76
|
+
for fc in self.capabilities.keys():
|
|
77
|
+
ret.append(self.capabilities[fc].get())
|
|
78
|
+
return ret
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
#
|
|
2
|
+
# Copyright (c) 2021-2023 Siddharth Chandrasekaran <sidcha.dev@gmail.com>
|
|
3
|
+
#
|
|
4
|
+
# SPDX-License-Identifier: Apache-2.0
|
|
5
|
+
#
|
|
6
|
+
|
|
7
|
+
import os
|
|
8
|
+
import tempfile
|
|
9
|
+
import random
|
|
10
|
+
|
|
11
|
+
class KeyStore():
|
|
12
|
+
def __init__(self, dir=None):
|
|
13
|
+
self.temp_dir = None
|
|
14
|
+
self.keys = {}
|
|
15
|
+
if not dir:
|
|
16
|
+
self.temp_dir = tempfile.TemporaryDirectory()
|
|
17
|
+
self.key_dir = self.temp_dir.name
|
|
18
|
+
else:
|
|
19
|
+
self.key_dir = dir
|
|
20
|
+
|
|
21
|
+
def key_file(self, name):
|
|
22
|
+
return os.path.join(self.key_dir, 'key_' + name + '.bin')
|
|
23
|
+
|
|
24
|
+
@staticmethod
|
|
25
|
+
def gen_key(key_len=16):
|
|
26
|
+
key = []
|
|
27
|
+
for i in range(key_len):
|
|
28
|
+
key.append(random.randint(0, 255))
|
|
29
|
+
return bytes(key)
|
|
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:
|
|
36
|
+
f.write(key.hex())
|
|
37
|
+
|
|
38
|
+
def get_key(self, name):
|
|
39
|
+
if name not in self.keys:
|
|
40
|
+
raise RuntimeError
|
|
41
|
+
return self.keys[name]
|
|
42
|
+
|
|
43
|
+
def new_key(self, name, key_len=16, force=True):
|
|
44
|
+
if not force and name in self.keys:
|
|
45
|
+
raise RuntimeError
|
|
46
|
+
self.keys[name] = self.gen_key(key_len)
|
|
47
|
+
return self.keys[name]
|
|
48
|
+
|
|
49
|
+
def update_key(self, name, key):
|
|
50
|
+
if name not in self.keys:
|
|
51
|
+
raise RuntimeError
|
|
52
|
+
self.keys[name] = key
|
|
53
|
+
|
|
54
|
+
def load_key(self, name, key_len=16):
|
|
55
|
+
if not os.path.exists(self.key_file(name)):
|
|
56
|
+
raise RuntimeError
|
|
57
|
+
with open(self.key_file(name), "r") as f:
|
|
58
|
+
key = bytes.fromhex(f.read())
|
|
59
|
+
if not key or not isinstance(key, bytes) or len(key) != key_len:
|
|
60
|
+
raise RuntimeError
|
|
61
|
+
self.keys[name] = key
|
|
62
|
+
return key
|
|
63
|
+
|
|
64
|
+
def __del__(self):
|
|
65
|
+
if self.temp_dir:
|
|
66
|
+
self.temp_dir.cleanup()
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
#
|
|
2
|
+
# Copyright (c) 2021-2023 Siddharth Chandrasekaran <sidcha.dev@gmail.com>
|
|
3
|
+
#
|
|
4
|
+
# SPDX-License-Identifier: Apache-2.0
|
|
5
|
+
#
|
|
6
|
+
|
|
7
|
+
import osdp_sys
|
|
8
|
+
import time
|
|
9
|
+
import queue
|
|
10
|
+
import threading
|
|
11
|
+
|
|
12
|
+
from .helpers import PDInfo, PDCapabilities
|
|
13
|
+
from .constants import LogLevel
|
|
14
|
+
|
|
15
|
+
class PeripheralDevice():
|
|
16
|
+
def __init__(self, pd_info: PDInfo, pd_cap: PDCapabilities,
|
|
17
|
+
log_level: LogLevel=LogLevel.Info):
|
|
18
|
+
self.command_queue = queue.Queue()
|
|
19
|
+
self.address = pd_info.address
|
|
20
|
+
self.ctx = osdp_sys.PeripheralDevice(pd_info.get(), capabilities=pd_cap.get())
|
|
21
|
+
self.ctx.set_loglevel(log_level)
|
|
22
|
+
self.ctx.set_command_callback(self.command_handler)
|
|
23
|
+
self.event = None
|
|
24
|
+
self.lock = None
|
|
25
|
+
self.thread = None
|
|
26
|
+
|
|
27
|
+
@staticmethod
|
|
28
|
+
def refresh(event, lock, ctx):
|
|
29
|
+
while not event.is_set():
|
|
30
|
+
lock.acquire()
|
|
31
|
+
ctx.refresh()
|
|
32
|
+
lock.release()
|
|
33
|
+
time.sleep(0.020) #sleep for 20ms
|
|
34
|
+
|
|
35
|
+
def command_handler(self, command):
|
|
36
|
+
self.command_queue.put(command)
|
|
37
|
+
return { "return_code": 0 }
|
|
38
|
+
|
|
39
|
+
def get_command(self, timeout: int=5):
|
|
40
|
+
try:
|
|
41
|
+
cmd = self.command_queue.get(timeout=timeout)
|
|
42
|
+
except queue.Empty:
|
|
43
|
+
return None
|
|
44
|
+
return cmd
|
|
45
|
+
|
|
46
|
+
def notify_event(self, event):
|
|
47
|
+
self.lock.acquire()
|
|
48
|
+
ret = self.ctx.notify_event(event)
|
|
49
|
+
self.lock.release()
|
|
50
|
+
return ret
|
|
51
|
+
|
|
52
|
+
def register_file_ops(self, fops):
|
|
53
|
+
self.lock.acquire()
|
|
54
|
+
ret = self.ctx.register_file_ops(0, fops)
|
|
55
|
+
self.lock.release()
|
|
56
|
+
return ret
|
|
57
|
+
|
|
58
|
+
def is_sc_active(self):
|
|
59
|
+
return self.ctx.is_sc_active()
|
|
60
|
+
|
|
61
|
+
def is_online(self):
|
|
62
|
+
return self.ctx.is_online()
|
|
63
|
+
|
|
64
|
+
def start(self):
|
|
65
|
+
if self.thread:
|
|
66
|
+
raise RuntimeError("Thread already running!")
|
|
67
|
+
self.event = threading.Event()
|
|
68
|
+
self.lock = threading.Lock()
|
|
69
|
+
args = (self.event, self.lock, self.ctx,)
|
|
70
|
+
self.thread = threading.Thread(name='pd', target=self.refresh, args=args)
|
|
71
|
+
self.thread.start()
|
|
72
|
+
|
|
73
|
+
def stop(self):
|
|
74
|
+
if not self.thread:
|
|
75
|
+
raise RuntimeError("Thread not running!")
|
|
76
|
+
while self.thread.is_alive():
|
|
77
|
+
self.event.set()
|
|
78
|
+
self.thread.join(2)
|
|
79
|
+
if not self.thread.is_alive():
|
|
80
|
+
self.thread = None
|
|
81
|
+
break
|
|
82
|
+
|
|
83
|
+
def teardown(self):
|
|
84
|
+
self.stop()
|
|
85
|
+
self.ctx = None
|
libosdp-2.4.0/setup.cfg
ADDED
libosdp-2.4.0/setup.py
ADDED
|
@@ -0,0 +1,203 @@
|
|
|
1
|
+
#
|
|
2
|
+
# Copyright (c) 2020-2023 Siddharth Chandrasekaran <sidcha.dev@gmail.com>
|
|
3
|
+
#
|
|
4
|
+
# SPDX-License-Identifier: Apache-2.0
|
|
5
|
+
#
|
|
6
|
+
|
|
7
|
+
import os
|
|
8
|
+
import re
|
|
9
|
+
from setuptools import setup, Extension
|
|
10
|
+
import shutil
|
|
11
|
+
import subprocess
|
|
12
|
+
|
|
13
|
+
current_dir = os.environ.get("PWD")
|
|
14
|
+
build_dir = os.path.abspath(os.path.join(current_dir, "build"))
|
|
15
|
+
root_dir = os.path.abspath(os.path.join(current_dir, ".."))
|
|
16
|
+
|
|
17
|
+
def read_version():
|
|
18
|
+
with open(os.path.join(root_dir, "CMakeLists.txt")) as f:
|
|
19
|
+
for line in f.readlines():
|
|
20
|
+
m = re.match(r"^project\((.+) VERSION (\d+\.\d+\.\d+)\)$", line)
|
|
21
|
+
if (m):
|
|
22
|
+
return m.groups()
|
|
23
|
+
raise RuntimeError("Failed to parse package name and version")
|
|
24
|
+
|
|
25
|
+
project_name, project_version = read_version()
|
|
26
|
+
|
|
27
|
+
def map_prefix(src_list, path, check_files=False):
|
|
28
|
+
paths = [ os.path.join(path, src) for src in src_list ]
|
|
29
|
+
for path in paths:
|
|
30
|
+
if check_files:
|
|
31
|
+
if not os.path.exists(path):
|
|
32
|
+
raise RuntimeError(f"Path '{path}' does not exist")
|
|
33
|
+
return paths
|
|
34
|
+
|
|
35
|
+
def exec_cmd(cmd):
|
|
36
|
+
r = subprocess.run(cmd, capture_output = True, text = True)
|
|
37
|
+
return r.stdout.strip()
|
|
38
|
+
|
|
39
|
+
def get_git_info():
|
|
40
|
+
d = {}
|
|
41
|
+
d["branch"] = exec_cmd(["git", "rev-parse", "--abbrev-ref", "HEAD"])
|
|
42
|
+
d["tag"] = exec_cmd([ "git", "describe", "--exact-match", "--tags" ])
|
|
43
|
+
d["diff"] = exec_cmd([ "git", "diff", "--quiet", "--exit-code" ])
|
|
44
|
+
d["rev"] = exec_cmd(["git", "log", "--pretty=format:%h", "-n", "1"])
|
|
45
|
+
d["root"] = exec_cmd(["git", "rev-parse", "--show-toplevel"])
|
|
46
|
+
return d
|
|
47
|
+
|
|
48
|
+
def configure_file(file, replacements):
|
|
49
|
+
with open(file) as f:
|
|
50
|
+
contents = f.read()
|
|
51
|
+
pat = re.compile(r"@(\w+)@")
|
|
52
|
+
for match in pat.findall(contents):
|
|
53
|
+
if match in replacements:
|
|
54
|
+
contents = contents.replace(f"@{match}@", replacements[match])
|
|
55
|
+
with open(file, 'w') as f:
|
|
56
|
+
f.write(contents)
|
|
57
|
+
|
|
58
|
+
def generate_osdp_build_headers():
|
|
59
|
+
os.makedirs(build_dir, exist_ok=True)
|
|
60
|
+
with open(os.path.join(build_dir, "osdp_export.h"), 'w') as f:
|
|
61
|
+
f.write("#define OSDP_EXPORT\n")
|
|
62
|
+
|
|
63
|
+
git = get_git_info()
|
|
64
|
+
dest = os.path.join(build_dir, "osdp_config.h")
|
|
65
|
+
shutil.copy(os.path.join(root_dir, "src/osdp_config.h.in"), dest)
|
|
66
|
+
configure_file(dest, {
|
|
67
|
+
"PROJECT_VERSION": project_version,
|
|
68
|
+
"PROJECT_NAME": project_name,
|
|
69
|
+
"GIT_BRANCH": git["branch"],
|
|
70
|
+
"GIT_REV": git["rev"],
|
|
71
|
+
"GIT_TAG": git["tag"],
|
|
72
|
+
"GIT_DIFF": git["diff"],
|
|
73
|
+
"REPO_ROOT": git["root"],
|
|
74
|
+
})
|
|
75
|
+
|
|
76
|
+
generate_osdp_build_headers()
|
|
77
|
+
|
|
78
|
+
utils_sources = map_prefix([
|
|
79
|
+
"utils/src/list.c",
|
|
80
|
+
"utils/src/queue.c",
|
|
81
|
+
"utils/src/slab.c",
|
|
82
|
+
"utils/src/utils.c",
|
|
83
|
+
"utils/src/logger.c",
|
|
84
|
+
"utils/src/disjoint_set.c",
|
|
85
|
+
"utils/src/serial.c",
|
|
86
|
+
"utils/src/channel.c",
|
|
87
|
+
"utils/src/hashmap.c",
|
|
88
|
+
"utils/src/strutils.c",
|
|
89
|
+
"utils/src/memory.c",
|
|
90
|
+
"utils/src/fdutils.c",
|
|
91
|
+
"utils/src/event.c",
|
|
92
|
+
"utils/src/workqueue.c",
|
|
93
|
+
"utils/src/sockutils.c",
|
|
94
|
+
"utils/src/bus_server.c",
|
|
95
|
+
], root_dir)
|
|
96
|
+
|
|
97
|
+
lib_sources = map_prefix([
|
|
98
|
+
"src/osdp_common.c",
|
|
99
|
+
"src/osdp_phy.c",
|
|
100
|
+
"src/osdp_sc.c",
|
|
101
|
+
"src/osdp_file.c",
|
|
102
|
+
"src/osdp_pd.c",
|
|
103
|
+
"src/osdp_cp.c",
|
|
104
|
+
"src/crypto/tinyaes_src.c",
|
|
105
|
+
"src/crypto/tinyaes.c",
|
|
106
|
+
], root_dir)
|
|
107
|
+
|
|
108
|
+
osdp_sys_sources = map_prefix([
|
|
109
|
+
"osdp_sys/module.c",
|
|
110
|
+
"osdp_sys/base.c",
|
|
111
|
+
"osdp_sys/cp.c",
|
|
112
|
+
"osdp_sys/pd.c",
|
|
113
|
+
"osdp_sys/data.c",
|
|
114
|
+
"osdp_sys/utils.c",
|
|
115
|
+
], current_dir)
|
|
116
|
+
|
|
117
|
+
source_files = utils_sources + lib_sources + osdp_sys_sources
|
|
118
|
+
|
|
119
|
+
include_dirs = map_prefix([
|
|
120
|
+
"utils/include",
|
|
121
|
+
"include",
|
|
122
|
+
"src",
|
|
123
|
+
"python/build",
|
|
124
|
+
], root_dir)
|
|
125
|
+
|
|
126
|
+
other_files = map_prefix([
|
|
127
|
+
"CMakeLists.txt",
|
|
128
|
+
"src/osdp_config.h.in"
|
|
129
|
+
], root_dir)
|
|
130
|
+
|
|
131
|
+
include_files = map_prefix([
|
|
132
|
+
"utils/include/utils/list.h",
|
|
133
|
+
"utils/include/utils/queue.h",
|
|
134
|
+
"utils/include/utils/slab.h",
|
|
135
|
+
"utils/include/utils/utils.h",
|
|
136
|
+
"utils/include/utils/logger.h",
|
|
137
|
+
"utils/include/utils/disjoint_set.h",
|
|
138
|
+
"utils/include/utils/serial.h",
|
|
139
|
+
"utils/include/utils/channel.h",
|
|
140
|
+
"utils/include/utils/hashmap.h",
|
|
141
|
+
"utils/include/utils/strutils.h",
|
|
142
|
+
"utils/include/utils/memory.h",
|
|
143
|
+
"utils/include/utils/fdutils.h",
|
|
144
|
+
"utils/include/utils/event.h",
|
|
145
|
+
"utils/include/utils/workqueue.h",
|
|
146
|
+
"utils/include/utils/sockutils.h",
|
|
147
|
+
"utils/include/utils/bus_server.h",
|
|
148
|
+
"include/osdp.h",
|
|
149
|
+
"src/osdp_common.h",
|
|
150
|
+
"src/osdp_file.h",
|
|
151
|
+
"python/build/osdp_config.h",
|
|
152
|
+
"python/build/osdp_export.h",
|
|
153
|
+
], root_dir, check_files=True)
|
|
154
|
+
|
|
155
|
+
libosdp_includes = [ "-I" + path for path in include_dirs ]
|
|
156
|
+
|
|
157
|
+
definitions = [
|
|
158
|
+
# "CONFIG_OSDP_PACKET_TRACE",
|
|
159
|
+
# "CONFIG_OSDP_DATA_TRACE",
|
|
160
|
+
# "CONFIG_OSDP_SKIP_MARK_BYTE",
|
|
161
|
+
]
|
|
162
|
+
|
|
163
|
+
compile_args = (
|
|
164
|
+
[ "-I" + path for path in include_dirs ] +
|
|
165
|
+
[ "-D" + define for define in definitions ]
|
|
166
|
+
)
|
|
167
|
+
|
|
168
|
+
link_args = []
|
|
169
|
+
|
|
170
|
+
if os.path.exists("README.md"):
|
|
171
|
+
with open("README.md", "r") as f:
|
|
172
|
+
long_description = f.read()
|
|
173
|
+
else:
|
|
174
|
+
long_description = ""
|
|
175
|
+
|
|
176
|
+
setup(
|
|
177
|
+
name = project_name,
|
|
178
|
+
version = project_version,
|
|
179
|
+
author = "Siddharth Chandrasekaran",
|
|
180
|
+
author_email = "sidcha.dev@gmail.com",
|
|
181
|
+
description = "Library implementation of IEC 60839-11-5 OSDP (Open Supervised Device Protocol)",
|
|
182
|
+
url = "https://github.com/goToMain/libosdp",
|
|
183
|
+
ext_modules = [
|
|
184
|
+
Extension(
|
|
185
|
+
name = "osdp_sys",
|
|
186
|
+
sources = source_files,
|
|
187
|
+
extra_compile_args = compile_args,
|
|
188
|
+
extra_link_args = link_args,
|
|
189
|
+
define_macros = [],
|
|
190
|
+
language = "C",
|
|
191
|
+
)
|
|
192
|
+
],
|
|
193
|
+
packages = [ "osdp" ],
|
|
194
|
+
classifiers = [
|
|
195
|
+
"Programming Language :: Python :: 3",
|
|
196
|
+
"License :: OSI Approved :: Apache Software License",
|
|
197
|
+
"Operating System :: OS Independent",
|
|
198
|
+
],
|
|
199
|
+
long_description = long_description,
|
|
200
|
+
long_description_content_type = "text/markdown",
|
|
201
|
+
python_requires = ">=3.8",
|
|
202
|
+
package_data = { project_name : other_files }
|
|
203
|
+
)
|