M lazy-lock.json M lua/custom/configs/lspconfig.lua M lua/custom/init.lua A lua/custom/journal.lua A nvim_venv/bin/Activate.ps1 A nvim_venv/bin/activate A nvim_venv/bin/activate.csh A nvim_venv/bin/activate.fish
208 lines
6.6 KiB
Python
208 lines
6.6 KiB
Python
"""Diagnostic record read/write."""
|
|
from __future__ import annotations
|
|
|
|
import struct
|
|
|
|
from pymodbus.constants import ModbusStatus
|
|
from pymodbus.datastore import ModbusSlaveContext
|
|
from pymodbus.device import DeviceInformationFactory, ModbusControlBlock
|
|
from pymodbus.pdu.pdu import ModbusPDU
|
|
|
|
|
|
_MCB = ModbusControlBlock()
|
|
|
|
|
|
class ReadExceptionStatusRequest(ModbusPDU):
|
|
"""ReadExceptionStatusRequest."""
|
|
|
|
function_code = 0x07
|
|
rtu_frame_size = 4
|
|
|
|
def encode(self) -> bytes:
|
|
"""Encode the message."""
|
|
return b""
|
|
|
|
def decode(self, _data: bytes) -> None:
|
|
"""Decode data part of the message."""
|
|
|
|
async def update_datastore(self, _context: ModbusSlaveContext) -> ModbusPDU:
|
|
"""Run a read exception status request against the store."""
|
|
status = _MCB.Counter.summary()
|
|
return ReadExceptionStatusResponse(status=status, dev_id=self.dev_id, transaction_id=self.transaction_id)
|
|
|
|
|
|
class ReadExceptionStatusResponse(ModbusPDU):
|
|
"""ReadExceptionStatusResponse."""
|
|
|
|
function_code = 0x07
|
|
rtu_frame_size = 5
|
|
|
|
def encode(self) -> bytes:
|
|
"""Encode the response."""
|
|
return struct.pack(">B", self.status)
|
|
|
|
def decode(self, data: bytes) -> None:
|
|
"""Decode a the response."""
|
|
self.status = int(data[0])
|
|
|
|
|
|
# Encapsulate interface transport 43, 14
|
|
# CANopen general reference 43, 13
|
|
|
|
class GetCommEventCounterRequest(ModbusPDU):
|
|
"""GetCommEventCounterRequest."""
|
|
|
|
function_code = 0x0B
|
|
rtu_frame_size = 4
|
|
|
|
def encode(self) -> bytes:
|
|
"""Encode the message."""
|
|
return b""
|
|
|
|
def decode(self, _data: bytes) -> None:
|
|
"""Decode data part of the message."""
|
|
|
|
async def update_datastore(self, _context) -> ModbusPDU:
|
|
"""Run a read exception status request against the store."""
|
|
count = _MCB.Counter.Event
|
|
return GetCommEventCounterResponse(count=count, dev_id=self.dev_id, transaction_id=self.transaction_id)
|
|
|
|
|
|
class GetCommEventCounterResponse(ModbusPDU):
|
|
"""GetCommEventCounterRequest."""
|
|
|
|
function_code = 0x0B
|
|
rtu_frame_size = 8
|
|
|
|
def encode(self) -> bytes:
|
|
"""Encode the response."""
|
|
ready = ModbusStatus.READY if self.status else ModbusStatus.WAITING
|
|
return struct.pack(">HH", ready, self.count)
|
|
|
|
def decode(self, data: bytes) -> None:
|
|
"""Decode a the response."""
|
|
ready, self.count = struct.unpack(">HH", data)
|
|
self.status = ready == ModbusStatus.READY
|
|
|
|
|
|
class GetCommEventLogRequest(ModbusPDU):
|
|
"""GetCommEventLogRequest."""
|
|
|
|
function_code = 0x0C
|
|
rtu_frame_size = 4
|
|
|
|
def encode(self) -> bytes:
|
|
"""Encode the message."""
|
|
return b""
|
|
|
|
def decode(self, _data: bytes) -> None:
|
|
"""Decode data part of the message."""
|
|
|
|
async def update_datastore(self, _context: ModbusSlaveContext) -> ModbusPDU:
|
|
"""Run a read exception status request against the store."""
|
|
return GetCommEventLogResponse(
|
|
status=True,
|
|
message_count=_MCB.Counter.BusMessage,
|
|
event_count=_MCB.Counter.Event,
|
|
events=_MCB.getEvents(),
|
|
dev_id=self.dev_id, transaction_id=self.transaction_id)
|
|
|
|
|
|
class GetCommEventLogResponse(ModbusPDU):
|
|
"""GetCommEventLogRequest."""
|
|
|
|
function_code = 0x0C
|
|
rtu_byte_count_pos = 2
|
|
|
|
def __init__(self, status: bool = True, message_count: int = 0, event_count: int = 0, events: list[int] | None = None, dev_id: int = 1, transaction_id: int = 0) -> None:
|
|
"""Initialize a new instance."""
|
|
super().__init__(transaction_id=transaction_id, dev_id=dev_id, status=status)
|
|
self.message_count = message_count
|
|
self.event_count = event_count
|
|
self.events = events or []
|
|
|
|
def encode(self) -> bytes:
|
|
"""Encode the response."""
|
|
if self.status:
|
|
ready = ModbusStatus.READY
|
|
else:
|
|
ready = ModbusStatus.WAITING
|
|
packet = struct.pack(">B", 6 + len(self.events))
|
|
packet += struct.pack(">H", ready)
|
|
packet += struct.pack(">HH", self.event_count, self.message_count)
|
|
packet += b"".join(struct.pack(">B", e) for e in self.events)
|
|
return packet
|
|
|
|
def decode(self, data: bytes) -> None:
|
|
"""Decode a the response."""
|
|
length = int(data[0])
|
|
status = struct.unpack(">H", data[1:3])[0]
|
|
self.status = status == ModbusStatus.READY
|
|
self.event_count = struct.unpack(">H", data[3:5])[0]
|
|
self.message_count = struct.unpack(">H", data[5:7])[0]
|
|
|
|
self.events = []
|
|
for i in range(7, length + 1):
|
|
self.events.append(int(data[i]))
|
|
|
|
|
|
class ReportSlaveIdRequest(ModbusPDU):
|
|
"""ReportSlaveIdRequest."""
|
|
|
|
function_code = 0x11
|
|
rtu_frame_size = 4
|
|
|
|
def encode(self) -> bytes:
|
|
"""Encode the message."""
|
|
return b""
|
|
|
|
def decode(self, _data: bytes) -> None:
|
|
"""Decode data part of the message."""
|
|
|
|
async def update_datastore(self, _context: ModbusSlaveContext) -> ModbusPDU:
|
|
"""Run a report slave id request against the store."""
|
|
information = DeviceInformationFactory.get(_MCB)
|
|
id_data = []
|
|
for v_item in information.values():
|
|
if isinstance(v_item, bytes):
|
|
id_data.append(v_item)
|
|
else:
|
|
id_data.append(v_item.encode())
|
|
|
|
identifier = b"-".join(id_data)
|
|
identifier = identifier or b"Pymodbus"
|
|
return ReportSlaveIdResponse(identifier=identifier, dev_id=self.dev_id, transaction_id=self.transaction_id)
|
|
|
|
|
|
class ReportSlaveIdResponse(ModbusPDU):
|
|
"""ReportSlaveIdRequeste."""
|
|
|
|
function_code = 0x11
|
|
rtu_byte_count_pos = 2
|
|
|
|
def __init__(self, identifier: bytes = b"\x00", status: bool = True, dev_id: int = 1, transaction_id: int = 0) -> None:
|
|
"""Initialize a new instance."""
|
|
super().__init__(transaction_id=transaction_id, dev_id=dev_id, status=status)
|
|
self.identifier = identifier
|
|
self.byte_count = 0
|
|
|
|
def encode(self) -> bytes:
|
|
"""Encode the response."""
|
|
status = ModbusStatus.SLAVE_ON if self.status else ModbusStatus.SLAVE_OFF
|
|
length = len(self.identifier) + 1
|
|
packet = struct.pack(">B", length)
|
|
packet += self.identifier # we assume it is already encoded
|
|
packet += struct.pack(">B", status)
|
|
return packet
|
|
|
|
def decode(self, data: bytes) -> None:
|
|
"""Decode a the response.
|
|
|
|
Since the identifier is device dependent, we just return the
|
|
raw value that a user can decode to whatever it should be.
|
|
"""
|
|
self.byte_count = int(data[0])
|
|
self.identifier = data[1 : self.byte_count + 1]
|
|
status = int(data[-1])
|
|
self.status = status == ModbusStatus.SLAVE_ON
|