initial
This commit is contained in:
142
env/lib/python3.11/site-packages/pymodbus/framer/base.py
vendored
Normal file
142
env/lib/python3.11/site-packages/pymodbus/framer/base.py
vendored
Normal file
@@ -0,0 +1,142 @@
|
||||
"""Framer start."""
|
||||
# pylint: disable=missing-type-doc
|
||||
from typing import Any, Dict, Union
|
||||
|
||||
from pymodbus.factory import ClientDecoder, ServerDecoder
|
||||
from pymodbus.logging import Log
|
||||
|
||||
|
||||
# Unit ID, Function Code
|
||||
BYTE_ORDER = ">"
|
||||
FRAME_HEADER = "BB"
|
||||
|
||||
# Transaction Id, Protocol ID, Length, Unit ID, Function Code
|
||||
SOCKET_FRAME_HEADER = BYTE_ORDER + "HHH" + FRAME_HEADER
|
||||
|
||||
# Function Code
|
||||
TLS_FRAME_HEADER = BYTE_ORDER + "B"
|
||||
|
||||
|
||||
class ModbusFramer:
|
||||
"""Base Framer class."""
|
||||
|
||||
name = ""
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
decoder: Union[ClientDecoder, ServerDecoder],
|
||||
client=None,
|
||||
) -> None:
|
||||
"""Initialize a new instance of the framer.
|
||||
|
||||
:param decoder: The decoder implementation to use
|
||||
"""
|
||||
self.decoder = decoder
|
||||
self.client = client
|
||||
self._header: Dict[str, Any] = {
|
||||
"lrc": "0000",
|
||||
"len": 0,
|
||||
"uid": 0x00,
|
||||
"tid": 0,
|
||||
"pid": 0,
|
||||
"crc": b"\x00\x00",
|
||||
}
|
||||
self._buffer = b""
|
||||
|
||||
def _validate_slave_id(self, slaves: list, single: bool) -> bool:
|
||||
"""Validate if the received data is valid for the client.
|
||||
|
||||
:param slaves: list of slave id for which the transaction is valid
|
||||
:param single: Set to true to treat this as a single context
|
||||
:return:
|
||||
"""
|
||||
if single:
|
||||
return True
|
||||
if 0 in slaves or 0xFF in slaves:
|
||||
# Handle Modbus TCP slave identifier (0x00 0r 0xFF)
|
||||
# in asynchronous requests
|
||||
return True
|
||||
return self._header["uid"] in slaves
|
||||
|
||||
def sendPacket(self, message):
|
||||
"""Send packets on the bus.
|
||||
|
||||
With 3.5char delay between frames
|
||||
:param message: Message to be sent over the bus
|
||||
:return:
|
||||
"""
|
||||
return self.client.send(message)
|
||||
|
||||
def recvPacket(self, size):
|
||||
"""Receive packet from the bus.
|
||||
|
||||
With specified len
|
||||
:param size: Number of bytes to read
|
||||
:return:
|
||||
"""
|
||||
return self.client.recv(size)
|
||||
|
||||
def resetFrame(self):
|
||||
"""Reset the entire message frame.
|
||||
|
||||
This allows us to skip ovver errors that may be in the stream.
|
||||
It is hard to know if we are simply out of sync or if there is
|
||||
an error in the stream as we have no way to check the start or
|
||||
end of the message (python just doesn't have the resolution to
|
||||
check for millisecond delays).
|
||||
"""
|
||||
Log.debug(
|
||||
"Resetting frame - Current Frame in buffer - {}", self._buffer, ":hex"
|
||||
)
|
||||
self._buffer = b""
|
||||
self._header = {
|
||||
"lrc": "0000",
|
||||
"crc": b"\x00\x00",
|
||||
"len": 0,
|
||||
"uid": 0x00,
|
||||
"pid": 0,
|
||||
"tid": 0,
|
||||
}
|
||||
|
||||
def populateResult(self, result):
|
||||
"""Populate the modbus result header.
|
||||
|
||||
The serial packets do not have any header information
|
||||
that is copied.
|
||||
|
||||
:param result: The response packet
|
||||
"""
|
||||
result.slave_id = self._header.get("uid", 0)
|
||||
result.transaction_id = self._header.get("tid", 0)
|
||||
result.protocol_id = self._header.get("pid", 0)
|
||||
|
||||
def processIncomingPacket(self, data, callback, slave, **kwargs):
|
||||
"""Process new packet pattern.
|
||||
|
||||
This takes in a new request packet, adds it to the current
|
||||
packet stream, and performs framing on it. That is, checks
|
||||
for complete messages, and once found, will process all that
|
||||
exist. This handles the case when we read N + 1 or 1 // N
|
||||
messages at a time instead of 1.
|
||||
|
||||
The processed and decoded messages are pushed to the callback
|
||||
function to process and send.
|
||||
|
||||
:param data: The new packet data
|
||||
:param callback: The function to send results to
|
||||
:param slave: Process if slave id matches, ignore otherwise (could be a
|
||||
list of slave ids (server) or single slave id(client/server))
|
||||
:param kwargs:
|
||||
:raises ModbusIOException:
|
||||
"""
|
||||
Log.debug("Processing: {}", data, ":hex")
|
||||
self._buffer += data
|
||||
if not isinstance(slave, (list, tuple)):
|
||||
slave = [slave]
|
||||
single = kwargs.pop("single", False)
|
||||
self.frameProcessIncomingPacket(single, callback, slave, **kwargs)
|
||||
|
||||
def frameProcessIncomingPacket(
|
||||
self, _single, _callback, _slave, _tid=None, **kwargs
|
||||
):
|
||||
"""Process new packet pattern."""
|
||||
Reference in New Issue
Block a user