|
|
@@ -1,11 +1,15 @@
|
|
|
import time
|
|
|
import serial
|
|
|
-from pydantic import validate_call
|
|
|
from typing import Any, Callable
|
|
|
-from nbus_types.nbus_serial_config import NBusSerialConfig
|
|
|
+
|
|
|
+from beartype import beartype
|
|
|
+
|
|
|
from nbus_types.nbus_command_type import *
|
|
|
from nbus_types.nbus_exceptions.nbus_network_exception import *
|
|
|
from nbus_types.nbus_exceptions.nbus_node_exception import *
|
|
|
+from nbus_hal.nbus_serial.serial_config import NBusSerialConfig
|
|
|
+from nbus_hal.nbus_generic_port import NBusPort, NBusDelay
|
|
|
+from nbus_types.nbus_address_type import NBusModuleAddress, NBusDeviceAddress
|
|
|
from nbus_hal.crc8 import crc8
|
|
|
|
|
|
|
|
|
@@ -24,17 +28,16 @@ def default_logger(*message: Any) -> None:
|
|
|
print()
|
|
|
|
|
|
|
|
|
-class NBusSerialPort:
|
|
|
+@beartype
|
|
|
+class NBusSerialPort(NBusPort):
|
|
|
"""
|
|
|
Class representing nBus serial port.
|
|
|
"""
|
|
|
-
|
|
|
- @validate_call
|
|
|
def __init__(self, config: NBusSerialConfig):
|
|
|
self._port = serial.Serial(timeout=config.timeout)
|
|
|
self._port.port = config.port_name
|
|
|
- self._port.parity = config.parity
|
|
|
- self._port.baudrate = config.baud
|
|
|
+ self._port.parity = config.parity.value
|
|
|
+ self._port.baudrate = config.baud.value
|
|
|
self._logger_cb = default_logger
|
|
|
self._enable_log = config.enable_log
|
|
|
self._request_attempts = config.request_attempts
|
|
|
@@ -48,7 +51,6 @@ class NBusSerialPort:
|
|
|
def open(self) -> None:
|
|
|
"""
|
|
|
Open port.
|
|
|
- :return: None
|
|
|
"""
|
|
|
self._port.open()
|
|
|
self._port.flush()
|
|
|
@@ -57,7 +59,6 @@ class NBusSerialPort:
|
|
|
def close(self) -> None:
|
|
|
"""
|
|
|
Close port.
|
|
|
- :return: None
|
|
|
"""
|
|
|
self._log('i', 0, 'Close communication port')
|
|
|
self._port.close()
|
|
|
@@ -65,69 +66,90 @@ class NBusSerialPort:
|
|
|
def is_connected(self) -> bool:
|
|
|
"""
|
|
|
Return connection status.
|
|
|
- :return: True = connected | False = not connected
|
|
|
+ :return: status (1 = connected, 0 = not connected)
|
|
|
"""
|
|
|
return self._port.is_open
|
|
|
|
|
|
- @validate_call(validate_return=True)
|
|
|
def set_logger(self, callback: Callable[[Any], None]) -> None:
|
|
|
"""
|
|
|
Set logger function.
|
|
|
:param callback: logging callback
|
|
|
- :return: None
|
|
|
"""
|
|
|
self._logger_cb = callback
|
|
|
|
|
|
- @validate_call
|
|
|
- def request_broadcast(self, command: NBusCommand, data: list[int]) -> None:
|
|
|
+ def request_broadcast(self, command: NBusCommand, data: bytearray) -> None:
|
|
|
"""
|
|
|
Make broadcast request to nbus network.
|
|
|
:param command: command id
|
|
|
:param data: command data to send
|
|
|
- :return: None
|
|
|
"""
|
|
|
request = self._create_packet([0, 0, 0, command.value], data)
|
|
|
self._log("\tBRQ>", request)
|
|
|
self._port.write(request) # send message
|
|
|
|
|
|
- @validate_call(validate_return=True)
|
|
|
- def request(self, module: int, sensor: int, command: NBusCommand, data: list[int], long_answer: float = 0) -> list[int]:
|
|
|
+ def request_module(self, module_addr: NBusModuleAddress, command: NBusCommand, data: bytearray,
|
|
|
+ long_answer: NBusDelay = 0.0) -> bytearray:
|
|
|
"""
|
|
|
- Make request to nbus node.
|
|
|
+ Make module request to nbus network.
|
|
|
+ :param module_addr: address of module
|
|
|
+ :param command: command id
|
|
|
+ :param data: command data to send
|
|
|
+ :param long_answer: delay in s for longer answer
|
|
|
+ :return: | payload length | payload |
|
|
|
+ """
|
|
|
+ return self._request_response(module_addr.value, 0, command.value, data, long_answer)
|
|
|
+
|
|
|
+ def request_device(self, module_addr: NBusModuleAddress, device_address: NBusDeviceAddress,
|
|
|
+ command: NBusCommand, data: bytearray, long_answer: NBusDelay = 0.0) -> bytearray:
|
|
|
+ """
|
|
|
+ Make device request to nbus network.
|
|
|
+ :param module_addr: address of module
|
|
|
+ :param device_address: address of device
|
|
|
+ :param command: command id
|
|
|
+ :param data: command data to send
|
|
|
+ :param long_answer: delay in s for longer answer
|
|
|
+ :return: | payload length | payload |
|
|
|
+ """
|
|
|
+ return self._request_response(module_addr.value, device_address.value, command.value, data, long_answer)
|
|
|
+
|
|
|
+ """
|
|
|
+ ================================================================================================================
|
|
|
+ Internal Methods
|
|
|
+ ================================================================================================================
|
|
|
+ """
|
|
|
+
|
|
|
+ def _request_response(self, module: int, sensor: int, command, data: bytearray,
|
|
|
+ long_answer: float = 0) -> bytearray:
|
|
|
+ """
|
|
|
+ Make request to nbus node and receive response.
|
|
|
:param module: module address
|
|
|
:param sensor: sensor address
|
|
|
:param command: command id
|
|
|
:param data: command data to send
|
|
|
:param long_answer: timeout for long answer
|
|
|
- :return: response
|
|
|
+ :return: response length | response
|
|
|
"""
|
|
|
- request = self._create_packet([0, module, sensor, command.value], data) # create request
|
|
|
- self._log('d', sensor, "\tRQ>", request) # log request
|
|
|
+ request = self._create_packet(bytearray([0, module, sensor, command]), data) # create request
|
|
|
+ self._log('d', sensor, "\tRQ>", request) # log request
|
|
|
|
|
|
- counter = 0 # err. trials
|
|
|
+ counter = 0 # err. trials
|
|
|
|
|
|
- while True: # try to communicate
|
|
|
+ while True: # try to communicate
|
|
|
self._port.write(request)
|
|
|
|
|
|
- if long_answer > 0: # wait for long answer
|
|
|
+ if long_answer > 0: # wait for long answer
|
|
|
time.sleep(long_answer)
|
|
|
|
|
|
try:
|
|
|
return self._receive_payload()
|
|
|
|
|
|
- except NBusErrorNetwork as Ex: # if network error, try to reconnect
|
|
|
+ except NBusErrorNetwork as Ex: # if network error, try to reconnect
|
|
|
counter += 1
|
|
|
|
|
|
if counter > self._request_attempts:
|
|
|
- raise Ex # if out of trials, propagate exception
|
|
|
-
|
|
|
- """
|
|
|
- ================================================================================================================
|
|
|
- Internal Methods
|
|
|
- ================================================================================================================
|
|
|
- """
|
|
|
+ raise Ex # if out of trials, propagate exception
|
|
|
|
|
|
- def _create_packet(self, start: list[int], data: list[int]) -> list[int]:
|
|
|
+ def _create_packet(self, start: bytearray, data: bytearray) -> bytearray:
|
|
|
"""
|
|
|
Create packet to send and prepare port.
|
|
|
:param start: head of message
|
|
|
@@ -148,10 +170,10 @@ class NBusSerialPort:
|
|
|
start.append(crc_sum)
|
|
|
return start
|
|
|
|
|
|
- def _receive_payload(self) -> list[int]:
|
|
|
+ def _receive_payload(self) -> bytearray:
|
|
|
"""
|
|
|
Read response from serial.
|
|
|
- :return: payload
|
|
|
+ :return: | payload len | payload
|
|
|
"""
|
|
|
# read data length
|
|
|
response_l = self._port.read(1)
|
|
|
@@ -169,19 +191,18 @@ class NBusSerialPort:
|
|
|
if response[-1] != crc8(response[:-1]):
|
|
|
raise NBusErrorNetwork(NBusErrorNetworkType.DAMAGED_MESSAGE)
|
|
|
|
|
|
- self._log('d', 0, "\tRS>", response_l, response) # log response
|
|
|
+ self._log('d', 0, "\tRS>", [response_l] + list(response)) # log response
|
|
|
|
|
|
# check for node error
|
|
|
if response[2] & NBUS_ERR_BIT:
|
|
|
raise NBusErrorNode(NBusErrorNodeType(response[3]))
|
|
|
|
|
|
- return [response_l - 4] + list(response)[3:-1] # return payload length + payload
|
|
|
+ return bytearray([response_l - 4]) + bytearray(response[3:-1]) # return payload length + payload
|
|
|
|
|
|
def _log(self, *message: Any) -> None:
|
|
|
"""
|
|
|
Log request/response.
|
|
|
:param message: message to log
|
|
|
- :return: processed log
|
|
|
"""
|
|
|
if self._enable_log:
|
|
|
self._logger_cb(*message)
|