import logging
from ctypes import byref, c_uint8, CFUNCTYPE
from time import sleep, time
from typing import Optional, Union
from .core import PSP, get_psp_exc_msg
from .exc import (
PSPError,
PSPInvalid,
PSPNotSupport,
)
from .lmbinc import (
ERR_NotSupport,
ERR_Success,
IntrusionMsg,
)
from .sdk_dll import DLL
logger = logging.getLogger(__name__)
SUPPORTED_PLATFORMS = ("LEB-7242", "NCA-2510",)
UNSUPPORTED_PLATFORMS = ("LEB-2680", "LEC-2290", "LEC-7230", "V3S", "V6S",)
[docs]
class SWR:
"""
Software Reset Button.
:param bool check_platform:
Set to :data:`True` to check if the platform supports this feature.
Defaults to :data:`False` for better compatibility.
:raises PSPNotSupport: This function is not supported
(when ``check_platform`` is set to :data:`True`).
:raises NotImplementedError: It has not been verified to run on this platform
(when ``check_platform`` is set to :data:`True`).
"""
def __init__(self, check_platform: bool = False) -> None:
self._version = DLL().get_version()
if not check_platform:
return
if self._version.platform_id in SUPPORTED_PLATFORMS:
pass
elif self._version.platform_id in UNSUPPORTED_PLATFORMS:
raise PSPNotSupport("Not supported on this platform")
else:
raise NotImplementedError
[docs]
def get_status(self) -> int:
"""
Get software reset button status.
Example:
.. code-block:: pycon
>>> swr = SWR()
>>> swr.get_status()
1
:return: software reset button status
:rtype: int
:raises PSPNotSupport: This function is not supported.
:raises PSPError: General PSP functional error.
"""
ub_read = c_uint8()
with PSP() as psp:
i_ret = psp.lib.LMB_SWR_GetStatus(byref(ub_read))
msg = get_psp_exc_msg("LMB_SWR_GetStatus", i_ret)
if i_ret == ERR_Success:
return ub_read.value
elif i_ret == ERR_NotSupport:
raise PSPNotSupport(msg)
else:
raise PSPError(msg)
@classmethod
def _callback(cls, stu_intrusion_msg: IntrusionMsg) -> None:
"""Callback function for :func:`exec_callback`."""
print(f"SWR Item = {stu_intrusion_msg.udw_occur_item:04X}, "
f"Status = {stu_intrusion_msg.udw_status:04X}, "
f"time is {stu_intrusion_msg.stu_time.uw_year:04d}/"
f"{stu_intrusion_msg.stu_time.ub_month:02d}/"
f"{stu_intrusion_msg.stu_time.ub_day:02d} "
f"{stu_intrusion_msg.stu_time.ub_hour:02d}:"
f"{stu_intrusion_msg.stu_time.ub_minute:02d}:"
f"{stu_intrusion_msg.stu_time.ub_second:02d}")
[docs]
def exec_callback(self) -> None:
"""
Use callback function to detect software reset button status (default 10 seconds).
Example:
.. code-block:: pycon
>>> swr = SWR()
>>> swr.exec_callback()
----> hook Software-Reset button Callback OK <----
===> wait about 10 second time <===
SWR Item = 0001, Status = 0001, time is 2022/08/01 17:45:12
SWR Item = 0001, Status = 0000, time is 2022/08/01 17:45:13
SWR Item = 0001, Status = 0001, time is 2022/08/01 17:45:14
SWR Item = 0001, Status = 0000, time is 2022/08/01 17:45:14
SWR Item = 0001, Status = 0001, time is 2022/08/01 17:45:15
SWR Item = 0001, Status = 0000, time is 2022/08/01 17:45:16
----> disabled Software-Reset button Callback hook <----
"""
c_callback = CFUNCTYPE(None, IntrusionMsg)
p_callback = c_callback(self._callback)
with PSP() as psp:
i_ret = psp.lib.LMB_SWR_IntrCallback(p_callback, 150)
if i_ret != ERR_Success:
print("-----> hook Software-Reset button callback failure <-------")
return
print("----> hook Software-Reset button Callback OK <----")
print("===> wait about 10 second time <===")
sleep(10)
i_ret = psp.lib.LMB_SWR_IntrCallback(None, 150)
if i_ret == ERR_Success:
print("----> disabled Software-Reset button Callback hook <----")
def test(self, secs: int = 5) -> None:
"""
For testing (default 5 seconds delay).
Example:
.. code-block:: pycon
>>> swr = SWR()
>>> swr.test(5)
>>> swr.test()
===> wait 5 seconds for Software Reset Button trigger .......
5. 4. 3. 2. 1. 0.
Software/Reset button not detected ! --> ALARM
.. code-block:: pycon
>>> swr.test()
===> wait 5 seconds for Software Reset Button trigger .......
5. 4.
Software/Reset button pressed ! --> OK
:param int secs: seconds for test
:raises TypeError: The input parameters type error.
:raises ValueError: The input parameters value error.
"""
# Check type.
if not isinstance(secs, int):
raise TypeError("'secs' type must be int")
# Check value.
if secs <= 0:
raise ValueError("'secs' value must be > 0")
# Run.
ub_read = c_uint8()
dw_cnt = 0
index = int(secs)
i_time = int(secs)
print(f"===> wait {secs:d} seconds for Software Reset Button trigger .......")
with PSP() as psp:
while True:
if dw_cnt % 10 == 0:
print(f"{index}. ", end="", flush=True)
index -= 1
psp.lib.LMB_SWR_GetStatus(byref(ub_read))
if ub_read.value == 1:
break
dw_cnt += 1
if dw_cnt > i_time * 10:
break
sleep(0.1)
print()
if ub_read.value == 1:
print("Software/Reset button pressed ! --> OK")
else:
print("\033[1;31mSoftware/Reset button not detected ! --> ALARM\033[0m")
@property
def is_pressed(self) -> bool:
"""
Returns :data:`True` if the device is currently active and :data:`False` otherwise.
Example:
.. code-block:: pycon
>>> swr = SWR()
>>> swr.is_pressed
True
:return: if is pressed or not
:rtype: bool
:raises PSPNotSupport: This function is not supported.
:raises PSPError: General PSP functional error.
"""
return bool(self.get_status())
[docs]
def wait_for_press(self, timeout: Optional[Union[float, int]] = None) -> None:
"""
Pause the script until the device is activated, or the timeout is reached.
Example:
.. code-block:: pycon
>>> swr = SWR()
>>> swr.wait_for_press()
:type timeout: float or int or None
:param timeout: Number of seconds to wait before proceeding.
If this is :data:`None` (the default), then wait indefinitely until the device is active.
:raises TypeError: The input parameters type error.
:raises PSPInvalid: The input parameters value error.
:raises PSPNotSupport: This function is not supported.
:raises PSPError: General PSP functional error.
"""
if timeout is not None:
# Check type.
if not isinstance(timeout, (float, int)):
raise TypeError("'timeout' type must be float or int or None")
# Check value.
if timeout <= 0:
raise PSPInvalid("'timeout' value must be > 0")
# Run.
start_time = time()
while True:
if self.is_pressed:
break
if timeout and time() - start_time >= timeout:
break
sleep(0.1)
[docs]
def wait_for_release(self, timeout: Optional[Union[float, int]] = None) -> None:
"""
Pause the script until the device is deactivated, or the timeout is reached.
Example:
.. code-block:: pycon
>>> swr = SWR()
>>> swr.wait_for_release()
:type timeout: float or int or None
:param timeout: Number of seconds to wait before proceeding.
If this is :data:`None` (the default), then wait indefinitely until the device is active.
:raises TypeError: The input parameters type error.
:raises PSPInvalid: The input parameters value error.
:raises PSPNotSupport: This function is not supported.
:raises PSPError: General PSP functional error.
"""
if timeout is not None:
# Check type.
if not isinstance(timeout, (float, int)):
raise TypeError("'timeout' type must be float or int or None")
# Check value.
if timeout <= 0:
raise PSPInvalid("'timeout' value must be > 0")
# Run.
start_time = time()
while True:
if not self.is_pressed:
break
if timeout and time() - start_time >= timeout:
break
sleep(0.1)