Sigma South

Reading TCP Modbus using C# library

18 posts in this topic

I am willing to pay someone who is knowledgeable in this are to help me remotely solve this problem.  (TeamViewer)

I have a Profinet PLC with data as shown in the image below. I have a converter that translates the data into TCP/Modbus. I have tried reading the data using a few existing client applications as well as a C# library called EasyModbus that I have used on projects before. I am getting data back but I cannot make sense of it. I have only used TCP/Modbus with integers before so it was easy. I am looking for someone with extensive experience to assist. 

 

r/PLC - Reading TCP Modbus using C# library

 

Share this post


Link to post
Share on other sites

What data were you expecting?

Since you used the term Profinet, you'll probably need to do byte swapping.  In you TCP/Modbus converter, you should be able to select that option.

Share this post


Link to post
Share on other sites
37 minutes ago, pcmccartney1 said:

What data were you expecting?

Since you used the term Profinet, you'll probably need to do byte swapping.  In you TCP/Modbus converter, you should be able to select that option.

Notice the first three are not floats.  They are decimals.  I'm not even sure at what register I should start at in the ModBus holding registers.  Also, what method should I use?

http://easymodbustcp.net/en/modbusclient-methods

Share this post


Link to post
Share on other sites

Sorry, I can't help you...This is over my head.  I thought you were using a protocol converting device.  Instead you are attempting to write your own, I cant' help.

Share this post


Link to post
Share on other sites

 

what seem to be the problem? you already get the data so just need to rearrange it into something friendly so that it is displayed same was like on sender? 

as already mentioned, it may simply be matter of changing radix to see values in expected format or the issue is with byte swapping.

and this is expected since ... one of the nodes is Siemens...

the other possibility would be that data is encoded in some way such as Fixed point, BCD etc. or... there could be some other problem (data corruption due interference, or defective sender or receiver etc.)

but as mentioned, this is common thing with Siemens so .... if byte order is the problem - fix it by changing byte order. this is why preferred way to exchange data is in bytes (before conversion to something specific takes place). this can be done either at PLC end or on whatever is connected to it.:

your screenshots shows four addresses per variable so i am pretty sure that AD 1024 is a byte, so is AD 1025, and AD 1026 etc. 
each byte is 8-bit but DEC and FLOAT are 32-bit or 4 bytes. this explains why in your screenshot, only first of the four consecutive addresses is listed (AD 1024, 1028, 1032 etc.)

when ever dealing with data transfer always try to ensure if problem is with corruption or not. therefore compare sent and received value by looking at both in a hexadecimal format (or in binary if you really have to).

so take the received value, and make sire to display it in a hexadecimal format (use calculator).
then see what is the value on other end (at the PLC) and convert that value also into hexadecimal format  (use calculator).

then compare two hex values. each byte is 2-chars in the hexadecimal representation so 32bit value will be 8 characters long. note: same four bytes must exist at both sides, just the order may be different. so untangle them by changing byte order and - keep track of order change.

 


example, value 238.02 (real) is 436E051F in hex. (bytes 0x46, 0xE0, 0x05, 0x1F )

but the other side may need that order changed to display same "238.02"
maybe the correct order need to be 0xE0, 0x46, 0x1F, 0x05 or whatever.  

then after the byte order is untangled, read those 32-bits as a new value and you should get what you expected. that's  it.

 


i don't use c# very often but, it should be something like this:

start by converting real to byte[] 

    float vIn = 238.02f;
    byte[] vTemp1 = BitConverter.GetBytes(vIn);


then create another byte arrays and reshuffle values into desired order (say from 0-1-2-3 to 1-0-3-2):


    byte[] vTemp2 = new byte[] { 0, 0, 0,0 };
    vTemp2[0]=vTemp1[1];
    vTemp2[1]=vTemp1[0];
    vTemp2[2]=vTemp1[3];
    vTemp2[3]=vTemp1[2];

then convert the four byte array back into data type of your choice (perhaps back into float/real for example):

    float vOut = Convert.ToSingle(BitConverter.ToDouble(vTemp2, 0 /* Which byte position to convert */));

and you will get converted value such as 1.509677E+28
but same works in reverse too so if you are getting scrambled display like 1.509677E+28, or 2.825505E-20 or 7.488529E-36 etc. using described method you can get that changed back to correct representation: 238.02
 

 

1 person likes this

Share this post


Link to post
Share on other sites

iAdmin,

I tried your method like this:


           

            float vIn = 238.02f;
            byte[] vTemp1 = BitConverter.GetBytes(vIn);


            byte[] vTemp2 = new byte[] { 0, 0, 0, 0 };
            vTemp2[0] = vTemp1[1];
            vTemp2[1] = vTemp1[0];
            vTemp2[2] = vTemp1[3];
            vTemp2[3] = vTemp1[2];

            float vOut = Convert.ToSingle(BitConverter.ToDouble(vTemp2, 0 /* Which byte position to convert */));
            Console.WriteLine(vOut);
            Console.ReadKey();

And I get the following error: "Destination array is not long enough to copy all the items in the collection. Check array index and length".

