forked from espressif/esp-modbus
update test
This commit is contained in:
@@ -11,6 +11,7 @@ target_include_directories(mb_ut_lib PUBLIC
|
|||||||
"${dir}/modbus/mb_controller/common/include"
|
"${dir}/modbus/mb_controller/common/include"
|
||||||
"${dir}/modbus/mb_controller/serial"
|
"${dir}/modbus/mb_controller/serial"
|
||||||
"${dir}/modbus/mb_controller/tcp"
|
"${dir}/modbus/mb_controller/tcp"
|
||||||
|
"${dir}/modbus/mb_objects/common"
|
||||||
"${dir}/modbus/mb_objects/include"
|
"${dir}/modbus/mb_objects/include"
|
||||||
"${dir}/modbus/mb_ports/common"
|
"${dir}/modbus/mb_ports/common"
|
||||||
"${dir}/modbus/mb_ports/serial"
|
"${dir}/modbus/mb_ports/serial"
|
||||||
|
@@ -36,8 +36,8 @@ class ModbusMBAP(Packet):
|
|||||||
name = "Modbus TCP"
|
name = "Modbus TCP"
|
||||||
fields_desc = [ ShortField("transId", 0),
|
fields_desc = [ ShortField("transId", 0),
|
||||||
ShortField("protoId", 0),
|
ShortField("protoId", 0),
|
||||||
ShortField("len", 6),
|
ShortField("len", 0),
|
||||||
XByteField("UnitId", 247),
|
XByteField("unitId", 0),
|
||||||
]
|
]
|
||||||
|
|
||||||
# Can be used to replace all Modbus read
|
# Can be used to replace all Modbus read
|
||||||
@@ -252,10 +252,27 @@ class ModbusPDUXX_Custom_Request(Packet):
|
|||||||
FieldListField("customBytes", [0x00], XByteField("", 0x00))
|
FieldListField("customBytes", [0x00], XByteField("", 0x00))
|
||||||
]
|
]
|
||||||
|
|
||||||
|
class ModbusPDUXX_Custom_Exception(Packet):
|
||||||
|
name = "Custom Command Exception"
|
||||||
|
fields_desc = [
|
||||||
|
XByteField("funcCode", 0x00),
|
||||||
|
ByteEnumField("exceptCode", 1, modbus_exceptions)
|
||||||
|
]
|
||||||
|
|
||||||
|
# Custom command respond
|
||||||
|
class ModbusPDUXX_Custom_Answer(Packet):
|
||||||
|
name = "Custom Command Answer"
|
||||||
|
fields_desc = [
|
||||||
|
ConditionalField(XByteField("funcCode", 0x00), lambda pkt: (type(pkt.underlayer) is ModbusADU_Response)),
|
||||||
|
ConditionalField(FieldListField("customBytes", [0x00], XByteField("", 0x00), count_from = lambda pkt: pkt.underlayer.len if pkt.underlayer is not None else 0), lambda pkt: type(pkt.underlayer) is ModbusADU_Response)
|
||||||
|
]
|
||||||
|
|
||||||
# 0x11 - Report Slave Id
|
# 0x11 - Report Slave Id
|
||||||
class ModbusPDU11_Report_Slave_Id(Packet):
|
class ModbusPDU11_Report_Slave_Id(Packet):
|
||||||
name = "Report Slave Id"
|
name = "Report Slave Id"
|
||||||
fields_desc = [ XByteField("funcCode", 0x11) ]
|
fields_desc = [
|
||||||
|
XByteField("funcCode", 0x11)
|
||||||
|
]
|
||||||
|
|
||||||
class ModbusPDU11_Report_Slave_Id_Answer(Packet):
|
class ModbusPDU11_Report_Slave_Id_Answer(Packet):
|
||||||
name = "Report Slave Id Answer"
|
name = "Report Slave Id Answer"
|
||||||
@@ -279,7 +296,8 @@ class ModbusADU_Request(ModbusMBAP):
|
|||||||
XShortField("transId", 0x0000), # needs to be unique
|
XShortField("transId", 0x0000), # needs to be unique
|
||||||
XShortField("protoId", 0x0000), # needs to be zero (Modbus)
|
XShortField("protoId", 0x0000), # needs to be zero (Modbus)
|
||||||
XShortField("len", None), # is calculated with payload
|
XShortField("len", None), # is calculated with payload
|
||||||
XByteField("unitId", 0x00)] # 0xFF or 0x00 should be used for Modbus over TCP/IP
|
XByteField("unitId", 0x00) # 0xFF or 0x00 should be used for Modbus over TCP/IP
|
||||||
|
]
|
||||||
|
|
||||||
def mb_get_last_exception(self):
|
def mb_get_last_exception(self):
|
||||||
return _mb_exception
|
return _mb_exception
|
||||||
@@ -372,7 +390,8 @@ class ModbusADU_Request(ModbusMBAP):
|
|||||||
class ModbusADU_Response(ModbusMBAP):
|
class ModbusADU_Response(ModbusMBAP):
|
||||||
name = "ModbusADU Response"
|
name = "ModbusADU Response"
|
||||||
_mb_exception: modbus_exceptions = 0
|
_mb_exception: modbus_exceptions = 0
|
||||||
|
_current_main_packet: Packet = None
|
||||||
|
_modbus_pdu: Packet = None
|
||||||
fields_desc = [
|
fields_desc = [
|
||||||
XShortField("transId", 0x0000), # needs to be unique
|
XShortField("transId", 0x0000), # needs to be unique
|
||||||
XShortField("protoId", 0x0000), # needs to be zero (Modbus)
|
XShortField("protoId", 0x0000), # needs to be zero (Modbus)
|
||||||
@@ -381,6 +400,15 @@ class ModbusADU_Response(ModbusMBAP):
|
|||||||
|
|
||||||
def mb_get_last_exception(self):
|
def mb_get_last_exception(self):
|
||||||
return _mb_exception
|
return _mb_exception
|
||||||
|
|
||||||
|
# def extract_padding(self, s):
|
||||||
|
# print(f'Extract pedding: {self, s, self.len, self.underlayer}')
|
||||||
|
# return self.guess_payload_class( s) #, s #self.extract_pedding(self, s)
|
||||||
|
|
||||||
|
def pre_dissect(self, s):
|
||||||
|
print(f'Pre desect: {self, s, self.len, self.underlayer}')
|
||||||
|
_current_main_packet = self
|
||||||
|
return s
|
||||||
|
|
||||||
# Dissects packets
|
# Dissects packets
|
||||||
def guess_payload_class(self, payload):
|
def guess_payload_class(self, payload):
|
||||||
@@ -443,11 +471,14 @@ class ModbusADU_Response(ModbusMBAP):
|
|||||||
return ModbusPDU10_Write_Multiple_Registers_Exception
|
return ModbusPDU10_Write_Multiple_Registers_Exception
|
||||||
|
|
||||||
elif funcCode == 0x11:
|
elif funcCode == 0x11:
|
||||||
print(f'Packet answer: {payload}, func: {funcCode}')
|
|
||||||
return ModbusPDU11_Report_Slave_Id_Answer
|
return ModbusPDU11_Report_Slave_Id_Answer
|
||||||
elif funcCode == 0x91:
|
elif funcCode == 0x91:
|
||||||
self._mb_exception = int(payload[1])
|
self._mb_exception = int(payload[1])
|
||||||
return ModbusPDU11_Report_Slave_Id_Exception
|
return ModbusPDU11_Report_Slave_Id_Exception
|
||||||
|
|
||||||
else:
|
else:
|
||||||
return Packet.guess_payload_class(self, payload)
|
if (funcCode & 0x80):
|
||||||
|
self._mb_exception = int(payload[1])
|
||||||
|
return ModbusPDUXX_Custom_Exception
|
||||||
|
return ModbusPDUXX_Custom_Answer
|
||||||
|
#return Packet.guess_payload_class(self, payload)
|
@@ -42,6 +42,8 @@ MB_LOGGING_PATH = '.'
|
|||||||
|
|
||||||
# The constructed packets for self testing
|
# The constructed packets for self testing
|
||||||
|
|
||||||
|
TEST_PACKET_REPORT_CUSTOM_0X41 = 'ModbusADU_Request(transId=MB_DEF_TRANS_ID, unitId=0x01, protoId=0)/\
|
||||||
|
ModbusPDUXX_Custom_Request(customBytes=[0x41])'
|
||||||
TEST_PACKET_REPORT_SLAVE_ID_CUSTOM = 'ModbusADU_Request(transId=MB_DEF_TRANS_ID, unitId=0x01, protoId=0)/\
|
TEST_PACKET_REPORT_SLAVE_ID_CUSTOM = 'ModbusADU_Request(transId=MB_DEF_TRANS_ID, unitId=0x01, protoId=0)/\
|
||||||
ModbusPDUXX_Custom_Request(customBytes=[0x11])'
|
ModbusPDUXX_Custom_Request(customBytes=[0x11])'
|
||||||
TEST_PACKET_REPORT_SLAVE_ID = 'ModbusADU_Request(transId=MB_DEF_TRANS_ID, unitId=0x01, protoId=0)/\
|
TEST_PACKET_REPORT_SLAVE_ID = 'ModbusADU_Request(transId=MB_DEF_TRANS_ID, unitId=0x01, protoId=0)/\
|
||||||
@@ -431,6 +433,15 @@ class ModbusTestLib:
|
|||||||
def self_test(self) -> None:
|
def self_test(self) -> None:
|
||||||
# type: () -> None
|
# type: () -> None
|
||||||
self.connect(ip_addr=MB_DEF_SERVER_IP, port=MB_DEF_PORT)
|
self.connect(ip_addr=MB_DEF_SERVER_IP, port=MB_DEF_PORT)
|
||||||
|
packet = self.create_request(TEST_PACKET_REPORT_CUSTOM_0X41)
|
||||||
|
print(f"Test: 0x41 <Custom command> packet: {packet}")
|
||||||
|
response = self.send_packet_and_get_response(packet, timeout=1, verbose=0)
|
||||||
|
assert response and len(response) > 1, "No response from slave"
|
||||||
|
print(f"Test: received: {bytes(response)}")
|
||||||
|
pdu = self.translate_response(response)
|
||||||
|
if pdu is not None:
|
||||||
|
print(f"Received: {pdu}")
|
||||||
|
#print(f"PDU Exception: {self.check_response(pdu, packet.customBytes[0])}")
|
||||||
packet = self.create_request(TEST_PACKET_REPORT_SLAVE_ID_CUSTOM)
|
packet = self.create_request(TEST_PACKET_REPORT_SLAVE_ID_CUSTOM)
|
||||||
print(f"Test: 0x11 <Report Slave ID> packet: {packet}")
|
print(f"Test: 0x11 <Report Slave ID> packet: {packet}")
|
||||||
response = self.send_packet_and_get_response(packet, timeout=1, verbose=0)
|
response = self.send_packet_and_get_response(packet, timeout=1, verbose=0)
|
||||||
|
@@ -18,6 +18,11 @@ Library Collections
|
|||||||
Library ModbusTestLib.py WITH NAME ModbusTestLib
|
Library ModbusTestLib.py WITH NAME ModbusTestLib
|
||||||
|
|
||||||
*** Keywords ***
|
*** Keywords ***
|
||||||
|
Create Custom Command Request
|
||||||
|
[Arguments] ${uid} ${customData}
|
||||||
|
${packet} = Create Request ModbusADU_Request(unitId=${uid}, protoId=0)/ModbusPDUXX_Custom_Request(customBytes=${customData})
|
||||||
|
RETURN ${packet}
|
||||||
|
|
||||||
Create Report Slave Id Request
|
Create Report Slave Id Request
|
||||||
[Arguments] ${uid} ${customData}
|
[Arguments] ${uid} ${customData}
|
||||||
#${packet} = Create Request ModbusADU_Request(unitId=${uid}, protoId=0)/ModbusPDU11_Report_Slave_Id(funcCode=${FUNC_REPORT_SLAVE_ID})
|
#${packet} = Create Request ModbusADU_Request(unitId=${uid}, protoId=0)/ModbusPDU11_Report_Slave_Id(funcCode=${FUNC_REPORT_SLAVE_ID})
|
||||||
@@ -64,6 +69,48 @@ Create Discrete Read Request
|
|||||||
Log Packet: ${packet}
|
Log Packet: ${packet}
|
||||||
RETURN ${packet}
|
RETURN ${packet}
|
||||||
|
|
||||||
|
Lists Should Be Equal
|
||||||
|
[Arguments] ${get_list} ${exp_list}
|
||||||
|
Should Not Be Empty ${get_list}
|
||||||
|
Should Not Be Empty ${exp_list}
|
||||||
|
${get_length} = Get length ${get_list}
|
||||||
|
${exp_length} = Get length ${exp_list}
|
||||||
|
Should Be Equal As Integers ${get_length} ${exp_length}
|
||||||
|
FOR ${i} IN RANGE ${exp_length}
|
||||||
|
${get_item} = Get From List ${get_list} ${i}
|
||||||
|
${exp_item} = Get From List ${exp_list} ${i}
|
||||||
|
Should Be Equal As Integers ${get_item} ${exp_item}
|
||||||
|
END
|
||||||
|
|
||||||
|
Custom Command
|
||||||
|
[Arguments] ${uid} ${customData} ${exception_expected} ${expected_list}
|
||||||
|
${classId} = Get Class Id
|
||||||
|
Log Library ClassId: ${classId}
|
||||||
|
Log Get Slave Identificator UID:${uid}, Custom bytes: ${customData}
|
||||||
|
${req} = Create Custom Command Request ${uid} ${customData}
|
||||||
|
#Create Connection ${server} ${port}
|
||||||
|
${response_frame} = Send Packet And Get Response ${req}
|
||||||
|
Should Not Be Empty ${response_frame}
|
||||||
|
${packet} = Translate Response ${response_frame}
|
||||||
|
Should Be Equal As Integers ${req.transId} ${packet.transId}
|
||||||
|
${exception} ${exp_message} = Check Response ${packet} ${req.customBytes[0]}
|
||||||
|
Should Be Equal As Integers ${exception} ${exception_expected}
|
||||||
|
Log exception: (${exception}: ${exp_message}), expected: ${exception_expected}
|
||||||
|
IF ${exception} == ${0}
|
||||||
|
Log SlaveUID:${uid}, Custom_data received:${packet.customBytes}
|
||||||
|
IF ${expected_list} != ${None}
|
||||||
|
Log ${expected_list}
|
||||||
|
Log ${packet.customBytes}
|
||||||
|
${get_list} = Convert To List ${packet.customBytes}
|
||||||
|
${exp_list} = Evaluate ${expected_list}
|
||||||
|
Lists Should Be Equal ${get_list} ${exp_list}
|
||||||
|
ELSE
|
||||||
|
Log "Skip comparison with expected list"
|
||||||
|
END
|
||||||
|
ELSE
|
||||||
|
Log "Exception is evaluated correctly (${exception}: ${exp_message}) == ${exception_expected}"
|
||||||
|
END
|
||||||
|
|
||||||
Report Slave Id
|
Report Slave Id
|
||||||
[Arguments] ${uid} ${customData} ${exception_expected}
|
[Arguments] ${uid} ${customData} ${exception_expected}
|
||||||
${classId} = Get Class Id
|
${classId} = Get Class Id
|
||||||
|
@@ -11,6 +11,13 @@ Suite Teardown Disconnect
|
|||||||
${suiteConnection} None
|
${suiteConnection} None
|
||||||
|
|
||||||
*** Test Cases ***
|
*** Test Cases ***
|
||||||
|
Test Cusom Command Request
|
||||||
|
[Documentation] Test reading slave UID, running status, identificator structure (use custom frame template)
|
||||||
|
[Template] Custom Command
|
||||||
|
0x01 [0x41] 0 ${None} # Try o send shortest request for custom command, do not check the buffer
|
||||||
|
0x01 [0x41, 0x11, 0x22, 0x33, 0x44] 0 ${None} # Send custom data, do not compare the response buffer
|
||||||
|
0x01 [0x41, 0x11, 0x22, 0x33] 0 [17, 34, 51, 0x3A, 83, 108, 97, 118, 101] # Send the custom command and compare expected response (can use hex or dec values)
|
||||||
|
|
||||||
Test Report Slave Id
|
Test Report Slave Id
|
||||||
[Documentation] Test reading slave UID, running status, identificator structure (use custom frame template)
|
[Documentation] Test reading slave UID, running status, identificator structure (use custom frame template)
|
||||||
[Template] Report Slave Id
|
[Template] Report Slave Id
|
||||||
|
Reference in New Issue
Block a user