BiancoRoyal / node-red-contrib-modbus

maintained by PLUS for Node-RED - https://plus4nodered.com
https://www.npmjs.com/package/node-red-contrib-modbus
BSD 3-Clause "New" or "Revised" License
278 stars 107 forks source link

How to read signed float values? #459

Open mridah opened 2 months ago

mridah commented 2 months ago

I want to read a signed float value. I'm using Modbus Read node with quantity set to 2.

image

The function I have is as follows:

let pay = msg.payload.data;

var sign = pay[0] + pay[1] >= 65535 ? '-' : '+'; 

pay[0] = pay[0] > 32767 ? pay[0] - 32767 : pay[0];
pay[1] = pay[1] > 32767 ? pay[1] - 32767 : pay[1];

const buf = Buffer.allocUnsafe(4);

buf.writeUInt16BE(pay[0], 2); // high byte
buf.writeUInt16BE(pay[1], 0); // low byte

var val = Math.round(buf.readFloatBE(0) * 100) / 100;

msg.payload = parseFloat(sign + val);

This gives me the correct numeric value, however the sign keeps changing randomly. So I figured my logic to calculate the sign is wrong.

How can I read the actual float value with the correct sign?

unborn-andy commented 2 months ago

Hi .. I believe that readFloatBE should handle negative and positive values .. no need to calculate the sign yourself. Use the node-red-contrib-buffer-parser nodes .. they are very convenient for these kind of conversions.

Test Flow of their use (note that modbus nodes have the buffer data in msg.responseBuffer.buffer )

[{"id":"e9ea7e42fad5bfc9","type":"debug","z":"54efb553244c241f","name":"debug 71","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"payload","targetType":"msg","statusVal":"","statusType":"auto","x":660,"y":2180,"wires":[]},{"id":"e423319c59b4385d","type":"buffer-parser","z":"54efb553244c241f","name":"","data":"payload","dataType":"msg","specification":"spec","specificationType":"ui","items":[{"type":"floatbe","name":"item1","offset":0,"length":1,"offsetbit":0,"scale":"1","mask":""}],"swap1":"","swap2":"","swap3":"","swap1Type":"swap","swap2Type":"swap","swap3Type":"swap","msgProperty":"payload","msgPropertyType":"str","resultType":"keyvalue","resultTypeType":"return","multipleResult":false,"fanOutMultipleResult":false,"setTopic":true,"outputs":1,"x":350,"y":2180,"wires":[["351a01ed0d1285b6"]]},{"id":"7ef5c6af71df65b8","type":"inject","z":"54efb553244c241f","name":"","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"-1234.4452","payloadType":"num","x":170,"y":2040,"wires":[["89a4fa5d19b5ccdf"]]},{"id":"89a4fa5d19b5ccdf","type":"buffer-maker","z":"54efb553244c241f","name":"","specification":"spec","specificationType":"ui","items":[{"name":"item1","type":"floatbe","length":1,"dataType":"msg","data":"payload"}],"swap1":"","swap2":"","swap3":"","swap1Type":"swap","swap2Type":"swap","swap3Type":"swap","msgProperty":"payload","msgPropertyType":"str","x":330,"y":2040,"wires":[["9d8e141360959f50"]]},{"id":"9d8e141360959f50","type":"debug","z":"54efb553244c241f","name":"debug 72","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"false","statusVal":"","statusType":"auto","x":480,"y":2040,"wires":[]},{"id":"351a01ed0d1285b6","type":"function","z":"54efb553244c241f","name":"math round","func":"msg.payload = Math.round(msg.payload.item1 * 100) /100\nreturn msg;","outputs":1,"timeout":0,"noerr":0,"initialize":"","finalize":"","libs":[],"x":510,"y":2180,"wires":[["e9ea7e42fad5bfc9"]]},{"id":"31828368077565d8","type":"inject","z":"54efb553244c241f","name":"Modbus buffer","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"[196,154,78,63]","payloadType":"bin","x":180,"y":2180,"wires":[["e423319c59b4385d"]]},{"id":"0565e32cafce835e","type":"comment","z":"54efb553244c241f","name":"float to Buffer","info":"","x":170,"y":2000,"wires":[]},{"id":"4a8da04fb4850514","type":"comment","z":"54efb553244c241f","name":"Buffer to float","info":"","x":170,"y":2140,"wires":[]}]
grewek commented 2 months ago

Hi,

The sign bit in a floating value is the highest bit of the number so in your case this would be bit 15 in pay[0] so what you could do is use a bit mask and a shift:

var sign = pay[0] & (1 << 15) ? '-' : '+'

Short explanation: (1 << 15) First we are take the value 1(binary: 0000 0000 0000 0001) and shift it up 15 positions to the left (<<) which gives us (binary: 1000 0000 0000 0000) we can now isolate the sign bit by use the Binary AND operator (i will use the value shown in your screenshot):

1000 0001 1010 1110 | (33198)
1000 0000 0000 0000 | (32786)
--------------------
1000 0000 0000 0000

This should solve your sign issues