<commit_before># -*- coding: utf-8 -*-

"""
Collection of transaction based abstractions
"""
import struct
import socket
from binascii import b2a_hex, a2b_hex
from pymodbus3.exceptions import ModbusIOException
from pymodbus3.constants import Defaults, FramerState
from pymodbus3.interfaces import IModbusFramer
from pymodbus3.utilities import check_crc, compute_crc
from pymodbus3.utilities import check_lrc, compute_lrc

# Logging
import logging
_logger = logging.getLogger(__name__)


# region The Global Transaction Manager

class ModbusTransactionManager(object):
    """ Implements a transaction for a manager

    The transaction protocol can be represented by the following pseudo code::

        count = 0
        do
          result = send(message)
          if (timeout or result == bad)
             count++
          else break
        while (count < 3)

    This module helps to abstract this away from the framer and protocol.
    """

    def __init__(self, client, **kwargs):
        """ Initializes an instance of the ModbusTransactionManager

        :param client: The client socket wrapper
        :param retry_on_empty: Should the client retry on empty
        :param retries: The number of retries to allow
        """
        self.transactions = None
        self.state = None
        self.tid = Defaults.TransactionId
        self.client = client
        self.framer = client and client.framer
        self.retry_on_empty = kwargs.get(
            'retry_on_empty', Defaults.RetryOnEmpty
        )
        self.retries = kwargs.get('retries', Defaults.Retries)

    def execute(self, request):
        """ Starts the producer to send the next request to
        consumer.write(Frame(request))
        """
        retries = self.retries
        request.transaction_id = self.get_next_tid()
        _logger.debug('Running transaction ' + str(request.transaction_id))

        while retries > 0:
            try:
                self.state = FramerState.Initializing
                self.client.connect()
                self.client.send(self.client.framer.build_packet(request))
                if not self.handle_message_framing():
                    raise ModbusIOException(
                        'Server responded with bad response'
                    )
                break
            except socket.error as msg:
                self.client.close()
                _logger.debug('Transaction failed ' + str(msg))
                retries -= 1
        return self.get_transaction(request.transaction_id)

    def handle_message_framing(self):
        """ This abstracts performing all the framing logic
        using a simple state machine.

        It should be explained that the original framer design
        was intended to be used by the twisted framework and to
        respond to streams provided by a single async callback.
        That is why the design is as it is now.

        Along the way a number of users asked for a non-twisted
        version, using stock python. In order to do this I tried
        to simply reuse the existing framing code with a few hacks.
        It turned out to be poor fit.

        In order to not have to rewrite the entire framing base,
        I am simply using it to implement the following state
        machine directly which should take care of a number of
        legacy issues.

        **The Management**
        """
        retries = self.retries  # we want to allow a few errors

        while retries > 0:
            # before we start reading, we allow the framer to
            # put itself into a newly consistent state.
            if self.state == FramerState.Initializing:
                self.framer.advance_frame()  # initialize
                self.state = FramerState.ReadingHeader

            # we know how much to read for the fixed size
            # header, so we loop until we have it to guide us.
            elif self.state == FramerState.ReadingHeader:
                size = self.framer.header_size - len(self.framer.buffer)
                if size != 0:
                    result = self.client.receive(size)  # off by one on clear<commit_msg>RTU framer fix - read ADU _and_ PDU header<commit_after># -*- coding: utf-8 -*-

"""
Collection of transaction based abstractions
"""
import struct
import socket
from binascii import b2a_hex, a2b_hex
from pymodbus3.exceptions import ModbusIOException
from pymodbus3.constants import Defaults, FramerState
from pymodbus3.interfaces import IModbusFramer
from pymodbus3.utilities import check_crc, compute_crc
from pymodbus3.utilities import check_lrc, compute_lrc

# Logging
import logging
_logger = logging.getLogger(__name__)


# region The Global Transaction Manager

class ModbusTransactionManager(object):
    """ Implements a transaction for a manager

    The transaction protocol can be represented by the following pseudo code::

        count = 0
        do
          result = send(message)
          if (timeout or result == bad)
             count++
          else break
        while (count < 3)

    This module helps to abstract this away from the framer and protocol.
    """

    def __init__(self, client, **kwargs):
        """ Initializes an instance of the ModbusTransactionManager

        :param client: The client socket wrapper
        :param retry_on_empty: Should the client retry on empty
        :param retries: The number of retries to allow
        """
        self.transactions = None
        self.state = None
        self.tid = Defaults.TransactionId
        self.client = client
        self.framer = client and client.framer
        self.retry_on_empty = kwargs.get(
            'retry_on_empty', Defaults.RetryOnEmpty
        )
        self.retries = kwargs.get('retries', Defaults.Retries)

    def execute(self, request):
        """ Starts the producer to send the next request to
        consumer.write(Frame(request))
        """
        retries = self.retries
        request.transaction_id = self.get_next_tid()
        _logger.debug('Running transaction ' + str(request.transaction_id))

        while retries > 0:
            try:
                self.state = FramerState.Initializing
                self.client.connect()
                self.client.send(self.client.framer.build_packet(request))
                if not self.handle_message_framing():
                    raise ModbusIOException(
                        'Server responded with bad response'
                    )
                break
            except socket.error as msg:
                self.client.close()
                _logger.debug('Transaction failed ' + str(msg))
                retries -= 1
        return self.get_transaction(request.transaction_id)

    def handle_message_framing(self):
        """ This abstracts performing all the framing logic
        using a simple state machine.

        It should be explained that the original framer design
        was intended to be used by the twisted framework and to
        respond to streams provided by a single async callback.
        That is why the design is as it is now.

        Along the way a number of users asked for a non-twisted
        version, using stock python. In order to do this I tried
        to simply reuse the existing framing code with a few hacks.
        It turned out to be poor fit.

        In order to not have to rewrite the entire framing base,
        I am simply using it to implement the following state
        machine directly which should take care of a number of
        legacy issues.

        **The Management**
        """
        retries = self.retries  # we want to allow a few errors

        while retries > 0:
            # before we start reading, we allow the framer to
            # put itself into a newly consistent state.
            if self.state == FramerState.Initializing:
                self.framer.advance_frame()  # initialize
                self.state = FramerState.ReadingHeader

            # we know how much to read for the fixed size
            # header, so we loop until we have it to guide us.
            elif self.state == FramerState.ReadingHeader:
                # size = self.framer.header_size - len(self.framer.buffer)
                # framing on not yet received stream data does not work.
                # RTU header_size is 1 (1Byte of ADU for UnitID/SlaveID/Modbus Address)
                # But need FunctionCode (1Byte) and Byte Count Byte to calculate length of Content Part
                # [header_size xByte ... unitId/Addr 1Byte][FunctionCode 1Byte][Count 1Byte]
                size = self.framer.header_size + 2 - len(self.framer.buffer)
                if size != 0:
                    result = self.client.receive(size)  # off by one on clear
{'fraction_non_alphanumeric': 0.06204379562043796, 'fraction_numerical': 0.0039917883211678835, 'mean_word_length': 2.097492052278347, 'pattern_counts': {'":': 0, '<': 5, '<?xml version=': 0, '>': 7, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '2193573', 'n_tokens_mistral': 2268, 'n_tokens_neox': 2176, 'n_words': 848}