Closed shaileshsathe closed 5 years ago
Hi, Any update about this issue ?
There is a test for this that uses a TCP connection which is working fine so it suggests it is an issue with the serial comms. I will add a serial test tonight and see if I can replicate it
Thanks Steve for looking into it.
Even I am using the WriteMultipleRegistersRequest and WriteMultipleRegistersResponse to write Holding Register with both TCP as well as RTU and it absolutely works fine. But when I am trying to request Preset Multiple Register. It says Illegal Data Value.
I could see the requested Hex Message through j2mod looks like "03 10 01 CA 00 06 0C 00 14 00 28 00 01 00 04 00 03 00 13"
and using third party tool where I manually enter each HEX, the request looks like "03 10 01 CC 00 14 28 01 04 03 13 6B B2"
I don't get where this 00 06 0C gets appended after Starting Address 01 CA. (Note :Here I have to used 01 CA =>(458) instead of 01 CC =>(460) since using J2Mod I have to lower the Starting address by 1 as per my experience. In this case 2 because 2 registers makes 1 value in this case). Also before each HEX 00 is getting prepended in the J2MOD request which I made as bold . Let me know If I do need to change my request using J2MOD.
Hi , Any update about this issue ? I have been stuck here since long. Please help me to move ahead with this.
Apologies for the delay.
I've just taken another look at this and can see that there are in fact unit tests for this and they are working fine. The unit test is testWriteMultipleRegisters()
Preset Multiple Registers (FC16) is WriteMultipleRegistersRequest
in j2mod which you say is working fine so I'm not sure what methods you are using.
The request message formed by j2mod follows the format as defined here; http://www.simplymodbus.ca/FC16.htm
03 10 01 CA 00 06 0C 00 14 00 28 00 01 00 04 00 03 00 13
03
The Slave Address
10
The Function Code 16 (Preset Multiple Registers, 10 hex - 16 )
01CA
The Data Address of the first register (0001 hex = 1 , + 40001 offset = register #40002)
0006
The number of registers to write
0C
The number of data bytes to follow (6 registers x 2 bytes each = 12 bytes)
0014
The value to write to register 40459
0028
The value to write to register 40460
0001
The value to write to register 40461
0004
The value to write to register 40462
0003
The value to write to register 40463
0013
The value to write to register 40464
The exception you are getting indicates that the slave doesn't like your request i.e. you are trying to write to registers that cannot take those values - see http://www.simplymodbus.ca/exceptions.htm response code 03
Thanks for the answer Steve. Agreed that register cannot accept those values but how its accepting the values from third party tool "DockLight" and giving the response. Below is my code using J2MOD.
import com.ghgande.j2mod.modbus.ModbusException;
import com.ghgande.j2mod.modbus.io.ModbusSerialTransaction;
import com.ghgande.j2mod.modbus.msg.ModbusRequest;
import com.ghgande.j2mod.modbus.msg.ReadMultipleRegistersRequest;
import com.ghgande.j2mod.modbus.msg.ReadMultipleRegistersResponse;
import com.ghgande.j2mod.modbus.msg.WriteMultipleRegistersRequest;
import com.ghgande.j2mod.modbus.msg.WriteMultipleRegistersResponse;
import com.ghgande.j2mod.modbus.net.SerialConnection;
import com.ghgande.j2mod.modbus.procimg.Register;
import com.ghgande.j2mod.modbus.procimg.SimpleInputRegister;
import com.ghgande.j2mod.modbus.util.SerialParameters;
import java.util.logging.Level;
import java.util.logging.Logger;
public class ReadWritePresetRegisterTest {
public static void main(String args[]){
SerialConnection serialConnection = null;
WriteMultipleRegistersRequest writeMultipleRegistersRequest = null;
WriteMultipleRegistersResponse writeMultipleRegistersResponse = null;
SerialParameters params = new SerialParameters();
params.setPortName("COM5");
params.setBaudRate("9600");
params.setParity("None");
params.setDatabits("8");
params.setStopbits("1");
params.setEncoding("rtu");
params.setEcho(false);
serialConnection = new SerialConnection(params);
serialConnection.setTimeout(500);
try {
serialConnection.open();
//Query according to Meter Manual
writeMultipleRegistersRequest = new WriteMultipleRegistersRequest(460, new Register[]{
new SimpleInputRegister(20), //No of Registers to be accessed
new SimpleInputRegister(40), //Log Download Bytes
new SimpleInputRegister(1),//Parameter No
new SimpleInputRegister(4),//Date
new SimpleInputRegister(3),//Month
new SimpleInputRegister(19)//Year
});
writeMultipleRegistersRequest.setUnitID(3);
writeMultipleRegistersRequest.setHeadless();
System.out.println("Request Hex >> " + writeMultipleRegistersRequest.getHexMessage());
writeMultipleRegistersResponse = writeMultipleRegistersResponse(serialConnection,
writeMultipleRegistersRequest);
System.out.println("Response Hex >> " + writeMultipleRegistersResponse.getHexMessage());
} catch (ModbusException ex) {
Logger.getLogger(ReadWritePresetRegisterTest.class.getName()).log(Level.SEVERE, null, ex);
} catch (Exception ex) {
Logger.getLogger(ReadWritePresetRegisterTest.class.getName()).log(Level.SEVERE, null, ex);
}
}
private static WriteMultipleRegistersResponse writeMultipleRegistersResponse(SerialConnection
serialConnection, ModbusRequest modbusRequest) throws ModbusException {
ModbusSerialTransaction modbusSerialTransaction = new
ModbusSerialTransaction(serialConnection);
modbusSerialTransaction.setRequest(modbusRequest);
modbusSerialTransaction.setTransDelayMS(10);
modbusSerialTransaction.execute();
if (modbusSerialTransaction.getResponse() instanceof WriteMultipleRegistersResponse) {
return (WriteMultipleRegistersResponse) modbusSerialTransaction.getResponse();
}
return null;
}
}
Hope I am using it in correct way. Let me know if I am missing something here. I used the same code earlier to write Holding Registers (FC:03) and values written successfully but when I use it for Preset Multiple Register (FC:16). It gives the error "Illegal Data Value". Any help would be really appreciated .
Below is the screenshot of Docklight tool with Request and Response.
Your FC16 message to your slave device is incorrect - the reference I sent you is a depiction of the actual standard http://www.modbus.org/docs/Modbus_Application_Protocol_V1_1b3.pdf page 30. Can you tell me the name, model and manufacturer of the slave device and perhaps I can figure it out.
Yes Steve.Please find attached Interface Definition of the product.You can check the page 53-54 and 56-57 for the queries I am working on.
LM_13xx_Interface_Definition.pdf
And one more question, I am trying the query on Page No. 56 according to j2mod code as follows. If it's not correct then please let me know what is the correct format to send this query using J2Mod. (Only Date,Month and Year is changed here)
//Query according to Meter Manual
WriteMultipleRegistersRequest writeMultipleRegistersRequest = new WriteMultipleRegistersRequest(460, new Register[]{
new SimpleInputRegister(20), //No of Registers to be accessed
new SimpleInputRegister(40), //Log Download Bytes
new SimpleInputRegister(1),//Parameter No
new SimpleInputRegister(4),//Date
new SimpleInputRegister(3),//Month
new SimpleInputRegister(19)//Year
});
Thanks in advance.
I've checked the specification of the meter and it states that FC16 messages must be sent as per my previous explanation. Take a look at page 21.
I have no idea why your hand-cranked queries are working, because they shouldn't be, according to the meter spec.
Page 5 also states that you will get an Illegal DataValue response if your floating point value isn't valid when writing. Perhaps that is your root cause.
Yes. You are correct. But if you refer further this document till page no. 56, the meter offers the read multiple registers (Load Profile datalog) functionality using the same function code (FC16).
Here we are facing problem. As I reported my observation 12 days ago about additional bytes found in request(Query) stream I am trying to send to meter.
03 10 01 CA 00 06 0C 00 14 00 28 00 01 00 04 00 03 00 13 *bold bytes are getting added automatically.
I guess due to this extra bytes meter is not responding properly. Even I would like to know how to print received bytes in response from meter
My confidence is that as Docklight utility can send same query and get desired response from meter, My logic using J2MOD lib should also give the same response.
Please refer the below query I am sending to meter using J2MOD lib.
//Query according to Meter Manual
WriteMultipleRegistersRequest writeMultipleRegistersRequest = new WriteMultipleRegistersRequest(460, new Register[]{
new SimpleInputRegister(20), //No of Registers to be accessed =>20 Registers
new SimpleInputRegister(40), //Log Download Bytes =>40 Bytes
new SimpleInputRegister(1), //Parameter No =>1
new SimpleInputRegister(4), //Date =>4
new SimpleInputRegister(3), //Month =>3
new SimpleInputRegister(19) //Year =>19
});
Here we are accessing 20 Registers to read not writing 6 Parameters according to Page No.56 of Meter Spec.
Please correct me if I am doing anything wrong here.
Please advise on this.
Looking forward for your usual prompt reply with guidelines.
Apologies. Mistakenly closed the issue.
Ok, I see what you're doing wrong. You are supplying the number of registers as a register value, similarly the number of bytes in the message. These are part of the Modbus protocol, not something you can supply yourself, they are calculated by j2mod based on the number of registers you are writing. Try this;
WriteMultipleRegistersRequest writeMultipleRegistersRequest = new
WriteMultipleRegistersRequest(460, new Register[]{
new SimpleInputRegister(1), //Parameter No =>1
new SimpleInputRegister(4), //Date =>4
new SimpleInputRegister(3), //Month =>3
new SimpleInputRegister(19) //Year =>19
});
If that doesn't work, try padding out the registers;
WriteMultipleRegistersRequest writeMultipleRegistersRequest = new
WriteMultipleRegistersRequest(460, new Register[]{
new SimpleInputRegister(1), //Parameter No =>1
new SimpleInputRegister(4), //Date =>4
new SimpleInputRegister(3), //Month =>3
new SimpleInputRegister(19), //Year =>19
new SimpleInputRegister(0),
new SimpleInputRegister(0),
new SimpleInputRegister(0),
new SimpleInputRegister(0),
new SimpleInputRegister(0),
new SimpleInputRegister(0)
});
BTW - Page 56 is telling you exactly the same thing as page 21. It is describing the FC16 Modbus protocol message :)
Thanks for the prompt response. Tried the way you mentioned, but still output is same "Illegal Data Value". Even I have a doubt about your reply. Here in my test query as per meter document, I need to read 20 Registers (0014) for Daily Energy (01CC in Table 17) category and Capacitive VAr energy (03 in Table 18) sub-category from date of 04/11/2017 date (040B11).
Here all these inputs are user inputs and defined at the time of query. So I guess these should be varying for each query. Where as you are suggesting to just supply Parameter No. and Date as input and J2MOD lib will do rest for me. How J2MOD can understand and take my categories, sub-categories, no. of registers and start date inputs required for query to meter for my desired expected output ? Please clarify and suggest. Your usual prompt reply is expected.
j2mod is following the Modbus specification exactly so this isn't a j2mod problem. FC16 is a "Write Multiple Registers" so the number of registers and bytes in the protocol message is the number of registers/bytes you are sending, not expecting in the reply. Please read the Modbus specifications that I have sent you links for. A basic understanding of the protocol will at least help you see what the meter is doing.
Have you tried using other Modbus tools like modpoll? I can't believe they will work either but at least you will validate what you are doing.
I don't have anything else to suggest other than you contact the meter manufacturer.
I have tried with modpoll and mbpoll but it opens those 20 registers values to enter that will be written. So as per my knowledge it must be a customized request and response given on page no 56 which is not according to the Modbus standard. So I will close this issue. Thanks a lot for your time, effort and valuable guidance.
I am using WriteMultipleRegistersRequest and WriteMultipleRegistersResponse class to read the Preset Multiple Registers. Is that correct function code classes am I using ? Because I am getting output as "Illegal Data Value". Can you provide any test class for the same ?
When used third party tool for same query by typing HEX for each Register and sending the query getting expected response. Is anything I am missing ? Any help will be appreciated. Query fired using the tool was 03 10 CC 00 14 28 01 04 03 13 6B B2