@@ -42,7 +42,6 @@ class Talent(Message):
|
||||
self.contact_name = b''
|
||||
self.contact_mail = b''
|
||||
self.db = InfosG3()
|
||||
self.mb = Modbus()
|
||||
self.forward_modbus_resp = False
|
||||
self.switch = {
|
||||
0x00: self.msg_contact_info,
|
||||
@@ -392,11 +391,11 @@ class Talent(Message):
|
||||
self.header_len+self.data_len]
|
||||
|
||||
if self.ctrl.is_req():
|
||||
if not self.mb.recv_req(data[hdr_len:]):
|
||||
return
|
||||
|
||||
self.forward_modbus_resp = True
|
||||
self.inc_counter('Modbus_Command')
|
||||
if not self.remoteStream.mb.recv_req(data[hdr_len:]):
|
||||
self.inc_counter('Invalid_Msg_Format')
|
||||
else:
|
||||
self.inc_counter('Modbus_Command')
|
||||
self.remoteStream.forward_modbus_resp = True
|
||||
elif self.ctrl.is_ind():
|
||||
# logger.debug(f'Modbus Ind MsgLen: {modbus_len}')
|
||||
self.modbus_elms = 0
|
||||
|
||||
@@ -60,8 +60,8 @@ class SolarmanV5(Message):
|
||||
self.snr = 0
|
||||
self.db = InfosG3P()
|
||||
self.time_ofs = 0
|
||||
self.mb = Modbus()
|
||||
self.forward_modbus_resp = False
|
||||
self.forward_at_cmd_resp = False
|
||||
self.switch = {
|
||||
|
||||
0x4210: self.msg_data_ind, # real time data
|
||||
@@ -319,6 +319,7 @@ class SolarmanV5(Message):
|
||||
async def send_at_cmd(self, AT_cmd: str) -> None:
|
||||
if self.state != self.STATE_UP:
|
||||
return
|
||||
self.forward_at_cmd_resp = False
|
||||
self.__build_header(0x4510)
|
||||
self._send_buffer += struct.pack(f'<BHLLL{len(AT_cmd)}sc', self.AT_CMD,
|
||||
2, 0, 0, 0, AT_cmd.encode('utf-8'),
|
||||
@@ -372,14 +373,14 @@ class SolarmanV5(Message):
|
||||
data = self._recv_buffer[self.header_len:]
|
||||
result = struct.unpack_from('<BLLL', data, 0)
|
||||
ftype = result[0] # always 2
|
||||
total = result[1]
|
||||
# total = result[1]
|
||||
tim = result[2]
|
||||
res = result[3] # always zero
|
||||
logger.info(f'frame type:{ftype:02x}'
|
||||
f' timer:{tim:08x}s null:{res}')
|
||||
if self.time_ofs:
|
||||
dt = datetime.fromtimestamp(total + self.time_ofs)
|
||||
logger.info(f'ts: {dt.strftime("%Y-%m-%d %H:%M:%S")}')
|
||||
# if self.time_ofs:
|
||||
# dt = datetime.fromtimestamp(total + self.time_ofs)
|
||||
# logger.info(f'ts: {dt.strftime("%Y-%m-%d %H:%M:%S")}')
|
||||
|
||||
self.__process_data(ftype)
|
||||
self.__forward_msg()
|
||||
@@ -389,7 +390,7 @@ class SolarmanV5(Message):
|
||||
data = self._recv_buffer
|
||||
result = struct.unpack_from('<BHLLLHL', data, self.header_len)
|
||||
ftype = result[0] # 1 or 0x81
|
||||
total = result[2]
|
||||
# total = result[2]
|
||||
tim = result[3]
|
||||
if 1 == ftype:
|
||||
self.time_ofs = result[4]
|
||||
@@ -397,9 +398,9 @@ class SolarmanV5(Message):
|
||||
cnt = result[6]
|
||||
logger.info(f'ftype:{ftype:02x} timer:{tim:08x}s'
|
||||
f' ??: {unkn:04x} cnt:{cnt}')
|
||||
if self.time_ofs:
|
||||
dt = datetime.fromtimestamp(total + self.time_ofs)
|
||||
logger.info(f'ts: {dt.strftime("%Y-%m-%d %H:%M:%S")}')
|
||||
# if self.time_ofs:
|
||||
# dt = datetime.fromtimestamp(total + self.time_ofs)
|
||||
# logger.info(f'ts: {dt.strftime("%Y-%m-%d %H:%M:%S")}')
|
||||
|
||||
self.__process_data(ftype)
|
||||
self.__forward_msg()
|
||||
@@ -426,11 +427,13 @@ class SolarmanV5(Message):
|
||||
ftype = result[0]
|
||||
if ftype == self.AT_CMD:
|
||||
self.inc_counter('AT_Command')
|
||||
self.forward_at_cmd_resp = True
|
||||
elif ftype == self.MB_RTU_CMD:
|
||||
if not self.mb.recv_req(data[15:]):
|
||||
return
|
||||
self.forward_modbus_resp = True
|
||||
self.inc_counter('Modbus_Command')
|
||||
if not self.remoteStream.mb.recv_req(data[15:]):
|
||||
self.inc_counter('Invalid_Msg_Format')
|
||||
else:
|
||||
self.inc_counter('Modbus_Command')
|
||||
self.remoteStream.forward_modbus_resp = True
|
||||
|
||||
self.__forward_msg()
|
||||
# self.__send_ack_rsp(0x1510, ftype)
|
||||
@@ -440,7 +443,8 @@ class SolarmanV5(Message):
|
||||
self.header_len+self.data_len]
|
||||
ftype = data[0]
|
||||
if ftype == self.AT_CMD:
|
||||
pass
|
||||
if not self.forward_at_cmd_resp:
|
||||
return
|
||||
elif ftype == self.MB_RTU_CMD:
|
||||
valid = data[1]
|
||||
modbus_msg_len = self.data_len - 14
|
||||
|
||||
@@ -3,8 +3,10 @@ import weakref
|
||||
|
||||
if __name__ == "app.src.messages":
|
||||
from app.src.infos import Infos
|
||||
from app.src.modbus import Modbus
|
||||
else: # pragma: no cover
|
||||
from infos import Infos
|
||||
from modbus import Modbus
|
||||
|
||||
logger = logging.getLogger('msg')
|
||||
|
||||
@@ -58,6 +60,9 @@ class Message(metaclass=IterRegistry):
|
||||
self._registry.append(weakref.ref(self))
|
||||
|
||||
self.server_side = server_side
|
||||
if server_side:
|
||||
self.mb = Modbus()
|
||||
|
||||
self.header_valid = False
|
||||
self.header_len = 0
|
||||
self.data_len = 0
|
||||
|
||||
@@ -86,11 +86,11 @@ class Modbus():
|
||||
# logging.info(f'recv_req: first byte modbus:{buf[0]} len:{len(buf)}')
|
||||
if not self.check_crc(buf):
|
||||
self.err = 1
|
||||
logging.error('Modbus: CRC error')
|
||||
logging.error('Modbus recv: CRC error')
|
||||
return False
|
||||
if buf[0] != self.INV_ADDR:
|
||||
self.err = 2
|
||||
logging.info(f'Modbus: Wrong addr{buf[0]}')
|
||||
logging.info(f'Modbus recv: Wrong addr{buf[0]}')
|
||||
return False
|
||||
res = struct.unpack_from('>BHH', buf, 1)
|
||||
self.last_fcode = res[0]
|
||||
@@ -103,11 +103,11 @@ class Modbus():
|
||||
Generator[tuple[str, bool], None, None]:
|
||||
# logging.info(f'recv_resp: first byte modbus:{buf[0]} len:{len(buf)}')
|
||||
if not self.check_crc(buf):
|
||||
logging.error('Modbus: CRC error')
|
||||
logging.error('Modbus resp: CRC error')
|
||||
self.err = 1
|
||||
return
|
||||
if buf[0] != self.INV_ADDR:
|
||||
logging.info(f'Modbus: Wrong addr {buf[0]}')
|
||||
logging.info(f'Modbus resp: Wrong addr {buf[0]}')
|
||||
self.err = 2
|
||||
return
|
||||
if buf[1] != self.last_fcode:
|
||||
|
||||
@@ -63,6 +63,12 @@ class MemoryStream(SolarmanV5):
|
||||
if self.test_exception_async_write:
|
||||
raise RuntimeError("Peer closed.")
|
||||
|
||||
def createClientStream(self, msg, chunks = (0,)):
|
||||
c = MemoryStream(msg, chunks, False)
|
||||
self.remoteStream = c
|
||||
c. remoteStream = self
|
||||
return c
|
||||
|
||||
def _SolarmanV5__flush_recv_msg(self) -> None:
|
||||
super()._SolarmanV5__flush_recv_msg()
|
||||
self.msg_count += 1
|
||||
@@ -350,6 +356,39 @@ def InverterIndMsg800(): # 0x4210 rated Power 800W
|
||||
msg += b'\x15'
|
||||
return msg
|
||||
|
||||
@pytest.fixture
|
||||
def InverterIndMsg_81(): # 0x4210 fcode 0x81
|
||||
msg = b'\xa5\x99\x01\x10\x42\x02\x03' +get_sn() +b'\x81\xb0\x02\xbc\xc8'
|
||||
msg += b'\x24\x32\x6c\x1f\x00\x00\xa0\x07\x04\x03\x01\x00\x03\x08\x00\x00'
|
||||
msg += b'\x59\x31\x37\x45\x37\x41\x30\x46\x30\x31\x30\x42\x30\x31\x33\x45'
|
||||
msg += b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
|
||||
msg += b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
|
||||
msg += b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
|
||||
msg += b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
|
||||
msg += b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
|
||||
msg += b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
|
||||
msg += b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
|
||||
msg += b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
|
||||
msg += b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
|
||||
msg += b'\x00\x01\x00\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
|
||||
msg += b'\x40\x10\x08\xc8\x00\x49\x13\x8d\x00\x36\x00\x00\x02\x58\x06\x7a'
|
||||
msg += b'\x01\x61\x00\xa8\x02\x54\x01\x5a\x00\x8a\x01\xe4\x01\x5a\x00\xbd'
|
||||
msg += b'\x02\x8f\x00\x11\x00\x01\x00\x00\x00\x0b\x00\x00\x27\x98\x00\x04'
|
||||
msg += b'\x00\x00\x0c\x04\x00\x03\x00\x00\x0a\xe7\x00\x05\x00\x00\x0c\x75'
|
||||
msg += b'\x00\x00\x00\x00\x06\x16\x02\x00\x00\x00\x55\xaa\x00\x01\x00\x00'
|
||||
msg += b'\x00\x00\x00\x00\xff\xff\x07\xd0\x00\x03\x04\x00\x04\x00\x04\x00'
|
||||
msg += b'\x04\x00\x00\x01\xff\xff\x00\x01\x00\x06\x00\x68\x00\x68\x05\x00'
|
||||
msg += b'\x09\xcd\x07\xb6\x13\x9c\x13\x24\x00\x01\x07\xae\x04\x0f\x00\x41'
|
||||
msg += b'\x00\x0f\x0a\x64\x0a\x64\x00\x06\x00\x06\x09\xf6\x12\x8c\x12\x8c'
|
||||
msg += b'\x00\x10\x00\x10\x14\x52\x14\x52\x00\x10\x00\x10\x01\x51\x00\x05'
|
||||
msg += b'\x04\x00\x00\x01\x13\x9c\x0f\xa0\x00\x4e\x00\x66\x03\xe8\x04\x00'
|
||||
msg += b'\x09\xce\x07\xa8\x13\x9c\x13\x26\x00\x00\x00\x00\x00\x00\x00\x00'
|
||||
msg += b'\x00\x00\x00\x00\x04\x00\x04\x00\x00\x00\x00\x00\xff\xff\x00\x00'
|
||||
msg += b'\x00\x00\x00\x00'
|
||||
msg += correct_checksum(msg)
|
||||
msg += b'\x15'
|
||||
return msg
|
||||
|
||||
@pytest.fixture
|
||||
def InverterRspMsg(): # 0x1210
|
||||
msg = b'\xa5\x0a\x00\x10\x12\x02\02' +get_sn() +b'\x01\x01'
|
||||
@@ -359,6 +398,15 @@ def InverterRspMsg(): # 0x1210
|
||||
msg += b'\x15'
|
||||
return msg
|
||||
|
||||
@pytest.fixture
|
||||
def InverterRspMsg_81(): # 0x1210 fcode 0x81
|
||||
msg = b'\xa5\x0a\x00\x10\x12\x03\03' +get_sn() +b'\x81\x01'
|
||||
msg += total()
|
||||
msg += hb()
|
||||
msg += correct_checksum(msg)
|
||||
msg += b'\x15'
|
||||
return msg
|
||||
|
||||
@pytest.fixture
|
||||
def UnknownMsg(): # 0x5110
|
||||
msg = b'\xa5\x0a\x00\x10\x51\x10\x84' +get_sn() +b'\x01\x01\x69\x6f\x09'
|
||||
@@ -461,6 +509,15 @@ def MsgModbusCmd():
|
||||
msg += b'\x15'
|
||||
return msg
|
||||
|
||||
@pytest.fixture
|
||||
def MsgModbusCmdCrcErr():
|
||||
msg = b'\xa5\x17\x00\x10\x45\x03\x02' +get_sn() +b'\x02\xb0\x02'
|
||||
msg += b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x06\x20\x08'
|
||||
msg += b'\x00\x00\x04\xc8'
|
||||
msg += correct_checksum(msg)
|
||||
msg += b'\x15'
|
||||
return msg
|
||||
|
||||
@pytest.fixture
|
||||
def MsgModbusRsp(): # 0x1510
|
||||
msg = b'\xa5\x3b\x00\x10\x15\x03\x03' +get_sn() +b'\x02\x01'
|
||||
@@ -496,6 +553,19 @@ def MsgUnknownCmd():
|
||||
msg += b'\x15'
|
||||
return msg
|
||||
|
||||
@pytest.fixture
|
||||
def MsgUnknownCmdRsp(): # 0x1510
|
||||
msg = b'\xa5\x3b\x00\x10\x15\x03\x03' +get_sn() +b'\x03\x01'
|
||||
msg += total()
|
||||
msg += hb()
|
||||
msg += b'\x0a\xe2\xfa\x33\x01\x03\x28\x40\x10\x08\xd8'
|
||||
msg += b'\x00\x00\x13\x87\x00\x31\x00\x68\x02\x58\x00\x00\x01\x53\x00\x02'
|
||||
msg += b'\x00\x00\x01\x52\x00\x02\x00\x00\x01\x53\x00\x03\x00\x00\x00\x04'
|
||||
msg += b'\x00\x01\x00\x00\x6c\x68'
|
||||
msg += correct_checksum(msg)
|
||||
msg += b'\x15'
|
||||
return msg
|
||||
|
||||
@pytest.fixture
|
||||
def ConfigTsunAllowAll():
|
||||
Config.config = {'solarman':{'enabled': True}, 'inverters':{'allow_all':True}}
|
||||
@@ -779,6 +849,52 @@ def test_read_two_messages(ConfigTsunAllowAll, DeviceIndMsg, DeviceRspMsg, Inver
|
||||
assert m._send_buffer==b''
|
||||
m.close()
|
||||
|
||||
def test_read_two_messages2(ConfigTsunAllowAll, InverterIndMsg, InverterIndMsg_81, InverterRspMsg, InverterRspMsg_81):
|
||||
ConfigTsunAllowAll
|
||||
m = MemoryStream(InverterIndMsg, (0,))
|
||||
m.append_msg(InverterIndMsg_81)
|
||||
m.read() # read complete msg, and dispatch msg
|
||||
assert not m.header_valid # must be invalid, since msg was handled and buffer flushed
|
||||
assert m.msg_count == 1
|
||||
assert m.header_len==11
|
||||
assert m.snr == 2070233889
|
||||
assert m.unique_id == '2070233889'
|
||||
assert m.control == 0x4210
|
||||
assert m.time_ofs == 0x33e447a0
|
||||
assert str(m.seq) == '02:02'
|
||||
assert m.data_len == 0x199
|
||||
assert m.msg_count == 1
|
||||
assert m.db.stat['proxy']['Invalid_Msg_Format'] == 0
|
||||
assert m._forward_buffer==InverterIndMsg
|
||||
assert m._send_buffer==InverterRspMsg
|
||||
|
||||
m._send_buffer = bytearray(0) # clear send buffer for next test
|
||||
m._init_new_client_conn()
|
||||
assert m._send_buffer==b''
|
||||
assert m._recv_buffer==InverterIndMsg_81
|
||||
|
||||
m._send_buffer = bytearray(0) # clear send buffer for next test
|
||||
m._forward_buffer = bytearray(0) # clear forward buffer for next test
|
||||
m.read() # read complete msg, and dispatch msg
|
||||
assert m.db.stat['proxy']['Invalid_Msg_Format'] == 0
|
||||
assert not m.header_valid # must be invalid, since msg was handled and buffer flushed
|
||||
assert m.msg_count == 2
|
||||
assert m.header_len==11
|
||||
assert m.snr == 2070233889
|
||||
assert m.unique_id == '2070233889'
|
||||
assert m.control == 0x4210
|
||||
assert m.time_ofs == 0x33e447a0
|
||||
assert str(m.seq) == '03:03'
|
||||
assert m.data_len == 0x199
|
||||
assert m.db.stat['proxy']['Invalid_Msg_Format'] == 0
|
||||
assert m._forward_buffer==InverterIndMsg_81
|
||||
assert m._send_buffer==InverterRspMsg_81
|
||||
|
||||
m._send_buffer = bytearray(0) # clear send buffer for next test
|
||||
m._init_new_client_conn()
|
||||
assert m._send_buffer==b''
|
||||
m.close()
|
||||
|
||||
def test_unkown_message(ConfigTsunInv1, UnknownMsg):
|
||||
ConfigTsunInv1
|
||||
m = MemoryStream(UnknownMsg, (0,))
|
||||
@@ -1144,7 +1260,7 @@ async def test_AT_cmd(ConfigTsunAllowAll, DeviceIndMsg, DeviceRspMsg, InverterIn
|
||||
assert m._send_buffer==b''
|
||||
assert m._forward_buffer==b''
|
||||
assert str(m.seq) == '02:04'
|
||||
|
||||
assert m.forward_at_cmd_resp == False
|
||||
m.close()
|
||||
|
||||
def test_at_command_ind(ConfigTsunInv1, AtCommandIndMsg):
|
||||
@@ -1172,25 +1288,93 @@ def test_at_command_ind(ConfigTsunInv1, AtCommandIndMsg):
|
||||
assert m.forward_modbus_resp == False
|
||||
m.close()
|
||||
|
||||
def test_msg_at_command_rsp1(ConfigTsunInv1, AtCommandRspMsg):
|
||||
ConfigTsunInv1
|
||||
m = MemoryStream(AtCommandRspMsg)
|
||||
m.db.stat['proxy']['Unknown_Ctrl'] = 0
|
||||
m.db.stat['proxy']['Modbus_Command'] = 0
|
||||
m.forward_at_cmd_resp = True
|
||||
m.read() # read complete msg, and dispatch msg
|
||||
assert not m.header_valid # must be invalid, since msg was handled and buffer flushed
|
||||
assert m.msg_count == 1
|
||||
assert m.control == 0x1510
|
||||
assert str(m.seq) == '03:03'
|
||||
assert m.header_len==11
|
||||
assert m.data_len==10
|
||||
assert m._forward_buffer==AtCommandRspMsg
|
||||
assert m._send_buffer==b''
|
||||
assert m.db.stat['proxy']['Unknown_Ctrl'] == 0
|
||||
assert m.db.stat['proxy']['Modbus_Command'] == 0
|
||||
m.close()
|
||||
|
||||
def test_msg_at_command_rsp2(ConfigTsunInv1, AtCommandRspMsg):
|
||||
ConfigTsunInv1
|
||||
m = MemoryStream(AtCommandRspMsg)
|
||||
m.db.stat['proxy']['Unknown_Ctrl'] = 0
|
||||
m.db.stat['proxy']['Modbus_Command'] = 0
|
||||
m.forward_at_cmd_resp = False
|
||||
m.read() # read complete msg, and dispatch msg
|
||||
assert not m.header_valid # must be invalid, since msg was handled and buffer flushed
|
||||
assert m.msg_count == 1
|
||||
assert m.control == 0x1510
|
||||
assert str(m.seq) == '03:03'
|
||||
assert m.header_len==11
|
||||
assert m.data_len==10
|
||||
assert m._forward_buffer==b''
|
||||
assert m._send_buffer==b''
|
||||
assert m.db.stat['proxy']['Unknown_Ctrl'] == 0
|
||||
assert m.db.stat['proxy']['Modbus_Command'] == 0
|
||||
m.close()
|
||||
|
||||
def test_msg_modbus_req(ConfigTsunInv1, MsgModbusCmd):
|
||||
ConfigTsunInv1
|
||||
m = MemoryStream(MsgModbusCmd, (0,), False)
|
||||
m = MemoryStream(b'')
|
||||
c = m.createClientStream(MsgModbusCmd)
|
||||
|
||||
m.forward_modbus_resp = False
|
||||
m.db.stat['proxy']['Unknown_Ctrl'] = 0
|
||||
m.db.stat['proxy']['AT_Command'] = 0
|
||||
m.db.stat['proxy']['Modbus_Command'] = 0
|
||||
m.read() # read complete msg, and dispatch msg
|
||||
assert not m.header_valid # must be invalid, since msg was handled and buffer flushed
|
||||
assert m.msg_count == 1
|
||||
assert m.control == 0x4510
|
||||
assert str(m.seq) == '03:02'
|
||||
assert m.header_len==11
|
||||
assert m.data_len==23
|
||||
assert m._forward_buffer==MsgModbusCmd
|
||||
assert m._send_buffer==b''
|
||||
m.db.stat['proxy']['Invalid_Msg_Format'] = 0
|
||||
c.read() # read complete msg, and dispatch msg
|
||||
assert not c.header_valid # must be invalid, since msg was handled and buffer flushed
|
||||
assert c.msg_count == 1
|
||||
assert c.control == 0x4510
|
||||
assert str(c.seq) == '03:02'
|
||||
assert c.header_len==11
|
||||
assert c.data_len==23
|
||||
assert c._forward_buffer==MsgModbusCmd
|
||||
assert c._send_buffer==b''
|
||||
assert m.db.stat['proxy']['Unknown_Ctrl'] == 0
|
||||
assert m.db.stat['proxy']['AT_Command'] == 0
|
||||
assert m.db.stat['proxy']['Modbus_Command'] == 1
|
||||
assert m.db.stat['proxy']['Invalid_Msg_Format'] == 0
|
||||
assert m.forward_modbus_resp == True
|
||||
m.close()
|
||||
|
||||
def test_msg_modbus_req2(ConfigTsunInv1, MsgModbusCmdCrcErr):
|
||||
ConfigTsunInv1
|
||||
m = MemoryStream(b'')
|
||||
c = m.createClientStream(MsgModbusCmdCrcErr)
|
||||
|
||||
m.forward_modbus_resp = False
|
||||
m.db.stat['proxy']['Unknown_Ctrl'] = 0
|
||||
m.db.stat['proxy']['AT_Command'] = 0
|
||||
m.db.stat['proxy']['Modbus_Command'] = 0
|
||||
m.db.stat['proxy']['Invalid_Msg_Format'] = 0
|
||||
c.read() # read complete msg, and dispatch msg
|
||||
assert not c.header_valid # must be invalid, since msg was handled and buffer flushed
|
||||
assert c.msg_count == 1
|
||||
assert c.control == 0x4510
|
||||
assert str(c.seq) == '03:02'
|
||||
assert c.header_len==11
|
||||
assert c.data_len==23
|
||||
assert c._forward_buffer==MsgModbusCmdCrcErr
|
||||
assert c._send_buffer==b''
|
||||
assert m.db.stat['proxy']['Unknown_Ctrl'] == 0
|
||||
assert m.db.stat['proxy']['AT_Command'] == 0
|
||||
assert m.db.stat['proxy']['Modbus_Command'] == 0
|
||||
assert m.db.stat['proxy']['Invalid_Msg_Format'] == 1
|
||||
assert m.forward_modbus_resp == True
|
||||
m.close()
|
||||
|
||||
@@ -1201,6 +1385,7 @@ def test_msg_unknown_cmd_req(ConfigTsunInv1, MsgUnknownCmd):
|
||||
m.db.stat['proxy']['Unknown_Ctrl'] = 0
|
||||
m.db.stat['proxy']['AT_Command'] = 0
|
||||
m.db.stat['proxy']['Modbus_Command'] = 0
|
||||
m.db.stat['proxy']['Invalid_Msg_Format'] = 0
|
||||
m.read() # read complete msg, and dispatch msg
|
||||
assert not m.header_valid # must be invalid, since msg was handled and buffer flushed
|
||||
assert m.msg_count == 1
|
||||
@@ -1213,12 +1398,13 @@ def test_msg_unknown_cmd_req(ConfigTsunInv1, MsgUnknownCmd):
|
||||
assert m.db.stat['proxy']['Unknown_Ctrl'] == 0
|
||||
assert m.db.stat['proxy']['AT_Command'] == 0
|
||||
assert m.db.stat['proxy']['Modbus_Command'] == 0
|
||||
assert m.db.stat['proxy']['Invalid_Msg_Format'] == 0
|
||||
assert m.forward_modbus_resp == False
|
||||
m.close()
|
||||
|
||||
def test_msg_modbus_rsp1(ConfigTsunInv1, MsgModbusRsp):
|
||||
ConfigTsunInv1
|
||||
m = MemoryStream(MsgModbusRsp, (0,), False)
|
||||
m = MemoryStream(MsgModbusRsp)
|
||||
m.db.stat['proxy']['Unknown_Ctrl'] = 0
|
||||
m.db.stat['proxy']['Modbus_Command'] = 0
|
||||
m.forward_modbus_resp = False
|
||||
@@ -1237,7 +1423,7 @@ def test_msg_modbus_rsp1(ConfigTsunInv1, MsgModbusRsp):
|
||||
|
||||
def test_msg_modbus_rsp2(ConfigTsunInv1, MsgModbusRsp):
|
||||
ConfigTsunInv1
|
||||
m = MemoryStream(MsgModbusRsp, (0,), False)
|
||||
m = MemoryStream(MsgModbusRsp)
|
||||
m.db.stat['proxy']['Unknown_Ctrl'] = 0
|
||||
m.db.stat['proxy']['Modbus_Command'] = 0
|
||||
m.forward_modbus_resp = True
|
||||
@@ -1256,7 +1442,7 @@ def test_msg_modbus_rsp2(ConfigTsunInv1, MsgModbusRsp):
|
||||
|
||||
def test_msg_modbus_rsp3(ConfigTsunInv1, MsgModbusRsp):
|
||||
ConfigTsunInv1
|
||||
m = MemoryStream(MsgModbusRsp, (0,), False)
|
||||
m = MemoryStream(MsgModbusRsp)
|
||||
m.append_msg(MsgModbusRsp)
|
||||
|
||||
m.forward_modbus_resp = True
|
||||
@@ -1289,6 +1475,25 @@ def test_msg_modbus_rsp3(ConfigTsunInv1, MsgModbusRsp):
|
||||
|
||||
m.close()
|
||||
|
||||
def test_msg_unknown_rsp(ConfigTsunInv1, MsgUnknownCmdRsp):
|
||||
ConfigTsunInv1
|
||||
m = MemoryStream(MsgUnknownCmdRsp)
|
||||
m.db.stat['proxy']['Unknown_Ctrl'] = 0
|
||||
m.db.stat['proxy']['Modbus_Command'] = 0
|
||||
m.forward_modbus_resp = True
|
||||
m.read() # read complete msg, and dispatch msg
|
||||
assert not m.header_valid # must be invalid, since msg was handled and buffer flushed
|
||||
assert m.msg_count == 1
|
||||
assert m.control == 0x1510
|
||||
assert str(m.seq) == '03:03'
|
||||
assert m.header_len==11
|
||||
assert m.data_len==59
|
||||
assert m._forward_buffer==MsgUnknownCmdRsp
|
||||
assert m._send_buffer==b''
|
||||
assert m.db.stat['proxy']['Unknown_Ctrl'] == 0
|
||||
assert m.db.stat['proxy']['Modbus_Command'] == 0
|
||||
m.close()
|
||||
|
||||
def test_msg_modbus_invalid(ConfigTsunInv1, MsgModbusInvalid):
|
||||
ConfigTsunInv1
|
||||
m = MemoryStream(MsgModbusInvalid, (0,), False)
|
||||
|
||||
@@ -51,6 +51,12 @@ class MemoryStream(Talent):
|
||||
def _timestamp(self):
|
||||
return 1700260990000
|
||||
|
||||
def createClientStream(self, msg, chunks = (0,)):
|
||||
c = MemoryStream(msg, chunks, False)
|
||||
self.remoteStream = c
|
||||
c. remoteStream = self
|
||||
return c
|
||||
|
||||
def _Talent__flush_recv_msg(self) -> None:
|
||||
super()._Talent__flush_recv_msg()
|
||||
self.msg_count += 1
|
||||
@@ -188,6 +194,13 @@ def MsgModbusCmd():
|
||||
msg += b'\x00\x00\x03\xc8'
|
||||
return msg
|
||||
|
||||
@pytest.fixture
|
||||
def MsgModbusCmdCrcErr():
|
||||
msg = b'\x00\x00\x00\x20\x10R170000000000001'
|
||||
msg += b'\x70\x77\x00\x01\xa3\x28\x08\x01\x06\x20\x08'
|
||||
msg += b'\x00\x00\x04\xc8'
|
||||
return msg
|
||||
|
||||
@pytest.fixture
|
||||
def MsgModbusRsp():
|
||||
msg = b'\x00\x00\x00\x20\x10R170000000000001'
|
||||
@@ -789,27 +802,55 @@ def test_proxy_counter():
|
||||
|
||||
def test_msg_modbus_req(ConfigTsunInv1, MsgModbusCmd):
|
||||
ConfigTsunInv1
|
||||
m = MemoryStream(MsgModbusCmd, (0,), False)
|
||||
m = MemoryStream(b'')
|
||||
c = m.createClientStream(MsgModbusCmd)
|
||||
|
||||
m.db.stat['proxy']['Unknown_Ctrl'] = 0
|
||||
m.db.stat['proxy']['Modbus_Command'] = 0
|
||||
m.read() # read complete msg, and dispatch msg
|
||||
assert not m.header_valid # must be invalid, since msg was handled and buffer flushed
|
||||
assert m.msg_count == 1
|
||||
assert m.id_str == b"R170000000000001"
|
||||
assert m.unique_id == 'R170000000000001'
|
||||
assert int(m.ctrl)==112
|
||||
assert m.msg_id==119
|
||||
assert m.header_len==23
|
||||
assert m.data_len==13
|
||||
assert m._forward_buffer==MsgModbusCmd
|
||||
assert m._send_buffer==b''
|
||||
m.db.stat['proxy']['Invalid_Msg_Format'] = 0
|
||||
c.read() # read complete msg, and dispatch msg
|
||||
assert not c.header_valid # must be invalid, since msg was handled and buffer flushed
|
||||
assert c.msg_count == 1
|
||||
assert c.id_str == b"R170000000000001"
|
||||
assert c.unique_id == 'R170000000000001'
|
||||
assert int(c.ctrl)==112
|
||||
assert c.msg_id==119
|
||||
assert c.header_len==23
|
||||
assert c.data_len==13
|
||||
assert c._forward_buffer==MsgModbusCmd
|
||||
assert c._send_buffer==b''
|
||||
assert m.db.stat['proxy']['Unknown_Ctrl'] == 0
|
||||
assert m.db.stat['proxy']['Modbus_Command'] == 1
|
||||
assert m.db.stat['proxy']['Invalid_Msg_Format'] == 0
|
||||
m.close()
|
||||
|
||||
def test_msg_modbus_req2(ConfigTsunInv1, MsgModbusCmdCrcErr):
|
||||
ConfigTsunInv1
|
||||
m = MemoryStream(b'')
|
||||
c = m.createClientStream(MsgModbusCmdCrcErr)
|
||||
|
||||
m.db.stat['proxy']['Unknown_Ctrl'] = 0
|
||||
m.db.stat['proxy']['Modbus_Command'] = 0
|
||||
m.db.stat['proxy']['Invalid_Msg_Format'] = 0
|
||||
c.read() # read complete msg, and dispatch msg
|
||||
assert not c.header_valid # must be invalid, since msg was handled and buffer flushed
|
||||
assert c.msg_count == 1
|
||||
assert c.id_str == b"R170000000000001"
|
||||
assert c.unique_id == 'R170000000000001'
|
||||
assert int(c.ctrl)==112
|
||||
assert c.msg_id==119
|
||||
assert c.header_len==23
|
||||
assert c.data_len==13
|
||||
assert c._forward_buffer==MsgModbusCmdCrcErr
|
||||
assert c._send_buffer==b''
|
||||
assert m.db.stat['proxy']['Unknown_Ctrl'] == 0
|
||||
assert m.db.stat['proxy']['Modbus_Command'] == 0
|
||||
assert m.db.stat['proxy']['Invalid_Msg_Format'] == 1
|
||||
m.close()
|
||||
|
||||
def test_msg_modbus_rsp1(ConfigTsunInv1, MsgModbusRsp):
|
||||
ConfigTsunInv1
|
||||
m = MemoryStream(MsgModbusRsp, (0,), False)
|
||||
m = MemoryStream(MsgModbusRsp)
|
||||
m.db.stat['proxy']['Unknown_Ctrl'] = 0
|
||||
m.db.stat['proxy']['Modbus_Command'] = 0
|
||||
m.forward_modbus_resp = False
|
||||
@@ -830,7 +871,7 @@ def test_msg_modbus_rsp1(ConfigTsunInv1, MsgModbusRsp):
|
||||
|
||||
def test_msg_modbus_rsp2(ConfigTsunInv1, MsgModbusRsp):
|
||||
ConfigTsunInv1
|
||||
m = MemoryStream(MsgModbusRsp, (0,), False)
|
||||
m = MemoryStream(MsgModbusRsp)
|
||||
m.db.stat['proxy']['Unknown_Ctrl'] = 0
|
||||
m.db.stat['proxy']['Modbus_Command'] = 0
|
||||
m.forward_modbus_resp = True
|
||||
@@ -851,7 +892,7 @@ def test_msg_modbus_rsp2(ConfigTsunInv1, MsgModbusRsp):
|
||||
|
||||
def test_msg_modbus_rsp3(ConfigTsunInv1, MsgModbusResp20):
|
||||
ConfigTsunInv1
|
||||
m = MemoryStream(MsgModbusResp20, (0,), False)
|
||||
m = MemoryStream(MsgModbusResp20)
|
||||
m.append_msg(MsgModbusResp20)
|
||||
|
||||
m.forward_modbus_resp = True
|
||||
|
||||
Reference in New Issue
Block a user