Can you help?

Share this post


Link to post
Share on other sites

there was a mistake, one of methods is using Double.which is larger data type. size need to match so just change BitConverter.ToDouble method into BitConverter.ToSingle

 

byte shuffle.jpg

Share this post


Link to post
Share on other sites

Panic Mode,

Thank you.  I am so close now.  I notice in the OEM's chart above that the value for the first 3 registers are decimal and they display a value in the OEM's documentation with "L#".  Is "L#" not part of the actual value in your opinion?

Thanks

Share this post


Link to post
Share on other sites

I am also wondering how 1.50967693E+28f is the same thing as 238.02f.  What Am I missing?

Share this post


Link to post
Share on other sites

because it is not the same thing.... 
the content is the the same (in both cases four bytes are same values) 
but the composition is different (bytes are in different order)

different processors use different way to access and store data in the memory. Data is organized in bytes but order may be different (big endian vs. little endian). Intel and Motorola CPUs use different "endinanness" (byte order).

when one device (PLC using Motorola CPU) sends stream of data, it does so by sending bytes in what is natural order for it.
when another device (PC using Intel CPU) receives that stream of data, it receives them in order it was sent (FIFO). 
but since receiver works with the different architecture, received data appears scrambled. to fix the issue, one simply must rearrange what was received.

REAL and DINT are data structures that are composed of 4 bytes. if you change the order you get something that looks different.

here is an example of image transmitted in four pieces. you can choose different order result will only look the same if order is correctly changed back.

4-bytes.jpg

Share this post


Link to post
Share on other sites

Ahh.  Thank you so much.  Lol.  So, I tried converting and I am still struggling.  If you are open to working with me for 2 hours via Team Viewer I would be glad to pay you.  I really need to get this project closed and have been struggling for some time now.

 

708-556-2929

Share this post


Link to post
Share on other sites

sounds good but i am busy during regular hours, how about evening?

Share this post


Link to post
Share on other sites
9 hours ago, Sigma South said:

 I notice in the OEM's chart above that the value for the first 3 registers are decimal and they display a value in the OEM's documentation with "L#".  Is "L#" not part of the actual value in your opinion?
 

that is correct..., this is simply indication of the format  ("long number" or DINT)

the way format is represented also varies from platform to platform.
if you are writing down value to a piece of papere, you would probably write it as 283.02
if you try to represent the same value in C#, you would have to write 283.02f
notice "f" on the end, this tells that format is FLOAT or REAL data type, or... more specifically 
this is a SINGLE precision real number (32bit)
DOUBLE precision is 64-bit as we already saw before.

same goes with other data types (BOOL,CHAR,BYTE, SINT, INT, SINT, USINT, DINT, etc.)

ultimately, all data in computer is bunch of 1 and 0.
but that does not tell you what the group of bits represent. you really need to get both value AND format correctly or this will not make sense. 

so if you look at column to the left of the values, it shows the format. this must not be ignored. DEC and FLOATING_POINT are not the same format. 

they have different range, different resolution, etc. but they both are 32-bit values.
 

 

Share this post


Link to post
Share on other sites

Thanks.  Evening hours work for me.  Call me or text me to schedule.  Do you think it would be this evening or possibly tomorrow?

Share this post


Link to post
Share on other sites
3 hours ago, Sigma South said:

So, I tried converting and I am still struggling.

what seem to be the problem? did you look at the data at both sides in hexadecimal format? is the data transfer correct? in other words are you sure there is no corruption? really need to see the values on both ends in basic form (hexadecimal or maybe binary). if the data transfer is ocnfirmed to be ok, then the only reason there can be different representation is - format. but t know the format and order values correctly, you still need to look at data at both sides (send and receive) and at the same time, and compare values. 

tonight is fine. (in 4-5h)

 

 

 

Share this post


Link to post
Share on other sites

I cannot see both sides of the data.  I can assume AD1024 on the Profinet side is going to be a large number between 900,000 and 20,000,000.  I can also assume AD1036 and AD1040 will be somewhere between 200.000 and 600.000.  These are safe assumptions, so I would like to try and do everything on the Modbus side to see if I can get close before I ask the OEM for further help.

Thank you

Bill

Mobile Phone:  708-556-2929

 

Share this post


Link to post
Share on other sites

and why not?

how are you supposed to develop something that communicates it if you cannot see the data going back and forth? 

EasyModbus  has examples of both client and server. you can run server to simulate PLC. 

This allows you to see exactly what you are sending or receiving.For example this is what i get: 

EasyModbus.jpg

Share this post


Link to post
Share on other sites
On 04/08/2020 at 2:40 AM, Sigma South said:

Notice the first three are not floats.  They are decimals.  I'm not even sure at what register I should start at in the ModBus holding registers.  Also, what method should I use?
 

What device are you using to convert from profinet - modbus/tcp . A protocol converter usually has to have the mapping setup.

You should have set your profinet variables to correspond with modbus registers in the protocol converter.

 

1 person likes this

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!


Register a new account

Sign in

Already have an account? Sign in here.


Sign In Now