Files
ThingsBoard/RPI Docker Test/modbus/utils.py
2024-10-04 18:53:54 -05:00

168 lines
4.9 KiB
Python

#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
Modbus TestKit: Implementation of Modbus protocol in python
(C)2009 - Luc Jean - luc.jean@gmail.com
(C)2009 - Apidev - http://www.apidev.fr
This is distributed under GNU LGPL license, see license.txt
"""
import threading
import logging
import socket
import select
def threadsafe_function(fcn):
"""decorator making sure that the decorated function is thread safe"""
lock = threading.Lock()
def new(*args, **kwargs):
"""lock and call the decorated function"""
lock.acquire()
try:
ret = fcn(*args, **kwargs)
except Exception, excpt:
raise excpt
finally:
lock.release()
return ret
return new
def flush_socket(socks, lim=0):
"""remove the data present on the socket"""
input_socks = [socks]
cnt = 0
while 1:
i_socks, o_socks, e_socks = select.select(input_socks, input_socks, input_socks, 0.0)
if len(i_socks)==0:
break
for sock in i_socks:
sock.recv(1024)
if lim>0:
cnt += 1
if cnt>=lim:
#avoid infinite loop due to loss of connection
raise Exception("flush_socket: maximum number of iterations reached")
def get_log_buffer(prefix, buff):
"""Format binary data into a string for debug purpose"""
log = prefix
for i in buff:
log += str(ord(i)) + "-"
return log[:-1]
class ConsoleHandler(logging.Handler):
"""This class is a logger handler. It prints on the console"""
def __init__(self):
"""Constructor"""
logging.Handler.__init__(self)
def emit(self, record):
"""format and print the record on the console"""
print self.format(record)
class LogitHandler(logging.Handler):
"""This class is a logger handler. It send to a udp socket"""
def __init__(self, dest):
"""Constructor"""
logging.Handler.__init__(self)
self._dest = dest
self._sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
def emit(self, record):
"""format and send the record over udp"""
self._sock.sendto(self.format(record)+"\r\n", self._dest)
class DummyHandler(logging.Handler):
"""This class is a logger handler. It doesn't do anything"""
def __init__(self):
"""Constructor"""
logging.Handler.__init__(self)
def emit(self, record):
"""do nothinbg with the given record"""
pass
def create_logger(name="dummy", level=logging.DEBUG, \
record_format="%(asctime)s\t%(levelname)s\t%(module)s.%(funcName)s\t%(threadName)s\t%(message)s"):
"""Create a logger according to the given settings"""
logger = logging.getLogger("modbus_tk")
logger.setLevel(level)
formatter = logging.Formatter(record_format)
if name == "udp":
log_handler = LogitHandler(("127.0.0.1", 1975))
elif name == "console":
log_handler = ConsoleHandler()
elif name == "dummy":
log_handler = DummyHandler()
else:
raise Exception("Unknown handler %s" % name)
log_handler.setFormatter(formatter)
logger.addHandler(log_handler)
return logger
def swap_bytes(word_val):
"""swap lsb and msb of a word"""
msb = word_val >> 8
lsb = word_val % 256
return (lsb << 8) + msb
def calculate_crc(data):
"""Calculate the CRC16 of a datagram"""
crc = 0xFFFF
for i in data:
crc = crc ^ ord(i)
for j in xrange(8):
tmp = crc & 1
crc = crc >> 1
if tmp:
crc = crc ^ 0xA001
return swap_bytes(crc)
def calculate_rtu_inter_char(baudrate):
"""calculates the interchar delay from the baudrate"""
if baudrate <= 19200:
return 11.0 / baudrate
else:
return 0.0005
class WorkerThread:
"""
A thread which is running an almost-ever loop
It can be stopped by calling the stop function
"""
def __init__(self, main_fct, args=(), init_fct=None, exit_fct=None):
"""Constructor"""
self._fcts = [init_fct, main_fct, exit_fct]
self._args = args
self._thread = threading.Thread(target=WorkerThread._run, args=(self,))
self._go = threading.Event()
def start(self):
"""Start the thread"""
self._go.set()
self._thread.start()
def stop(self):
"""stop the thread"""
if self._thread.isAlive():
self._go.clear()
self._thread.join()
def _run(self):
"""main function of the thread execute _main_fct until stop is called"""
try:
if self._fcts[0]:
self._fcts[0](*self._args)
while self._go.isSet():
self._fcts[1](*self._args)
except Exception, excpt:
LOGGER.error("error: %s" % str(excpt))
finally:
if self._fcts[2]:
self._fcts[2](*self._args)