import logging
from ctypes import byref
from typing import Any, Dict, NamedTuple
from .core import PSP, get_psp_exc_msg
from .exc import (
PSPBusyInUses,
PSPError,
PSPInvalid,
PSPNotOpened,
PSPNotSupport,
)
from .lmbinc import (
BASE_SECOND,
BASE_MINUTE,
ERR_BusyInUses,
ERR_Invalid,
ERR_NotOpened,
ERR_NotSupport,
ERR_Success,
WDT_TYPE_SIO,
WDT_TYPE_TCO,
WDT_TYPE_UNKNOWN,
WDTInfo,
)
from .sdk_dll import DLL
logger = logging.getLogger(__name__)
SUPPORTED_PLATFORMS = ("LEB-2680", "LEB-7242", "LEC-2290", "LEC-7230", "NCA-2510", "V3S", "V6S",)
UNSUPPORTED_PLATFORMS = ()
[docs]
class WDTInfoModel(NamedTuple):
"""To store WDT info values."""
type: str
max_count: int
is_minute_support: bool
[docs]
def to_dict(self) -> Dict[str, Any]:
"""Convert to dict."""
return dict(self._asdict())
[docs]
class WDT:
"""
Watch Dog Timer.
: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_info(self) -> WDTInfoModel:
"""
Get Watch Dog Timer information.
Example:
.. code-block:: pycon
>>> wdt = WDT()
>>> wdt.get_info()
WDTInfoModel(type='SuperIO', max_count=255, is_minute_support=True)
:return: WDT information
:rtype: WDTInfoModel
:raises PSPNotOpened: The library is not ready or opened yet.
:raises PSPNotSupport: This platform does not support this function.
:raises PSPError: General PSP functional error.
"""
stu_wdt_info = WDTInfo()
type_mapping = {WDT_TYPE_UNKNOWN: "Unknown", WDT_TYPE_SIO: "SuperIO", WDT_TYPE_TCO: "TCO"}
with PSP() as psp:
i_ret = psp.lib.LMB_WDT_QueryInfo(byref(stu_wdt_info))
msg = get_psp_exc_msg("LMB_WDT_QueryInfo", i_ret)
if i_ret == ERR_Success:
return WDTInfoModel(
type=type_mapping[stu_wdt_info.ub_type],
max_count=stu_wdt_info.uw_count_max,
is_minute_support=bool(stu_wdt_info.ub_minute_support),
)
elif i_ret == ERR_NotOpened:
raise PSPNotOpened(msg)
elif i_ret == ERR_NotSupport:
raise PSPNotSupport(msg)
else:
raise PSPError(msg)
[docs]
def config(self, count: int, time_base: int = 1) -> None:
"""
Configure the Watch Dog Timer for specific time.
Example for 200 seconds:
.. code-block:: pycon
>>> wdt = WDT()
>>> wdt.config(200)
Example for 2 minutes:
.. code-block:: pycon
>>> wdt = WDT()
>>> wdt.config(2, 2)
:param int count:
The value sets the timer count down.
:param int time_base:
The value selects time base. Set ``1`` to select SECOND base,
Set ``2`` to select MINUTE base. Defaults to ``1``.
:raises TypeError: The input parameters type error.
:raises PSPInvalid: Invalid parameter value.
:raises PSPNotOpened: The library is not ready or opened yet.
:raises PSPNotSupport: This platform does not support this function.
:raises PSPBusyInUses: This step is skipped because WDT is already starting now.
:raises PSPError: General PSP functional error.
"""
# Check type.
if not isinstance(count, int):
raise TypeError("'count' type must be int")
if not isinstance(time_base, int):
raise TypeError("'time_base' type must be int")
# Check value.
info = self.get_info()
if not 0 <= count <= info.max_count:
raise PSPInvalid(f"'count' value must be between 0 and {info.max_count}")
if time_base not in (BASE_SECOND, BASE_MINUTE):
raise PSPInvalid(f"'time_base' value must be {BASE_SECOND}"
f" for SECOND base or {BASE_MINUTE} for MINUTE base")
if not info.is_minute_support and time_base == BASE_MINUTE:
raise PSPInvalid("WDT only support SECOND base")
# Run.
time_base_mapping = {BASE_SECOND: "seconds", BASE_MINUTE: "minutes"}
with PSP() as psp:
i_ret = psp.lib.LMB_WDT_Config(count, time_base)
msg = get_psp_exc_msg("LMB_WDT_Config", i_ret)
if i_ret == ERR_Success:
logger.debug(f"configure the watchdog timer for {count:d} {time_base_mapping[time_base]}")
elif i_ret == ERR_Invalid:
raise PSPInvalid(msg)
elif i_ret == ERR_NotOpened:
raise PSPNotOpened(msg)
elif i_ret == ERR_NotSupport:
raise PSPNotSupport(msg)
elif i_ret == ERR_BusyInUses:
raise PSPBusyInUses(msg)
else:
raise PSPError(msg)
[docs]
def enable(self, count: int = 0, time_base: int = 1) -> None:
"""
Configure the Watch Dog Timer for specific time and start the WDT countdown.
You can :func:`enable` dircetly by a given time:
.. code-block:: pycon
>>> wdt = WDT()
>>> wdt.enable(200)
Or :func:`config` first then :func:`enable`
.. code-block:: pycon
>>> wdt = WDT()
>>> wdt.config(200)
>>> wdt.enable()
:param int count:
The value sets the timer count down. Defaults to 0.
:param int time_base:
The value selects time base. Set ``1`` to select SECOND base,
Set ``2`` to select MINUTE base. Defaults to ``1``.
:raises TypeError: The input parameters type error.
:raises PSPInvalid: Invalid parameter value.
:raises PSPNotOpened: The library is not ready or opened yet.
:raises PSPNotSupport: This platform does not support this function.
:raises PSPBusyInUses: This step is skipped because WDT is already starting now.
:raises PSPError: General PSP functional error.
"""
if count != 0:
self.config(count, time_base)
with PSP() as psp:
i_ret = psp.lib.LMB_WDT_Start()
msg = get_psp_exc_msg("LMB_WDT_Start", i_ret)
if i_ret == ERR_Success:
logger.debug("enable watchdog timer")
elif i_ret == ERR_NotOpened:
raise PSPNotOpened(msg)
elif i_ret == ERR_NotSupport:
raise PSPNotSupport(msg)
else:
raise PSPError(msg)
[docs]
def disable(self) -> None:
"""
Stop the WDT countdown.
Example:
.. code-block:: pycon
>>> wdt = WDT()
>>> wdt.enable(10)
>>>
>>> wdt.disable()
:raises PSPNotOpened: The library is not ready or opened yet.
:raises PSPNotSupport: This platform does not support this function.
:raises PSPError: General PSP functional error.
"""
with PSP() as psp:
i_ret = psp.lib.LMB_WDT_Stop()
msg = get_psp_exc_msg("LMB_WDT_Stop", i_ret)
if i_ret == ERR_Success:
logger.debug("disable watchdog timer")
elif i_ret == ERR_NotOpened:
raise PSPNotOpened(msg)
elif i_ret == ERR_NotSupport:
raise PSPNotSupport(msg)
else:
raise PSPError(msg)
[docs]
def reset(self) -> None:
"""
Reload the timer and then re-computes it.
Example:
.. code-block:: pycon
>>> wdt = WDT()
>>> wdt.enable(10)
>>>
>>> wdt.reset()
:raises PSPNotOpened: The library is not ready or opened yet.
:raises PSPNotSupport: This platform does not support this function.
:raises PSPError: General PSP functional error.
"""
with PSP() as psp:
i_ret = psp.lib.LMB_WDT_Tick()
msg = get_psp_exc_msg("LMB_WDT_Tick", i_ret)
if i_ret == ERR_Success:
logger.debug("reset watchdog timer")
elif i_ret == ERR_NotOpened:
raise PSPNotOpened(msg)
elif i_ret == ERR_NotSupport:
raise PSPNotSupport(msg)
else:
raise PSPError(msg)