Skip to content

Commit

Permalink
Merge pull request #135 from goToMain/osdp_pd_status
Browse files Browse the repository at this point in the history
Add support for PD online status
  • Loading branch information
sidcha committed Oct 11, 2023
2 parents a99e295 + cee13a9 commit e4df2be
Show file tree
Hide file tree
Showing 7 changed files with 135 additions and 24 deletions.
18 changes: 18 additions & 0 deletions python/pyosdp_pd.c
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,22 @@

#define TAG "pyosdp_pd"

#define pyosdp_pd_is_online_doc \
"Get PD status, (online/offline)\n" \
"\n" \
"@return PD online status (Bool)"
static PyObject *pyosdp_pd_is_online(pyosdp_pd_t *self, PyObject *args)
{
uint64_t mask;

osdp_get_status_mask(self->ctx, (uint8_t *)&mask);

if (mask & 1)
Py_RETURN_TRUE;
else
Py_RETURN_FALSE;
}

#define pyosdp_pd_is_sc_active_doc \
"Get Secure Channel status, (active/inactive)\n" \
"\n" \
Expand Down Expand Up @@ -351,6 +367,8 @@ static PyMethodDef pyosdp_pd_tp_methods[] = {
METH_VARARGS, pyosdp_pd_notify_event_doc },
{ "is_sc_active", (PyCFunction)pyosdp_pd_is_sc_active,
METH_NOARGS, pyosdp_pd_is_sc_active_doc },
{ "is_online", (PyCFunction)pyosdp_pd_is_online,
METH_NOARGS, pyosdp_pd_is_online_doc },
{ "flush_events", (PyCFunction)pyosdp_pd_flush_events,
METH_VARARGS, pyosdp_pd_flush_events_doc },
{ NULL, NULL, 0, NULL } /* Sentinel */
Expand Down
1 change: 1 addition & 0 deletions python/setup.py.in
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ sources = utils_sources + pyosdp_sources

libosdp_include_dirs = ('@PROJECT_SOURCE_DIR@/utils/include'.split(';') +
'@PROJECT_SOURCE_DIR@/include'.split(';') +
'@LIB_OSDP_INCLUDE_DIRS@'.split(';') +
'@LIB_OSDP_PRIVATE_INCLUDE_DIRS@'.split(';'))

libosdp_includes = [ '-I' + path for path in libosdp_include_dirs ]
Expand Down
10 changes: 7 additions & 3 deletions src/osdp_common.c
Original file line number Diff line number Diff line change
Expand Up @@ -255,7 +255,12 @@ void osdp_get_status_mask(osdp_t *ctx, uint8_t *bitmask)
input_check(ctx);
int i, pos;
uint8_t *mask = bitmask;
struct osdp_pd *pd;
struct osdp_pd *pd = osdp_to_pd(ctx, 0);

if (ISSET_FLAG(pd, PD_FLAG_PD_MODE)) {
*mask = osdp_millis_since(pd->tstamp) < OSDP_RESP_TOUT_MS;
return;
}

*mask = 0;
for (i = 0; i < NUM_PD(ctx); i++) {
Expand All @@ -265,8 +270,7 @@ void osdp_get_status_mask(osdp_t *ctx, uint8_t *bitmask)
*mask = 0;
}
pd = osdp_to_pd(ctx, i);
if (ISSET_FLAG(pd, PD_FLAG_PD_MODE) ||
pd->state == OSDP_CP_STATE_ONLINE) {
if (pd->state == OSDP_CP_STATE_ONLINE) {
*mask |= 1 << pos;
}
}
Expand Down
8 changes: 8 additions & 0 deletions tests/pytest/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
# Run Tests

`make check` on cmake builds will invoke pytest correctly. During development,
it might be useful to run an individual test (instead of everything). To do so,

```
PYTHONPATH=../../build/python/ python3 -m pytest -vv -s test_events.py::test_event_input
```
68 changes: 68 additions & 0 deletions tests/pytest/test_status.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
#
# Copyright (c) 2023 Siddharth Chandrasekaran <sidcha.dev@gmail.com>
#
# SPDX-License-Identifier: Apache-2.0
#

import time
import pytest

from testlib import *

pd_cap = PDCapabilities([
(Capability.OutputControl, 1, 1),
(Capability.LEDControl, 1, 1),
(Capability.AudibleControl, 1, 1),
(Capability.TextOutput, 1, 1),
])

pd_info = [
PDInfo(101, scbk=KeyStore.gen_key(), name='chn-0'),
]

# TODO remove this.
pd_addr = pd_info[0].address
pd = PeripheralDevice(pd_info[0], pd_cap, log_level=LogLevel.Debug)
cp = ControlPanel(pd_info)

@pytest.fixture(scope='module', autouse=True)
def setup_test():
pd.start()
cp.start()
cp.sc_wait_all()
yield
teardown_test()

def teardown_test():
cp.teardown()
pd.teardown()

def test_cp_status():
assert cp.online_wait(pd.address)
pd.stop()
assert cp.online_wait(pd.address) == False
pd.start()
assert cp.online_wait(pd.address)

def test_cp_sc_status():
assert cp.sc_wait(pd.address)
pd.stop()
assert cp.sc_wait(pd.address) == False
pd.start()
assert cp.sc_wait(pd.address)

def test_pd_status():
cp.stop()
time.sleep(1)
assert pd.is_online() == False
cp.start()
assert cp.sc_wait(pd.address)
assert pd.is_online()

def test_pd_sc_status():
cp.stop()
time.sleep(1)
assert pd.is_sc_active() == False
cp.start()
assert cp.sc_wait(pd.address)
assert pd.is_sc_active()
27 changes: 16 additions & 11 deletions tests/pytest/testlib/control_panel.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,10 +30,9 @@ def __init__(self, pd_info_list, log_level: LogLevel=LogLevel.Info,
self.ctx = osdp.ControlPanel(info_list)
self.ctx.set_event_callback(self.event_handler)
self.ctx.set_loglevel(log_level)
self.event = threading.Event()
self.lock = threading.Lock()
args = (self.event, self.lock, self.ctx,)
self.thread = threading.Thread(name='cp', target=self.refresh, args=args)
self.event = None
self.lock = None
self.thread = None

@staticmethod
def refresh(event, lock, ctx):
Expand Down Expand Up @@ -126,20 +125,26 @@ def get_file_tx_status(self, address):
return ret

def start(self):
if not self.thread:
return False
if self.thread:
raise RuntimeError("Thread already running!")
self.event = threading.Event()
self.lock = threading.Lock()
args=(self.event, self.lock, self.ctx)
self.thread = threading.Thread(name='cp', target=self.refresh, args=args)
self.thread.start()

def stop(self):
while self.thread and self.thread.is_alive():
if not self.thread:
raise RuntimeError("Thread not running!")
while self.thread.is_alive():
self.event.set()
self.thread.join(2)
if not self.thread.is_alive():
return True
return False
self.thread = None
break

def online_wait_all(self, timeout=10):
count = 10
count = 0
res = False
while count < timeout * 2:
time.sleep(0.5)
Expand All @@ -150,7 +155,7 @@ def online_wait_all(self, timeout=10):
return res

def online_wait(self, address, timeout=5):
count = 10
count = 0
res = False
while count < timeout * 2:
time.sleep(0.5)
Expand Down
27 changes: 17 additions & 10 deletions tests/pytest/testlib/peripheral_device.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,9 @@ def __init__(self, pd_info: PDInfo, pd_cap: PDCapabilities,
self.ctx = osdp.PeripheralDevice(pd_info.get(), capabilities=pd_cap.get())
self.ctx.set_loglevel(log_level)
self.ctx.set_command_callback(self.command_handler)
self.event = threading.Event()
self.lock = threading.Lock()
args = (self.event, self.lock, self.ctx,)
self.thread = threading.Thread(name='pd', target=self.refresh, args=args)
self.event = None
self.lock = None
self.thread = None

@staticmethod
def refresh(event, lock, ctx):
Expand Down Expand Up @@ -59,19 +58,27 @@ def register_file_ops(self, fops):
def is_sc_active(self):
return self.ctx.is_sc_active()

def is_online(self):
return self.ctx.is_online()

def start(self):
if self.thread:
self.thread.start()
return True
return False
raise RuntimeError("Thread already running!")
self.event = threading.Event()
self.lock = threading.Lock()
args = (self.event, self.lock, self.ctx,)
self.thread = threading.Thread(name='pd', target=self.refresh, args=args)
self.thread.start()

def stop(self):
while self.thread and self.thread.is_alive():
if not self.thread:
raise RuntimeError("Thread not running!")
while self.thread.is_alive():
self.event.set()
self.thread.join(2)
if not self.thread.is_alive():
return True
return False
self.thread = None
break

def teardown(self):
self.stop()
Expand Down

0 comments on commit e4df2be

Please sign in to comment.