├── .gitignore ├── Dockerfile ├── README.md ├── binding.gyp ├── configure.patch ├── examples ├── master.js ├── master_native.js └── slave.js ├── make_libmodbus.sh ├── modbus.js ├── mt.patch ├── package.json ├── src └── main.cpp └── wscript /.gitignore: -------------------------------------------------------------------------------- 1 | # Created by https://www.gitignore.io 2 | 3 | ### Node ### 4 | # Logs 5 | logs 6 | *.log 7 | 8 | # Runtime data 9 | pids 10 | *.pid 11 | *.seed 12 | 13 | # Directory for instrumented libs generated by jscoverage/JSCover 14 | lib-cov 15 | 16 | # Coverage directory used by tools like istanbul 17 | coverage 18 | 19 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) 20 | .grunt 21 | 22 | # node-waf configuration 23 | .lock-wscript 24 | 25 | # Compiled binary addons (http://nodejs.org/api/addons.html) 26 | build/Release 27 | build 28 | 29 | # Dependency directory 30 | # https://www.npmjs.org/doc/misc/npm-faq.html#should-i-check-my-node_modules-folder-into-git 31 | node_modules 32 | 33 | 34 | ### libmodbus ### 35 | libmodbus 36 | 37 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | ############################################################ 2 | # Dockerfile to ElephantHead IOT Gateway API server 3 | # Based on debian image 4 | ############################################################ 5 | 6 | # create base Debian image 7 | FROM phusion/baseimage:0.9.18 8 | MAINTAINER Paul Charlton techguru@byiq.com 9 | 10 | # Use baseimage-docker's init system. 11 | CMD ["/sbin/my_init"] 12 | 13 | RUN apt-get update 14 | RUN apt-get dist-upgrade -y 15 | RUN apt-get clean 16 | 17 | # install node.js 18 | RUN apt-get install nodejs -y 19 | RUN apt-get install build-essential -y 20 | RUN apt-get install npm -y 21 | RUN npm -g install npm@latest 22 | RUN apt-get install curl 23 | RUN apt-get clean 24 | RUN curl -sL https://deb.nodesource.com/setup_5.x | bash - 25 | RUN ln -s /usr/bin/nodejs /usr/bin/node 26 | RUN apt-get install nodejs -y 27 | RUN apt-get install libavahi-compat-libdnssd-dev -y 28 | RUN npm install 29 | 30 | # 31 | RUN useradd -ms /bin/bash modbus 32 | USER modbus 33 | WORKDIR /home/modbus 34 | COPY . ./ 35 | USER root 36 | RUN apt-get install git-core autoconf automake libtool -y 37 | 38 | 39 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | # News # 4 | Fix bindings to libmodbus 3.1.4. 5 | 6 | # About # 7 | This is binding to native library libmodbus (http://libmodbus.org/). 8 | 9 | Now working only in *nix system. 10 | 11 | Module have native function and framework. 12 | 13 | # Framework examples # 14 | ## Creating slave device (server) ## 15 | 16 | ```javascript 17 | var log = console.log; 18 | var mb = require('modbus').create(); 19 | 20 | // create device memory map 21 | var data = mb.createData({ countReg: 5, countBit: 2 }); 22 | data.setReg(2, 321); 23 | data.setBit(1, true); 24 | data.dumpData(); // show memory map 25 | 26 | // create slave device 27 | var ctx = mb.createSlave({ 28 | 29 | // connection type and params 30 | con: mb.createConTcp('127.0.0.1', 1502), 31 | //con: mb.createConRtu(1, '/dev/ttyS0', 9600), 32 | 33 | // data map 34 | data: data, 35 | 36 | // callback functions 37 | onQuery: function () { 38 | log('onQuery', mb.query()); 39 | //ctx.dumpData(); 40 | log(ctx.getBits(0, 2)); 41 | }, 42 | onDestroy: function () { 43 | log('onDestroy'); 44 | } 45 | }); 46 | 47 | // destroy device 48 | //setTimeout(function () { 49 | // ctx.destroy(); 50 | //}, 5000); 51 | ``` 52 | 53 | ## Creating master device (client) ## 54 | 55 | ```javascript 56 | var log = console.log; 57 | //var mb = require('modbus').create(true); // enable debug output 58 | var mb = require('modbus').create(); 59 | 60 | mb.onError(function (msg) { 61 | log('ERROR', msg); 62 | }); 63 | 64 | // create master device 65 | var ctx = mb.createMaster({ 66 | 67 | // connection type and params 68 | con: mb.createConTcp('127.0.0.1', 1502), 69 | //con: mb.createConRtu(1, '/dev/ttyS1', 9600), 70 | 71 | // callback functions 72 | onConnect: function () { 73 | log('onConnect'); 74 | log(ctx.getReg(2)); 75 | ctx.setBit(1, false); 76 | ctx.destroy(); 77 | }, 78 | onDestroy: function () { 79 | log('onDestroy'); 80 | } 81 | }); 82 | ``` 83 | 84 | # Creating master device use native function # 85 | WARNING: native function blocking all processes! 86 | 87 | ```javascript 88 | var log = console.log; 89 | var native = require('modbus').native; 90 | 91 | // create context 92 | var ctx = native.new_tcp("127.0.0.1", 1502); 93 | 94 | // connect to slave device 95 | native.connect(ctx); 96 | 97 | // get value 98 | var result = []; 99 | native.read_registers(ctx, 2, 1, result); 100 | log(result[0]); 101 | 102 | // set value 103 | native.write_bit(ctx, 1, native.OFF); 104 | 105 | // close context 106 | native.close(ctx); 107 | native.free(ctx); 108 | ``` 109 | 110 | # API # 111 | 112 | ## createData(arg) ## 113 | Create data map (use only slave device). 114 | 115 | arg[Object] - having next fields: 116 | * dataBit[Array] - array boolean values of read/write bits 117 | * dataInputBit[Array] - array boolean values of read only bits 118 | * dataReg[Array] - array 16bit unsigned integer values of read/write register 119 | * dataInputReg[Array] - array 16bit unsigned integer values of read only register 120 | * countBit[Number] - created empty dataBit array 121 | * countInputBit[Number] - created empty dataInputBit array 122 | * countReg[Number] - created empty dataReg array 123 | * countInputReg[Number] - created empty dataInputReg array 124 | * retur[Object] - data object with methods: 125 | 126 | getBit(adr) - get read/write bit value 127 | * adr[Number] - bit address 128 | * return[Boolean] - bit value 129 | 130 | getInputBit(adr) - get read only bit value 131 | 132 | getReg(adr) - get read/write register value 133 | 134 | getInputReg(adr) - get read only register value 135 | 136 | getBits(adr, count) - get read/write bits array value 137 | * adr[Number] - first bit address 138 | * count[Number] - count readed bits 139 | * return[Array] - array boolean values readed bits 140 | 141 | getInputBits(adr, count) - get read only bits array value 142 | 143 | getRegs(adr, count) - get read/write registers array value 144 | 145 | getInputRegs(adr, count) - get read only registers array value 146 | 147 | setBit(adr, val) - set read/write bit value 148 | * adr[Number] - address bit 149 | * val[Boolean] - value bit 150 | 151 | setInputBit(adr, val) - set read only bit value 152 | 153 | setReg(adr, val) - set read/write register value 154 | 155 | setInputReg(adr, val) - set read only register value 156 | 157 | setBits(adr, val) - set read/write bits array value 158 | * adr[Number] - first bit address 159 | * val[Array] - array boolean values 160 | 161 | setInputBits(adr, val) - set read only bits array value 162 | 163 | setRegs(adr, val) - set read/write registers array value 164 | 165 | setInputRegs(adr, val) - set read only registers array value 166 | 167 | dumpData() - show memory dump 168 | 169 | ## createConTcp(ip, port, max, slaveAddr) ## 170 | Create connection object for tcp connection. 171 | * ip[String] - ip address modbus slave device, default "127.0.0.1" 172 | * port[Number] - tcp port modbus slave device, default 502 173 | * max[Number] - max connections for slave device, default 1 174 | * slaveAddr[Number] - set slave device address, default 0xFF (need for some devices, e.g. segnetics) 175 | 176 | ## createConRtu(id, device, baud, parity, dataBit, stopBit) ## 177 | Create connection object for serial port connection. 178 | * id[Number] - id slave device on line, default 1 179 | * device[String] - name of serial port, default "/dev/ttyS0" 180 | * baud[Number] - using baudrate speed, the allowed values are 9600, 19200, 57600, 115200, etc, default 115200 181 | * parity[String] - using parity control, the allowed values are "N", "E", "O", default "N" 182 | * dataBit[Number] - count data bit, the allowed values are 5, 6, 7 and 8, default 8 183 | * stopBit[Number] - using stop bit, the allowed values are 1 and 2, default 1 184 | 185 | ## createSlave(arg) ## 186 | Create slave modbus device 187 | 188 | arg[Object] - having next fields: 189 | * con[Object] - connect object, created createConTcp/createConRtu function 190 | * data[Object] - memory map object, created createData function 191 | * onQuery[Function] - callback function, called if master device send any query request 192 | * onDestroy[Function] - callback function, called if device destroyed 193 | * return[Object] - data object (context) with methods: 194 | 195 | destroy() - destroyed slave device 196 | 197 | and all data object api 198 | 199 | ## createMaster(arg) ## 200 | Create master modbus device 201 | * con[Object] - connect object, created createConTcp/createConRtu function 202 | * onConnect[Function] - callback function, called if connect complete to slave device 203 | * onDestroy[Function] - callback function, called if device destroyed 204 | * return[Object] - data object (context) with methods: 205 | 206 | destroy() - destroyed slave device 207 | 208 | and all data object api without setInput* 209 | 210 | 211 | 212 | 213 | 214 | -------------------------------------------------------------------------------- /binding.gyp: -------------------------------------------------------------------------------- 1 | { 2 | 'conditions': [ 3 | [ 4 | 'OS=="mac"', { 5 | 'targets': [ 6 | { 7 | 'target_name': 'modbus_binding', 8 | 'cflags': [ 9 | '-Wall', 10 | ], 11 | 'xcode_settings': { 12 | 'OTHER_CFLAGS': [ '-ObjC' ], 13 | 'OTHER_CPLUSPLUSFLAGS' : ['-std=c++11','-stdlib=libc++', '-v'], 14 | 'OTHER_LDFLAGS': ['-stdlib=libc++'], 15 | 'MACOSX_DEPLOYMENT_TARGET': '10.11', 16 | 'GCC_ENABLE_CPP_EXCEPTIONS': 'YES', 17 | }, 18 | 'libraries': [ 19 | '../libmodbus/src/.libs/libmodbus.dylib', 20 | ], 21 | 'include_dirs': [ 22 | './libmodbus/src/', 23 | ], 24 | 'sources': [ 25 | './src/main.cpp' 26 | ], 27 | }, 28 | ] 29 | }, 30 | ], 31 | [ 32 | 'OS=="linux"', { 33 | 'targets': [ 34 | { 35 | 'target_name': 'modbus_binding', 36 | 'cflags': [ 37 | '-Wall', 38 | ], 39 | 'ldflags': [ 40 | '../libmodbus/src/.libs/modbus.o', 41 | '../libmodbus/src/.libs/modbus-data.o', 42 | '../libmodbus/src/.libs/modbus-rtu.o', 43 | '../libmodbus/src/.libs/modbus-tcp.o', 44 | ], 45 | 'include_dirs': [ 46 | './libmodbus/src/', 47 | ], 48 | 'sources': [ 49 | './src/main.cpp' 50 | ], 51 | }, 52 | ] 53 | }, 54 | ] 55 | ] 56 | } 57 | -------------------------------------------------------------------------------- /configure.patch: -------------------------------------------------------------------------------- 1 | --- configure.ac 2014-01-05 14:51:37.838162119 +0100 2 | +++ configure.ac.new 2014-01-05 14:52:09.269869766 +0100 3 | @@ -118,8 +118,8 @@ 4 | 5 | if test "x$GCC" = "xyes"; then 6 | case " $CFLAGS " in 7 | - *[[\ \ ]]-Werror[[\ \ ]]*) ;; 8 | - *) CFLAGS="$CFLAGS -Werror" ;; 9 | + *[[\ \ ]][[\ \ ]]*) ;; 10 | + *) CFLAGS="$CFLAGS" ;; 11 | esac 12 | fi 13 | 14 | -------------------------------------------------------------------------------- /examples/master.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var log = console.log; 4 | //var mb = require('../modbus.js').create(true); // enable debug output 5 | var mb = require('../modbus.js').create(); 6 | 7 | mb.onError(function (msg) { 8 | log('ERROR', msg); 9 | }); 10 | 11 | // create master device 12 | var ctx = mb.createMaster({ 13 | 14 | // connection type and params 15 | con: mb.createConTcp('127.0.0.1', 1502), 16 | //con: mb.createConRtu(1, '/dev/ttyS1', 9600), 17 | 18 | // callback functions 19 | onConnect: function () { 20 | log('onConnect'); 21 | log(ctx.getReg(2)); 22 | ctx.setBit(1, false); 23 | ctx.destroy(); 24 | }, 25 | onDestroy: function () { 26 | log('onDestroy'); 27 | } 28 | }); 29 | -------------------------------------------------------------------------------- /examples/master_native.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var log = console.log; 4 | var native = require('../modbus.js').native; 5 | 6 | // create context 7 | var ctx = native.new_tcp("127.0.0.1", 1502); 8 | 9 | // connect to slave device 10 | native.connect(ctx); 11 | 12 | // get value 13 | var result = []; 14 | native.read_registers(ctx, 2, 1, result); 15 | log(result[0]); 16 | 17 | // set value 18 | native.write_bit(ctx, 1, native.OFF); 19 | 20 | // close context 21 | native.close(ctx); 22 | native.free(ctx); 23 | -------------------------------------------------------------------------------- /examples/slave.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var log = console.log; 4 | var mb = require('../modbus.js').create(); 5 | 6 | mb.onError(function (msg) { 7 | log('ERROR', msg); 8 | }); 9 | 10 | // create device memory map 11 | var data = mb.createData({ countReg: 5, countBit: 2 }); 12 | data.setReg(2, 321); 13 | data.setBit(1, true); 14 | data.dumpData(); // show memory map 15 | 16 | // create slave device 17 | var ctx = mb.createSlave({ 18 | 19 | // connection type and params 20 | con: mb.createConTcp('127.0.0.1', 1502), 21 | //con: mb.createConRtu(1, '/dev/ttyS0', 9600), 22 | 23 | // data map 24 | data: data, 25 | 26 | // callback functions 27 | onQuery: function () { 28 | log('onQuery'); 29 | //ctx.dumpData(); 30 | log(ctx.getBits(0, 2)); 31 | }, 32 | onDestroy: function () { 33 | log('onDestroy'); 34 | } 35 | }); 36 | 37 | // destroy device 38 | //setTimeout(function () { 39 | // ctx.destroy(); 40 | //}, 5000); 41 | -------------------------------------------------------------------------------- /make_libmodbus.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | git clone https://github.com/stephane/libmodbus.git 4 | 5 | cd ./libmodbus/ 6 | 7 | # reset to patch commit number 8 | git reset --hard f935846 9 | 10 | # patch -c -p2 < ../mt.patch 11 | 12 | #./autogen.sh && ./configure --enable-static=yes --enable-shared=no && make 13 | ./autogen.sh && ./configure && make 14 | -------------------------------------------------------------------------------- /modbus.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var mb = require("./build/Release/modbus_binding"); 4 | 5 | //var DBG = true; 6 | var DBG = false; 7 | var data_query; 8 | var log = console.log; 9 | 10 | function dataChange(a, args) { 11 | var func = args.func; // вызываемая функция 12 | var jso = args.jso; // для локальных 13 | var ctx = args.ctx; // для удаленных 14 | var adr = args.adr; // адрес данных 15 | var count = args.count; // количество значений 16 | var val = args.val; // значения для записи 17 | 18 | var isLocal = null; 19 | if (jso) { 20 | isLocal = true; 21 | } else if (ctx) { 22 | isLocal = false; 23 | } else { 24 | a.err('dataChange: invalid arguments'); 25 | return null; 26 | } 27 | 28 | var funcs = {}; 29 | 30 | // получить один бит 31 | // params: adr 32 | funcs['getBit'] = function () { 33 | if (isLocal) { 34 | if (adr < 0 || adr >= jso.nb_bits) { 35 | a.err(func + ': invalid address'); 36 | return null; 37 | } 38 | 39 | if (jso.tab_bits[adr]) return true; 40 | else return false; 41 | } else { 42 | var val = []; 43 | 44 | if (mb.read_bits(ctx, adr, 1, val) == -1) { 45 | a.err(func + ': ' + mb.strerror()); 46 | return null; 47 | } 48 | 49 | if (val[0]) return true; 50 | else return false; 51 | } 52 | }; 53 | 54 | // получить один бит для чтения 55 | // params: adr 56 | funcs['getInputBit'] = function () { 57 | if (isLocal) { 58 | if (adr < 0 || adr >= jso.nb_input_bits) { 59 | a.err(func + ': invalid address'); 60 | return null; 61 | } 62 | 63 | if (jso.tab_input_bits[adr]) return true; 64 | else return false; 65 | } else { 66 | var val = []; 67 | 68 | if (mb.read_input_bits(ctx, adr, 1, val) == -1) { 69 | a.err(func + ': ' + mb.strerror()); 70 | return null; 71 | } 72 | 73 | if (val[0]) return true; 74 | else return false; 75 | } 76 | }; 77 | 78 | // получить один регистр 79 | // params: adr 80 | funcs['getReg'] = function () { 81 | if (isLocal) { 82 | if (adr < 0 || adr >= jso.nb_registers) { 83 | a.err(func + ': invalid address'); 84 | return null; 85 | } 86 | 87 | return jso.tab_registers[adr]; 88 | } else { 89 | var val = []; 90 | 91 | if (mb.read_registers(ctx, adr, 1, val) == -1) { 92 | a.err(func + ': ' + mb.strerror()); 93 | return null; 94 | } 95 | 96 | return val[0]; 97 | } 98 | }; 99 | 100 | // получить один регистр для чтения 101 | // params: adr 102 | funcs['getInputReg'] = function () { 103 | if (isLocal) { 104 | if (adr < 0 || adr >= jso.nb_input_registers) { 105 | a.err(func + ': invalid address'); 106 | return null; 107 | } 108 | 109 | return jso.tab_input_registers[adr]; 110 | } else { 111 | var val = []; 112 | 113 | if (mb.read_input_registers(ctx, adr, 1, val) == -1) { 114 | a.err(func + ': ' + mb.strerror()); 115 | return null; 116 | } 117 | 118 | return val[0]; 119 | } 120 | }; 121 | 122 | // получить список бит 123 | // params: adr, count 124 | funcs['getBits'] = function () { 125 | if (isLocal) { 126 | var end = adr + count; 127 | 128 | if (adr < 0 || adr >= jso.nb_bits || end > jso.nb_bits) { 129 | a.err(func + ': invalid address'); 130 | return null; 131 | } 132 | 133 | var ret = [], j = 0; 134 | for (var i = adr; i < end; i++) { 135 | if (jso.tab_bits[i]) ret[j] = true; 136 | else ret[j] = false; 137 | j++; 138 | } 139 | 140 | return ret; 141 | } else { 142 | var val = []; 143 | 144 | if (mb.read_bits(ctx, adr, count, val) == -1) { 145 | a.err(func + ': ' + mb.strerror()); 146 | return null; 147 | } 148 | 149 | var ret = []; 150 | for (var i in val) { 151 | if (val[i]) ret[i] = true; 152 | else ret[i] = false; 153 | } 154 | 155 | return ret; 156 | } 157 | }; 158 | 159 | // получить список бит для чтения 160 | // params: adr, count 161 | funcs['getInputBits'] = function () { 162 | if (isLocal) { 163 | var end = adr + count; 164 | 165 | if (adr < 0 || adr >= jso.nb_input_bits || end > jso.nb_input_bits) { 166 | a.err(func + ': invalid address'); 167 | return null; 168 | } 169 | 170 | var ret = [], j = 0; 171 | for (var i = adr; i < end; i++) { 172 | if (jso.tab_input_bits[i]) ret[j] = true; 173 | else ret[j] = false; 174 | j++; 175 | } 176 | 177 | return ret; 178 | } else { 179 | var val = []; 180 | 181 | if (mb.read_input_bits(ctx, adr, count, val) == -1) { 182 | a.err(func + ': ' + mb.strerror()); 183 | return null; 184 | } 185 | 186 | var ret = []; 187 | for (var i in val) { 188 | if (val[i]) ret[i] = true; 189 | else ret[i] = false; 190 | } 191 | 192 | return ret; 193 | } 194 | }; 195 | 196 | // получить список регистров 197 | // params: adr, count 198 | funcs['getRegs'] = function () { 199 | if (isLocal) { 200 | var end = adr + count; 201 | 202 | if (adr < 0 || adr >= jso.nb_registers || end > jso.nb_registers) { 203 | a.err(func + ': invalid address'); 204 | return null; 205 | } 206 | 207 | var ret = [], j = 0; 208 | for (var i = adr; i < end; i++) { 209 | ret[j] = jso.tab_registers[i]; 210 | j++; 211 | } 212 | 213 | return ret; 214 | } else { 215 | var ret = []; 216 | 217 | if (mb.read_registers(ctx, adr, count, ret) == -1) { 218 | a.err(func + ': ' + mb.strerror()); 219 | return null; 220 | } 221 | 222 | return ret; 223 | } 224 | }; 225 | 226 | // получить список регистров для чтения 227 | // params: adr, count 228 | funcs['getInputRegs'] = function () { 229 | if (isLocal) { 230 | var end = adr + count; 231 | 232 | if (adr < 0 || adr >= jso.nb_input_registers || end > jso.nb_input_registers) { 233 | a.err(func + ': invalid address'); 234 | return null; 235 | } 236 | 237 | var ret = [], j = 0; 238 | for (var i = adr; i < end; i++) { 239 | ret[j] = jso.tab_input_registers[i]; 240 | j++; 241 | } 242 | 243 | return ret; 244 | } else { 245 | var ret = []; 246 | 247 | if (mb.read_input_registers(ctx, adr, count, ret) == -1) { 248 | a.err(func + ': ' + mb.strerror()); 249 | return null; 250 | } 251 | 252 | return ret; 253 | } 254 | }; 255 | 256 | // установить один бит 257 | // params: adr, val 258 | funcs['setBit'] = function () { 259 | if (isLocal) { 260 | if (adr < 0 || adr >= jso.nb_bits) { 261 | a.err(func + ': invalid address'); 262 | return; 263 | } 264 | 265 | if (val) jso.tab_bits[adr] = mb.ON; 266 | else jso.tab_bits[adr] = mb.OFF; 267 | } else { 268 | if (val) val = mb.ON; 269 | else val = mb.OFF; 270 | 271 | if (mb.write_bit(ctx, adr, val) == -1) { 272 | a.err(func + ': ' + mb.strerror()); 273 | } 274 | } 275 | }; 276 | 277 | // установить один бит для чтения 278 | // params: adr, val 279 | funcs['setInputBit'] = function () { 280 | if (isLocal) { 281 | if (adr < 0 || adr >= jso.nb_input_bits) { 282 | a.err(func + ': invalid address'); 283 | return; 284 | } 285 | 286 | if (val) jso.tab_input_bits[adr] = mb.ON; 287 | else jso.tab_input_bits[adr] = mb.OFF; 288 | } else { 289 | a.err(func + ': permission denied'); 290 | } 291 | }; 292 | 293 | // установить один регистр 294 | // params: adr, val 295 | funcs['setReg'] = function () { 296 | if (val < 0 || val > 0xFFFF) { 297 | a.err(func + ': invalid value ' + val); 298 | val = 0; 299 | } 300 | 301 | if (isLocal) { 302 | if (adr < 0 || adr >= jso.nb_registers) { 303 | a.err(func + ': invalid address'); 304 | return; 305 | } 306 | 307 | jso.tab_registers[adr] = val; 308 | } else { 309 | if (mb.write_register(ctx, adr, val) == -1) { 310 | a.err(func + ': ' + mb.strerror()); 311 | } 312 | } 313 | }; 314 | 315 | // установить один регистр для чтения 316 | // params: adr, val 317 | funcs['setInputReg'] = function () { 318 | if (val < 0 || val > 0xFFFF) { 319 | a.err(func + ': invalid value ' + val); 320 | val = 0; 321 | } 322 | 323 | if (isLocal) { 324 | if (adr < 0 || adr >= jso.nb_input_registers) { 325 | a.err(func + ': invalid address'); 326 | return; 327 | } 328 | 329 | jso.tab_input_registers[adr] = val; 330 | } else { 331 | a.err(func + ': permission denied'); 332 | } 333 | }; 334 | 335 | // установить список бит 336 | // params: adr, val 337 | funcs['setBits'] = function () { 338 | var count = val.length; 339 | 340 | if (isLocal) { 341 | var end = adr + count; 342 | 343 | if (adr < 0 || adr >= jso.nb_bits || end > jso.nb_bits) { 344 | a.err(func + ': invalid address'); 345 | return null; 346 | } 347 | 348 | var j = 0; 349 | for (var i = adr; i < end; i++) { 350 | if (val[j]) jso.tab_bits[i] = mb.ON; 351 | else jso.tab_bits[i] = mb.OFF; 352 | j++; 353 | } 354 | } else { 355 | var ar = []; 356 | 357 | for (var i in val) { 358 | if (val[i]) ar[i] = mb.ON; 359 | else ar[i] = mb.OFF; 360 | } 361 | 362 | if (mb.write_bits(ctx, adr, count, ar) == -1) { 363 | a.err(func + ': ' + mb.strerror()); 364 | } 365 | } 366 | }; 367 | 368 | // установить список бит для чтения 369 | // params: adr, val 370 | funcs['setInputBits'] = function () { 371 | var count = val.length; 372 | 373 | if (isLocal) { 374 | var end = adr + count; 375 | 376 | if (adr < 0 || adr >= jso.nb_input_bits || end > jso.nb_input_bits) { 377 | a.err(func + ': invalid address'); 378 | return null; 379 | } 380 | 381 | var j = 0; 382 | for (var i = adr; i < end; i++) { 383 | if (val[j]) jso.tab_input_bits[i] = mb.ON; 384 | else jso.tab_input_bits[i] = mb.OFF; 385 | j++; 386 | } 387 | } else { 388 | a.err(func + ': permission denied'); 389 | } 390 | }; 391 | 392 | // установить список регистров 393 | // params: adr, val 394 | funcs['setRegs'] = function () { 395 | var count = val.length; 396 | 397 | if (isLocal) { 398 | var end = adr + count; 399 | 400 | if (adr < 0 || adr >= jso.nb_registers || end > jso.nb_registers) { 401 | a.err(func + ': invalid address'); 402 | return null; 403 | } 404 | 405 | var j = 0; 406 | for (var i = adr; i < end; i++) { 407 | if (val[j] < 0 || val[j] > 0xFFFF) { 408 | a.err(func + ': invalid value ' + val[j]); 409 | val[j] = 0; 410 | } 411 | 412 | jso.tab_registers[i] = val[j]; 413 | j++; 414 | } 415 | } else { 416 | var ar = []; 417 | 418 | for (var i in val) { 419 | if (val[i] < 0 || val[i] > 0xFFFF) { 420 | a.err(func + ': invalid value ' + val[i]); 421 | val[i] = 0; 422 | } 423 | 424 | ar[i] = val[i]; 425 | } 426 | 427 | if (mb.write_registers(ctx, adr, count, ar) == -1) { 428 | a.err(func + ': ' + mb.strerror()); 429 | } 430 | } 431 | }; 432 | 433 | // установить список регистров для чтения 434 | // params: adr, val 435 | funcs['setInputRegs'] = function () { 436 | var count = val.length; 437 | 438 | if (isLocal) { 439 | var end = adr + count; 440 | 441 | if (adr < 0 || adr >= jso.nb_input_registers || end > jso.nb_input_registers) { 442 | a.err(func + ': invalid address'); 443 | return null; 444 | } 445 | 446 | var j = 0; 447 | for (var i = adr; i < end; i++) { 448 | if (val[j] < 0 || val[j] > 0xFFFF) { 449 | a.err(func + ': invalid value ' + val[j]); 450 | val[j] = 0; 451 | } 452 | 453 | jso.tab_input_registers[i] = val[j]; 454 | j++; 455 | } 456 | } else { 457 | a.err(func + ': permission denied'); 458 | } 459 | }; 460 | 461 | funcs['setSlave'] = function () { 462 | //console.log("setting slave to:" + val); 463 | if (mb.set_slave(ctx, val) == -1) { 464 | a.err(func + ': ' + mb.strerror()); 465 | } 466 | }; 467 | 468 | return funcs[func](); 469 | } 470 | 471 | function createData(a, args) { 472 | var onError = null; 473 | 474 | var dataBit = args.dataBit || []; 475 | var dataInputBit = args.dataInputBit || []; 476 | var dataReg = args.dataReg || []; 477 | var dataInputReg = args.dataInputReg || []; 478 | 479 | // если указанна длинна больше массива, то расширяем 480 | if (args.countBit > dataBit.length) { 481 | for (var i = dataBit.length; i < args.countBit; i++) { 482 | dataBit[i] = false; 483 | } 484 | } 485 | if (args.countInputBit > dataInputBit.length) { 486 | for (var i = dataInputBit.length; i < args.countInputBit; i++) { 487 | dataInputBit[i] = false; 488 | } 489 | } 490 | if (args.countReg > dataReg.length) { 491 | for (var i = dataReg.length; i < args.countReg; i++) { 492 | dataReg[i] = 0; 493 | } 494 | } 495 | if (args.countInputReg > dataInputReg.length) { 496 | for (var i = dataInputReg.length; i < args.countInputReg; i++) { 497 | dataInputReg[i] = 0; 498 | } 499 | } 500 | 501 | // валидация данных 502 | for (var i in dataBit) { 503 | if (dataBit[i]) dataBit[i] = mb.ON; 504 | else dataBit[i] = mb.OFF; 505 | } 506 | 507 | for (var i in dataInputBit) { 508 | if (dataInputBit[i]) dataInputBit[i] = mb.ON; 509 | else dataInputBit[i] = mb.OFF; 510 | } 511 | 512 | for (var i in dataReg) { 513 | if (dataReg[i] < 0 || dataReg[i] > 0xFFFF) { 514 | a.err('createData: invalid value ' + dataReg[i]); 515 | dataReg[i] = 0; 516 | } 517 | } 518 | 519 | for (var i in dataInputReg) { 520 | if (dataInputReg[i] < 0 || dataInputReg[i] > 0xFFFF) { 521 | a.err('createData: invalid value ' + dataInputReg[i]); 522 | dataInputReg[i] = 0; 523 | } 524 | } 525 | 526 | // создаем структуру данных 527 | var map = mb.mapping_new(dataBit.length, dataInputBit.length, dataReg.length, dataInputReg.length); 528 | var jso = { 529 | nb_bits: dataBit.length, 530 | nb_input_bits: dataInputBit.length, 531 | nb_input_registers: dataInputReg.length, 532 | nb_registers: dataReg.length, 533 | tab_bits: dataBit, 534 | tab_input_bits: dataInputBit, 535 | tab_input_registers: dataInputReg, 536 | tab_registers: dataReg 537 | }; 538 | 539 | // TODO: оптимизировать процесс синхронизации jso и map 540 | 541 | // соханить в нативной структуре 542 | function write() { 543 | mb.json_to_map(jso, map); 544 | } 545 | 546 | // прочитать из нативной структуры 547 | function read() { 548 | mb.map_to_json(map, jso); 549 | } 550 | 551 | // сохраняем созданные данные 552 | write(); 553 | 554 | var api = {}; 555 | 556 | api.getBit = function (adr) { 557 | read(); 558 | return dataChange(a, { func: 'getBit', jso: jso, adr: adr }); 559 | }; 560 | 561 | api.getInputBit = function (adr) { 562 | read(); 563 | return dataChange(a, { func: 'getInputBit', jso: jso, adr: adr }); 564 | }; 565 | 566 | api.getReg = function (adr) { 567 | read(); 568 | return dataChange(a, { func: 'getReg', jso: jso, adr: adr }); 569 | }; 570 | 571 | api.getInputReg = function (adr) { 572 | read(); 573 | return dataChange(a, { func: 'getInputReg', jso: jso, adr: adr }); 574 | }; 575 | 576 | api.getBits = function (adr, count) { 577 | read(); 578 | return dataChange(a, { func: 'getBits', jso: jso, adr: adr, count: count }); 579 | }; 580 | 581 | api.getInputBits = function (adr, count) { 582 | read(); 583 | return dataChange(a, { func: 'getInputBits', jso: jso, adr: adr, count: count }); 584 | }; 585 | 586 | api.getRegs = function (adr, count) { 587 | read(); 588 | return dataChange(a, { func: 'getRegs', jso: jso, adr: adr, count: count }); 589 | }; 590 | 591 | api.getInputRegs = function (adr, count) { 592 | read(); 593 | return dataChange(a, { func: 'getInputRegs', jso: jso, adr: adr, count: count }); 594 | }; 595 | 596 | api.setBit = function (adr, val) { 597 | dataChange(a, { func: 'setBit', jso: jso, adr: adr, val: val }); 598 | write(); 599 | }; 600 | 601 | api.setInputBit = function (adr, val) { 602 | dataChange(a, { func: 'setInputBit', jso: jso, adr: adr, val: val }); 603 | write(); 604 | }; 605 | 606 | api.setReg = function (adr, val) { 607 | dataChange(a, { func: 'setReg', jso: jso, adr: adr, val: val }); 608 | write(); 609 | }; 610 | 611 | api.setInputReg = function (adr, val) { 612 | dataChange(a, { func: 'setInputReg', jso: jso, adr: adr, val: val }); 613 | write(); 614 | }; 615 | 616 | api.setBits = function (adr, val) { 617 | dataChange(a, { func: 'setBits', jso: jso, adr: adr, val: val }); 618 | write(); 619 | }; 620 | 621 | api.setInputBits = function (adr, val) { 622 | dataChange(a, { func: 'setInputBits', jso: jso, adr: adr, val: val }); 623 | write(); 624 | }; 625 | 626 | api.setRegs = function (adr, val) { 627 | dataChange(a, { func: 'setRegs', jso: jso, adr: adr, val: val }); 628 | write(); 629 | }; 630 | 631 | api.setInputRegs = function (adr, val) { 632 | dataChange(a, { func: 'setInputRegs', jso: jso, adr: adr, val: val }); 633 | write(); 634 | }; 635 | 636 | // вывести дамп всех значений в терминал 637 | api.dumpData = function () { 638 | console.dir(jso); 639 | }; 640 | 641 | // private methods 642 | api._copyApi = function (obj) { 643 | obj.getBit = api.getBit; 644 | obj.getReg = api.getReg; 645 | obj.setBit = api.setBit; 646 | obj.setReg = api.setReg; 647 | obj.getInputBit = api.getInputBit; 648 | obj.getInputReg = api.getInputReg; 649 | obj.setInputBit = api.setInputBit; 650 | obj.setInputReg = api.setInputReg; 651 | 652 | obj.getBits = api.getBits; 653 | obj.getRegs = api.getRegs; 654 | obj.setBits = api.setBits; 655 | obj.setRegs = api.setRegs; 656 | obj.getInputBits = api.getInputBits; 657 | obj.getInputRegs = api.getInputRegs; 658 | obj.setInputBits = api.setInputBits; 659 | obj.setInputRegs = api.setInputRegs; 660 | 661 | obj.dumpData = api.dumpData; 662 | }; 663 | 664 | // внутренние функции 665 | api._reply = function (ctx, query, len) { 666 | data_query = query; 667 | mb.reply(ctx, query, len, map); 668 | read(); // FIXME: делается в геттерах 669 | }; 670 | 671 | // очистить данные 672 | api._freeMap = function () { 673 | mb.mapping_free(map); 674 | }; 675 | 676 | return api; 677 | }; 678 | 679 | function createConTcp(ip, port, max, slaveAddr) { 680 | if (!ip) ip = '127.0.0.1'; 681 | if (!port) port = mb.MODBUS_TCP_DEFAULT_PORT; 682 | if (!max) max = 1; 683 | if (!slaveAddr) slaveAddr = 0xFF; 684 | 685 | return { 686 | type: 'TCP', 687 | ip: ip, 688 | port: port, 689 | max: max, 690 | slaveAddr: slaveAddr // нужен некоторым устройствам, к примеру сетевкам segnetics-а 691 | }; 692 | }; 693 | 694 | function createConRtu(id, device, baud, parity, dataBit, stopBit, serialMode, rts) { 695 | if (!id) id = 1; 696 | if (!device) device = '/dev/ttyS0'; 697 | if (!baud) baud = 115200; 698 | if (!parity) parity = 'N'; 699 | if (!dataBit) dataBit = 8; 700 | if (!stopBit) stopBit = 1; 701 | if (!serialMode) serialMode = mb.MODBUS_RTU_RS232; 702 | if (!rts) rts = mb.MODBUS_RTU_RTS_NONE; 703 | 704 | return { 705 | type: 'RTU', 706 | id: id, 707 | device: device, 708 | baud: baud, 709 | parity: parity, 710 | dataBit: dataBit, 711 | stopBit: stopBit, 712 | serialMode: serialMode, 713 | rts: rts 714 | }; 715 | }; 716 | 717 | function makeSlaveApi(ctx, data) { 718 | var api = {}; 719 | 720 | data._copyApi(api); 721 | 722 | api.getContext = function () { 723 | return ctx; 724 | }; 725 | 726 | return api; 727 | } 728 | 729 | function createSlaveTcp(a, con, data, cbs) { 730 | var isWorking = false; 731 | 732 | // создаем контекст подключения 733 | var ctx = mb.new_tcp(con.ip, con.port); 734 | if (!ctx) { 735 | a.err('createSlaveTcp: ' + mb.strerror()); 736 | return null; 737 | } 738 | 739 | if (DBG) mb.set_debug(ctx, 1); 740 | 741 | // создаем сокет для ожидания соединения 742 | var sock = mb.tcp_listen(ctx, con.max); 743 | if (sock == -1) { 744 | a.err('createSlaveTcp: ' + mb.strerror()); 745 | return null; 746 | } 747 | 748 | // returned api 749 | var api = makeSlaveApi(ctx, data); 750 | 751 | api.destroy = function () { 752 | isWorking = false; 753 | 754 | mb.close_mt(ctx); 755 | data._freeMap(); 756 | data = null; 757 | mb.free(ctx); 758 | 759 | ctx = null; 760 | 761 | // чтобы не повадно было 762 | for (var i in api) api[i] = null; 763 | 764 | if (cbs.onDestroy) cbs.onDestroy(api); 765 | }; 766 | 767 | isWorking = true; 768 | 769 | // ждем соединения 770 | function accept(ctx, sock) { 771 | mb.tcp_accept_async(ctx, sock, function (newSock) { 772 | // если слушающий сокет был закрыт 773 | if (newSock == -1) return; 774 | 775 | if (isWorking) accept(ctx, sock); 776 | 777 | function recive() { 778 | mb.receive_async(ctx, function (query, len) { 779 | // клиент закрыл соединение 780 | if (len == -1) return; 781 | 782 | // обрабатываем данные и отвечаем клиенту 783 | data._reply(ctx, query, len); 784 | 785 | if (cbs.onQuery) cbs.onQuery(api); 786 | 787 | if (isWorking) recive(); 788 | }); 789 | } 790 | 791 | // принимаем данные, пока клиент не закроет соединение 792 | if (isWorking) recive(); 793 | 794 | }); 795 | } 796 | 797 | if (isWorking) accept(ctx, sock); 798 | 799 | return api; 800 | } 801 | 802 | function createSlaveRtu(a, con, data, cbs) { 803 | var isWorking = false; 804 | 805 | // создаем контекст подключения 806 | var ctx = mb.new_rtu(con.device, con.baud, con.parity, con.dataBit, con.stopBit); 807 | if (!ctx) { 808 | a.err('createSlaveRtu: ' + mb.strerror()); 809 | return null; 810 | } 811 | 812 | if (DBG) mb.set_debug(ctx, 1); 813 | 814 | mb.set_slave(ctx, con.id); 815 | 816 | // returned api 817 | var api = makeSlaveApi(ctx, data); 818 | 819 | api.destroy = function () { 820 | isWorking = false; 821 | 822 | mb.close_mt(ctx); 823 | data._freeMap(); 824 | data = null; 825 | mb.free(ctx); 826 | 827 | ctx = null; 828 | 829 | // чтобы не повадно было 830 | for (var i in api) api[i] = null; 831 | 832 | if (cbs.onDestroy) cbs.onDestroy(api); 833 | }; 834 | 835 | mb.connect_async(ctx, function (errCode) { 836 | if (errCode == -1) { 837 | a.err('createSlaveRtu: ' + mb.strerror()); 838 | return; 839 | } 840 | 841 | // очищаем буфер 842 | mb.flush(ctx); 843 | 844 | // set serial modes 845 | mb.rtu_set_serial_mode(ctx, con.serialMode); 846 | mb.rtu_set_rts(ctx, con.rts); 847 | 848 | isWorking = true; 849 | 850 | function recive() { 851 | mb.receive_async(ctx, function (query, len) { 852 | if (len == -1) { // пока нету данных 853 | if (isWorking) recive(); 854 | return; 855 | } 856 | 857 | // обрабатываем данные и отвечаем клиенту 858 | data._reply(ctx, query, len); 859 | 860 | if (cbs.onQuery) cbs.onQuery(api); 861 | 862 | // принимаем данные, пока клиент не закроет соединение 863 | if (isWorking) recive(); 864 | }); 865 | } 866 | 867 | if (isWorking) recive(); 868 | }); 869 | 870 | return api; 871 | } 872 | 873 | // создать сетевое подчиненное устройство (сервер) 874 | function createSlave(a, args) { 875 | // callback functions 876 | var cbs = {}; 877 | // onConnect 878 | cbs.onQuery = args.onQuery; 879 | // onDiconnect 880 | cbs.onDestroy = args.onDestroy; 881 | 882 | switch (args.con.type) { 883 | case 'TCP': return createSlaveTcp(a, args.con, args.data, cbs); 884 | case 'RTU': return createSlaveRtu(a, args.con, args.data, cbs); 885 | } 886 | } 887 | 888 | function makeMasterApi(a, ctx) { 889 | var api = {}; 890 | 891 | api.getBit = function (adr) { 892 | return dataChange(a, { func: 'getBit', ctx: ctx, adr: adr }); 893 | }; 894 | 895 | api.getInputBit = function (adr) { 896 | return dataChange(a, { func: 'getInputBit', ctx: ctx, adr: adr }); 897 | }; 898 | 899 | api.getReg = function (adr) { 900 | return dataChange(a, { func: 'getReg', ctx: ctx, adr: adr }); 901 | }; 902 | 903 | api.getInputReg = function (adr) { 904 | return dataChange(a, { func: 'getInputReg', ctx: ctx, adr: adr }); 905 | }; 906 | 907 | api.getBits = function (adr, count) { 908 | return dataChange(a, { func: 'getBits', ctx: ctx, adr: adr, count: count }); 909 | }; 910 | 911 | api.getInputBits = function (adr, count) { 912 | return dataChange(a, { func: 'getInputBits', ctx: ctx, adr: adr, count: count }); 913 | }; 914 | 915 | api.getRegs = function (adr, count) { 916 | return dataChange(a, { func: 'getRegs', ctx: ctx, adr: adr, count: count }); 917 | }; 918 | 919 | api.getInputRegs = function (adr, count) { 920 | return dataChange(a, { func: 'getInputRegs', ctx: ctx, adr: adr, count: count }); 921 | }; 922 | 923 | api.setBit = function (adr, val) { 924 | dataChange(a, { func: 'setBit', ctx: ctx, adr: adr, val: val }); 925 | }; 926 | 927 | api.setReg = function (adr, val) { 928 | dataChange(a, { func: 'setReg', ctx: ctx, adr: adr, val: val }); 929 | }; 930 | 931 | api.setBits = function (adr, val) { 932 | dataChange(a, { func: 'setBits', ctx: ctx, adr: adr, val: val }); 933 | }; 934 | 935 | api.setRegs = function (adr, val) { 936 | dataChange(a, { func: 'setRegs', ctx: ctx, adr: adr, val: val }); 937 | }; 938 | 939 | api.setSlave = function(val) { 940 | dataChange(a, { func: 'setSlave', ctx: ctx, val: val }); 941 | }; 942 | 943 | api.getContext = function () { 944 | return ctx; 945 | }; 946 | 947 | return api; 948 | } 949 | 950 | function createMasterTcp(a, con, cbs) { 951 | var isWorking = false; 952 | 953 | // создаем контекст подключения 954 | var ctx = mb.new_tcp(con.ip, con.port); 955 | if (!ctx) { 956 | a.err('createMasterTcp: ' + mb.strerror()); 957 | return null; 958 | } 959 | 960 | if (DBG) mb.set_debug(ctx, 1); 961 | 962 | var api = makeMasterApi(a, ctx); 963 | 964 | api.destroy = function () { 965 | isWorking = false; 966 | 967 | mb.close(ctx); 968 | mb.free(ctx); 969 | 970 | ctx = null; 971 | 972 | // чтобы не повадно было 973 | for (var i in api) api[i] = null; 974 | 975 | if (cbs.onDestroy) cbs.onDestroy(api); 976 | }; 977 | 978 | mb.connect_async(ctx, function (errCode) { 979 | if (errCode == -1) { 980 | a.err('createMasterTcp: ' + mb.strerror()); 981 | return; 982 | } 983 | 984 | isWorking = true; 985 | 986 | mb.set_slave(ctx, con.slaveAddr); 987 | 988 | if (cbs.onConnect) cbs.onConnect(api); 989 | }); 990 | 991 | return api; 992 | } 993 | 994 | function createMasterRtu(a, con, cbs) { 995 | var isWorking = false; 996 | 997 | // создаем контекст подключения 998 | var ctx = mb.new_rtu(con.device, con.baud, con.parity, con.dataBit, con.stopBit); 999 | if (!ctx) { 1000 | a.err('createMasterRtu: ' + mb.strerror()); 1001 | return null; 1002 | } 1003 | 1004 | if (DBG) mb.set_debug(ctx, 1); 1005 | 1006 | mb.set_slave(ctx, con.id); 1007 | 1008 | var api = makeMasterApi(a, ctx); 1009 | 1010 | api.destroy = function () { 1011 | isWorking = false; 1012 | 1013 | mb.close(ctx); 1014 | mb.free(ctx); 1015 | 1016 | ctx = null; 1017 | 1018 | // чтобы не повадно было 1019 | for (var i in api) api[i] = null; 1020 | 1021 | if (cbs.onDestroy) cbs.onDestroy(api); 1022 | }; 1023 | 1024 | mb.connect_async(ctx, function (errCode) { 1025 | if (errCode == -1) { 1026 | a.err('createMasterRtu: ' + mb.strerror()); 1027 | return; 1028 | } 1029 | 1030 | // очищаем буфер 1031 | mb.flush(ctx); 1032 | 1033 | // set serial modes 1034 | mb.rtu_set_serial_mode(ctx, con.serialMode); 1035 | mb.rtu_set_rts(ctx, con.rts); 1036 | 1037 | isWorking = true; 1038 | 1039 | if (cbs.onConnect) cbs.onConnect(api); 1040 | }); 1041 | 1042 | return api; 1043 | } 1044 | 1045 | function createMaster(a, args) { 1046 | // callback functions 1047 | var cbs = {}; 1048 | cbs.onConnect = args.onConnect; 1049 | // onDiconnect 1050 | cbs.onDestroy = args.onDestroy; 1051 | 1052 | switch (args.con.type) { 1053 | case 'TCP': return createMasterTcp(a, args.con, cbs); 1054 | case 'RTU': return createMasterRtu(a, args.con, cbs); 1055 | } 1056 | }; 1057 | 1058 | /* 1059 | reg2signed 1060 | reg2float 1061 | */ 1062 | // Decode a HEX-encoded float (2 regs) or double (4 regs) response 1063 | // params: resp (usually the response of the modbus device) (array) 1064 | function hexDecode(resp) { 1065 | return mb.hex_decode.apply(null, resp); 1066 | } 1067 | 1068 | function create(isDbg) { 1069 | var onError = null; // функция - обработчик ошибок 1070 | 1071 | if (isDbg) DBG = true; 1072 | 1073 | function err(msg) { 1074 | if (onError) onError(msg); 1075 | } 1076 | 1077 | // параметры текущего контекста 1078 | var ctxParam = { 1079 | err: err 1080 | }; 1081 | 1082 | return { 1083 | // установить функцию - обработчик ошибок 1084 | onError: function (func) { 1085 | onError = func; 1086 | }, 1087 | 1088 | // создать область с данными для сервера 1089 | createData: function (args) { 1090 | return createData(ctxParam, args); 1091 | }, 1092 | 1093 | // создать подключение 1094 | createConTcp: createConTcp, 1095 | createConRtu: createConRtu, 1096 | 1097 | // создать ведущее устройство (клиент) 1098 | createMaster: function (args) { 1099 | return createMaster(ctxParam, args); 1100 | }, 1101 | 1102 | // создать ведомое устройство (серер) 1103 | createSlave: function (args) { 1104 | return createSlave(ctxParam, args); 1105 | }, 1106 | 1107 | query: function () { 1108 | return data_query; 1109 | } 1110 | 1111 | }; 1112 | } 1113 | 1114 | module.exports = { 1115 | native: mb, 1116 | create: create 1117 | }; 1118 | -------------------------------------------------------------------------------- /mt.patch: -------------------------------------------------------------------------------- 1 | diff -cr -x .git ./libmodbus.orig/src/modbus.c ./libmodbus/src/modbus.c 2 | *** ./libmodbus.orig/src/modbus.c 2014-02-07 22:46:00.000000000 +0100 3 | --- ./libmodbus/src/modbus.c 2014-02-07 22:46:48.000000000 +0100 4 | *************** 5 | *** 1457,1468 **** 6 | --- 1457,1477 ---- 7 | ctx->backend->close(ctx); 8 | } 9 | 10 | + void modbus_close_mt(modbus_t *ctx) 11 | + { 12 | + if (ctx == NULL) 13 | + return; 14 | + 15 | + ctx->backend->close_mt(ctx); 16 | + } 17 | + 18 | void modbus_free(modbus_t *ctx) 19 | { 20 | if (ctx == NULL) 21 | return; 22 | 23 | free(ctx->backend_data); 24 | + free(ctx->mt_data); 25 | free(ctx); 26 | } 27 | 28 | diff -cr -x .git ./libmodbus.orig/src/modbus.h ./libmodbus/src/modbus.h 29 | *** ./libmodbus.orig/src/modbus.h 2014-02-07 22:46:00.000000000 +0100 30 | --- ./libmodbus/src/modbus.h 2014-02-07 22:46:48.000000000 +0100 31 | *************** 32 | *** 169,174 **** 33 | --- 169,175 ---- 34 | 35 | EXPORT int modbus_connect(modbus_t *ctx); 36 | EXPORT void modbus_close(modbus_t *ctx); 37 | + EXPORT void modbus_close_mt(modbus_t *ctx); 38 | 39 | EXPORT void modbus_free(modbus_t *ctx); 40 | 41 | diff -cr -x .git ./libmodbus.orig/src/modbus-private.h ./libmodbus/src/modbus-private.h 42 | *** ./libmodbus.orig/src/modbus-private.h 2014-02-07 22:46:00.000000000 +0100 43 | --- ./libmodbus/src/modbus-private.h 2014-02-07 22:46:48.000000000 +0100 44 | *************** 45 | *** 109,114 **** 46 | --- 109,115 ---- 47 | const uint8_t *rsp, int rsp_length); 48 | int (*connect) (modbus_t *ctx); 49 | void (*close) (modbus_t *ctx); 50 | + void (*close_mt) (modbus_t *ctx); 51 | int (*flush) (modbus_t *ctx); 52 | int (*select) (modbus_t *ctx, fd_set *rset, struct timeval *tv, int msg_length); 53 | } modbus_backend_t; 54 | *************** 55 | *** 124,129 **** 56 | --- 125,131 ---- 57 | struct timeval byte_timeout; 58 | const modbus_backend_t *backend; 59 | void *backend_data; 60 | + void *mt_data; 61 | }; 62 | 63 | void _modbus_init_common(modbus_t *ctx); 64 | diff -cr -x .git ./libmodbus.orig/src/modbus-rtu.c ./libmodbus/src/modbus-rtu.c 65 | *** ./libmodbus.orig/src/modbus-rtu.c 2014-02-07 22:46:00.000000000 +0100 66 | --- ./libmodbus/src/modbus-rtu.c 2014-02-07 22:58:00.000000000 +0100 67 | *************** 68 | *** 937,942 **** 69 | --- 937,954 ---- 70 | #endif 71 | } 72 | 73 | + void _modbus_rtu_close_mt(modbus_t *ctx) 74 | + { 75 | + ssize_t size; 76 | + _modbus_rtu_close(ctx); 77 | + 78 | + modbus_rtu_mt_t *ctx_mt = ctx->mt_data; 79 | + size = write(ctx_mt->mtp_w, "q", 1); 80 | + if (size == -1) 81 | + fprintf(stderr, "ERROR returned by write() (%s)\n", 82 | + strerror(errno)); 83 | + } 84 | + 85 | int _modbus_rtu_flush(modbus_t *ctx) 86 | { 87 | #if defined(_WIN32) 88 | *************** 89 | *** 964,970 **** 90 | return -1; 91 | } 92 | #else 93 | ! while ((s_rc = select(ctx->s+1, rset, NULL, NULL, tv)) == -1) { 94 | if (errno == EINTR) { 95 | if (ctx->debug) { 96 | fprintf(stderr, "A non blocked signal was caught\n"); 97 | --- 976,988 ---- 98 | return -1; 99 | } 100 | #else 101 | ! /* Add pipe descriptor to select */ 102 | ! modbus_rtu_mt_t *ctx_mt = ctx->mt_data; 103 | ! FD_SET(ctx_mt->mtp_r, rset); 104 | ! 105 | ! int max_n = (ctx->s > ctx_mt->mtp_r) ? ctx->s : ctx_mt->mtp_r; 106 | ! 107 | ! while ((s_rc = select(max_n+1, rset, NULL, NULL, tv)) == -1) { 108 | if (errno == EINTR) { 109 | if (ctx->debug) { 110 | fprintf(stderr, "A non blocked signal was caught\n"); 111 | *************** 112 | *** 972,977 **** 113 | --- 990,996 ---- 114 | /* Necessary after an error */ 115 | FD_ZERO(rset); 116 | FD_SET(ctx->s, rset); 117 | + FD_SET(ctx_mt->mtp_r, rset); 118 | } else { 119 | return -1; 120 | } 121 | *************** 122 | *** 983,989 **** 123 | return -1; 124 | } 125 | #endif 126 | ! 127 | return s_rc; 128 | } 129 | 130 | --- 1002,1013 ---- 131 | return -1; 132 | } 133 | #endif 134 | ! if (FD_ISSET(ctx_mt->mtp_r, rset)) { 135 | ! /* Connection reset. */ 136 | ! errno = ECONNRESET; 137 | ! return -1; 138 | ! } 139 | ! 140 | return s_rc; 141 | } 142 | 143 | *************** 144 | *** 1004,1009 **** 145 | --- 1028,1034 ---- 146 | _modbus_rtu_pre_check_confirmation, 147 | _modbus_rtu_connect, 148 | _modbus_rtu_close, 149 | + _modbus_rtu_close_mt, 150 | _modbus_rtu_flush, 151 | _modbus_rtu_select 152 | }; 153 | *************** 154 | *** 1014,1019 **** 155 | --- 1039,1045 ---- 156 | { 157 | modbus_t *ctx; 158 | modbus_rtu_t *ctx_rtu; 159 | + modbus_rtu_mt_t *ctx_mt; 160 | size_t dest_size; 161 | size_t ret_size; 162 | 163 | *************** 164 | *** 1062,1067 **** 165 | --- 1088,1107 ---- 166 | #endif 167 | 168 | ctx_rtu->confirmation_to_ignore = FALSE; 169 | + 170 | + /* Create pipe chanel */ 171 | + ctx->mt_data = (modbus_rtu_mt_t *) malloc(sizeof(modbus_rtu_mt_t)); 172 | + ctx_mt = (modbus_rtu_mt_t *)ctx->mt_data; 173 | + 174 | + int mtp[2]; 175 | + if (pipe(mtp) == -1) { 176 | + fprintf(stderr, "ERROR Can't create pipe (%s)\n", 177 | + strerror(errno)); 178 | + modbus_free(ctx); 179 | + return NULL; 180 | + } 181 | + ctx_mt->mtp_r = mtp[0]; 182 | + ctx_mt->mtp_w = mtp[1]; 183 | 184 | return ctx; 185 | } 186 | diff -cr -x .git ./libmodbus.orig/src/modbus-rtu-private.h ./libmodbus/src/modbus-rtu-private.h 187 | *** ./libmodbus.orig/src/modbus-rtu-private.h 2014-02-07 22:46:00.000000000 +0100 188 | --- ./libmodbus/src/modbus-rtu-private.h 2014-02-07 22:46:48.000000000 +0100 189 | *************** 190 | *** 94,97 **** 191 | --- 94,103 ---- 192 | int confirmation_to_ignore; 193 | } modbus_rtu_t; 194 | 195 | + typedef struct _modbus_rtu_mt { 196 | + /* Pipes for control in multithread */ 197 | + int mtp_r; 198 | + int mtp_w; 199 | + } modbus_rtu_mt_t; 200 | + 201 | #endif /* _MODBUS_RTU_PRIVATE_H_ */ 202 | diff -cr -x .git ./libmodbus.orig/src/modbus-tcp.c ./libmodbus/src/modbus-tcp.c 203 | *** ./libmodbus.orig/src/modbus-tcp.c 2014-02-07 22:46:00.000000000 +0100 204 | --- ./libmodbus/src/modbus-tcp.c 2014-02-07 22:46:48.000000000 +0100 205 | *************** 206 | *** 404,409 **** 207 | --- 404,420 ---- 208 | close(ctx->s); 209 | } 210 | 211 | + void _modbus_tcp_close_mt(modbus_t *ctx) 212 | + { 213 | + _modbus_tcp_close(ctx); 214 | + 215 | + modbus_tcp_mt_t *ctx_mt = ctx->mt_data; 216 | + if (ctx_mt->lst_socket != -1) { 217 | + shutdown(ctx_mt->lst_socket, SHUT_RDWR); 218 | + close(ctx_mt->lst_socket); 219 | + } 220 | + } 221 | + 222 | int _modbus_tcp_flush(modbus_t *ctx) 223 | { 224 | int rc; 225 | *************** 226 | *** 448,453 **** 227 | --- 459,465 ---- 228 | int yes; 229 | struct sockaddr_in addr; 230 | modbus_tcp_t *ctx_tcp = ctx->backend_data; 231 | + modbus_tcp_mt_t *ctx_mt = ctx->mt_data; 232 | 233 | #ifdef OS_WIN32 234 | if (_modbus_tcp_init_win32() == -1) { 235 | *************** 236 | *** 481,486 **** 237 | --- 493,500 ---- 238 | close(new_socket); 239 | return -1; 240 | } 241 | + 242 | + ctx_mt->lst_socket = new_socket; 243 | 244 | return new_socket; 245 | } 246 | *************** 247 | *** 495,500 **** 248 | --- 509,515 ---- 249 | const char *service; 250 | int new_socket; 251 | modbus_tcp_pi_t *ctx_tcp_pi = ctx->backend_data; 252 | + modbus_tcp_mt_t *ctx_mt = ctx->mt_data; 253 | 254 | if (ctx_tcp_pi->node[0] == 0) 255 | node = NULL; /* == any */ 256 | *************** 257 | *** 577,582 **** 258 | --- 592,599 ---- 259 | if (new_socket < 0) { 260 | return -1; 261 | } 262 | + 263 | + ctx_mt->lst_socket = new_socket; 264 | 265 | return new_socket; 266 | } 267 | *************** 268 | *** 671,676 **** 269 | --- 688,694 ---- 270 | _modbus_tcp_pre_check_confirmation, 271 | _modbus_tcp_connect, 272 | _modbus_tcp_close, 273 | + _modbus_tcp_close_mt, 274 | _modbus_tcp_flush, 275 | _modbus_tcp_select 276 | }; 277 | *************** 278 | *** 693,698 **** 279 | --- 711,717 ---- 280 | _modbus_tcp_pre_check_confirmation, 281 | _modbus_tcp_pi_connect, 282 | _modbus_tcp_close, 283 | + _modbus_tcp_close_mt, 284 | _modbus_tcp_flush, 285 | _modbus_tcp_select 286 | }; 287 | *************** 288 | *** 701,706 **** 289 | --- 720,726 ---- 290 | { 291 | modbus_t *ctx; 292 | modbus_tcp_t *ctx_tcp; 293 | + modbus_tcp_mt_t *ctx_mt; 294 | size_t dest_size; 295 | size_t ret_size; 296 | 297 | *************** 298 | *** 727,732 **** 299 | --- 747,755 ---- 300 | 301 | ctx->backend_data = (modbus_tcp_t *) malloc(sizeof(modbus_tcp_t)); 302 | ctx_tcp = (modbus_tcp_t *)ctx->backend_data; 303 | + 304 | + ctx->mt_data = (modbus_tcp_mt_t *) malloc(sizeof(modbus_tcp_mt_t)); 305 | + ctx_mt = (modbus_tcp_mt_t *)ctx->mt_data; 306 | 307 | dest_size = sizeof(char) * 16; 308 | ret_size = strlcpy(ctx_tcp->ip, ip, dest_size); 309 | *************** 310 | *** 746,751 **** 311 | --- 769,776 ---- 312 | 313 | ctx_tcp->port = port; 314 | ctx_tcp->t_id = 0; 315 | + 316 | + ctx_mt->lst_socket = -1; 317 | 318 | return ctx; 319 | } 320 | *************** 321 | *** 755,760 **** 322 | --- 780,786 ---- 323 | { 324 | modbus_t *ctx; 325 | modbus_tcp_pi_t *ctx_tcp_pi; 326 | + modbus_tcp_mt_t *ctx_mt; 327 | size_t dest_size; 328 | size_t ret_size; 329 | 330 | *************** 331 | *** 768,773 **** 332 | --- 794,802 ---- 333 | 334 | ctx->backend_data = (modbus_tcp_pi_t *) malloc(sizeof(modbus_tcp_pi_t)); 335 | ctx_tcp_pi = (modbus_tcp_pi_t *)ctx->backend_data; 336 | + 337 | + ctx->mt_data = (modbus_tcp_mt_t *) malloc(sizeof(modbus_tcp_mt_t)); 338 | + ctx_mt = (modbus_tcp_mt_t *)ctx->mt_data; 339 | 340 | dest_size = sizeof(char) * _MODBUS_TCP_PI_NODE_LENGTH; 341 | ret_size = strlcpy(ctx_tcp_pi->node, node, dest_size); 342 | *************** 343 | *** 802,807 **** 344 | --- 831,838 ---- 345 | } 346 | 347 | ctx_tcp_pi->t_id = 0; 348 | + 349 | + ctx_mt->lst_socket = -1; 350 | 351 | return ctx; 352 | } 353 | diff -cr -x .git ./libmodbus.orig/src/modbus-tcp-private.h ./libmodbus/src/modbus-tcp-private.h 354 | *** ./libmodbus.orig/src/modbus-tcp-private.h 2014-02-07 22:46:00.000000000 +0100 355 | --- ./libmodbus/src/modbus-tcp-private.h 2014-02-07 22:46:48.000000000 +0100 356 | *************** 357 | *** 53,56 **** 358 | --- 53,62 ---- 359 | char service[_MODBUS_TCP_PI_SERVICE_LENGTH]; 360 | } modbus_tcp_pi_t; 361 | 362 | + 363 | + typedef struct _modbus_tcp_mt { 364 | + /* Main listen socket */ 365 | + int lst_socket; 366 | + } modbus_tcp_mt_t; 367 | + 368 | #endif /* _MODBUS_TCP_PRIVATE_H_ */ 369 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "modbus", 3 | "version": "0.0.16", 4 | "description": "libmodbus binding", 5 | "keywords": [ 6 | "modbus" 7 | ], 8 | "main": "modbus.js", 9 | "engines": { 10 | "node": ">= 0.8.0" 11 | }, 12 | "scripts": { 13 | "install": "./make_libmodbus.sh && node-gyp configure && node-gyp build", 14 | "preuninstall": "rm -rf libmodbus build" 15 | }, 16 | "author": { 17 | "name": "Davydov Denis", 18 | "email": "mail@tuxnsk.ru" 19 | }, 20 | "maintainers": [ 21 | { 22 | "name": "Davydov Denis", 23 | "email": "mail@tuxnsk.ru" 24 | } 25 | ], 26 | "repository": { 27 | "type": "git", 28 | "url": "https://github.com/tuxnsk/nodejs_libmodbus.git" 29 | }, 30 | "license": "BSD" 31 | } 32 | -------------------------------------------------------------------------------- /src/main.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | #include 13 | 14 | using namespace v8; 15 | using namespace node; 16 | using namespace std; 17 | 18 | // finger to the sky 19 | #define REPORT_LEN 0xFF 20 | 21 | #if (NODE_MODULE_VERSION < 12) 22 | 23 | #define TO_EXTERNAL(sb) \ 24 | External::Wrap(sb) 25 | #define FROM_EXTERNAL(sb) \ 26 | External::Unwrap(sb) 27 | 28 | #else 29 | 30 | #define TO_EXTERNAL(sb) \ 31 | External::New(v8::Isolate::GetCurrent(), sb) 32 | #define FROM_EXTERNAL(sb) \ 33 | External::Cast(*sb)->Value() 34 | 35 | #endif 36 | 37 | // modbus_t *modbus_new_rtu(const char *device, int baud, char parity, int data_bit, int stop_bit); 38 | // External new_rtu(String, Integer, String, Integer, Integer); 39 | void js_new_rtu(const v8::FunctionCallbackInfo& args) { 40 | String::Utf8Value device(args[0]); 41 | int baud = Local::Cast(args[1])->Int32Value(); 42 | String::Utf8Value parity_str(args[2]); 43 | int data_bit = Local::Cast(args[3])->Int32Value(); 44 | int stop_bit = Local::Cast(args[4])->Int32Value(); 45 | 46 | char parity = (*parity_str)[0]; 47 | 48 | modbus_t *ctx = modbus_new_rtu(*device, baud, parity, data_bit, stop_bit); 49 | 50 | if (ctx == NULL) { 51 | args.GetReturnValue().SetNull(); 52 | } else { 53 | args.GetReturnValue().Set(TO_EXTERNAL(ctx)); 54 | } 55 | } 56 | 57 | // int modbus_rtu_get_serial_mode(modbus_t *ctx); 58 | // Integer rtu_get_serial_mode(External); 59 | void js_rtu_get_serial_mode(const v8::FunctionCallbackInfo& args) { 60 | modbus_t *ctx = static_cast(FROM_EXTERNAL(args[0])); 61 | 62 | int ret = modbus_rtu_get_serial_mode(ctx); 63 | 64 | args.GetReturnValue().Set(ret); 65 | } 66 | 67 | // int modbus_rtu_set_serial_mode(modbus_t *ctx, int mode); 68 | // Integer rtu_set_serial_mode(External, Integer); 69 | void js_rtu_set_serial_mode(const v8::FunctionCallbackInfo& args) { 70 | modbus_t *ctx = static_cast(FROM_EXTERNAL(args[0])); 71 | int mode = Local::Cast(args[1])->Int32Value(); 72 | 73 | int ret = modbus_rtu_set_serial_mode(ctx, mode); 74 | 75 | args.GetReturnValue().Set(ret); 76 | } 77 | 78 | // int modbus_rtu_get_rts(modbus_t *ctx); 79 | void js_rtu_get_rts(const v8::FunctionCallbackInfo& args) { 80 | modbus_t *ctx = static_cast(FROM_EXTERNAL(args[0])); 81 | 82 | int ret = modbus_rtu_get_rts(ctx); 83 | 84 | args.GetReturnValue().Set(ret); 85 | } 86 | 87 | // int modbus_rtu_set_rts(modbus_t *ctx, int mode) 88 | void js_rtu_set_rts(const v8::FunctionCallbackInfo& args) { 89 | modbus_t *ctx = static_cast(FROM_EXTERNAL(args[0])); 90 | int mode = Local::Cast(args[1])->Int32Value(); 91 | 92 | int ret = modbus_rtu_set_rts(ctx, mode); 93 | 94 | args.GetReturnValue().Set(ret); 95 | } 96 | 97 | // modbus_t *modbus_new_tcp(const char *ip, int port); 98 | // External new_tcp(String, Integer); 99 | void js_new_tcp(const v8::FunctionCallbackInfo& args) { 100 | String::Utf8Value ip(args[0]); 101 | int port = Local::Cast(args[1])->Int32Value(); 102 | 103 | modbus_t *ctx = modbus_new_tcp(*ip, port); 104 | 105 | if (ctx == NULL) { 106 | args.GetReturnValue().SetNull(); 107 | } else { 108 | args.GetReturnValue().Set(TO_EXTERNAL(ctx)); 109 | } 110 | } 111 | 112 | // modbus_t *modbus_new_tcp_pi(const char *node, const char *service); 113 | // External new_tcp_pi(String, String); 114 | void js_new_tcp_pi(const v8::FunctionCallbackInfo& args) { 115 | String::Utf8Value node(args[0]); 116 | String::Utf8Value service(args[1]); 117 | 118 | modbus_t *ctx = modbus_new_tcp_pi(*node, *service); 119 | 120 | if (ctx == NULL) { 121 | args.GetReturnValue().SetNull(); 122 | } else { 123 | args.GetReturnValue().Set(TO_EXTERNAL(ctx)); 124 | } 125 | } 126 | 127 | // void modbus_free(modbus_t *ctx); 128 | // Undefined free(External); 129 | void js_free(const v8::FunctionCallbackInfo& args) { 130 | modbus_t *ctx = static_cast(FROM_EXTERNAL(args[0])); 131 | 132 | modbus_free(ctx); 133 | 134 | args.GetReturnValue().SetUndefined(); 135 | } 136 | 137 | // void modbus_get_byte_timeout(modbus_t *ctx, struct timeval *timeout); 138 | // Undefined get_byte_timeout(External, Object); 139 | void js_get_byte_timeout(const v8::FunctionCallbackInfo& args) { 140 | Isolate* isolate = v8::Isolate::GetCurrent(); 141 | HandleScope scope(isolate); 142 | modbus_t *ctx = static_cast(FROM_EXTERNAL(args[0])); 143 | Local timeout_obj = Local::Cast(args[1]); 144 | 145 | 146 | uint32_t sec = 0; 147 | uint32_t usec = 0; 148 | 149 | modbus_get_byte_timeout(ctx, &sec, &usec); 150 | 151 | struct timeval timeout; 152 | timeout.tv_sec = sec; 153 | timeout.tv_usec = usec; 154 | 155 | timeout_obj->Set(String::NewFromUtf8(isolate, "tv_sec"), Uint32::New(isolate, timeout.tv_sec)); 156 | timeout_obj->Set(String::NewFromUtf8(isolate, "tv_usec"), Uint32::New(isolate, timeout.tv_usec)); 157 | 158 | args.GetReturnValue().SetUndefined(); 159 | } 160 | 161 | // void modbus_set_byte_timeout(modbus_t *ctx, struct timeval *timeout); 162 | // Undefined set_byte_timeout(External, Object); 163 | void js_set_byte_timeout(const v8::FunctionCallbackInfo& args) { 164 | Isolate* isolate = v8::Isolate::GetCurrent(); 165 | HandleScope scope(isolate); 166 | modbus_t *ctx = static_cast(FROM_EXTERNAL(args[0])); 167 | Local timeout_obj = Local::Cast(args[1]); 168 | 169 | struct timeval timeout; 170 | timeout.tv_sec = timeout_obj->Get(String::NewFromUtf8(isolate, "tv_sec"))->Uint32Value(); 171 | timeout.tv_usec = timeout_obj->Get(String::NewFromUtf8(isolate, "tv_usec"))->Uint32Value(); 172 | 173 | modbus_set_byte_timeout(ctx, timeout.tv_sec, timeout.tv_usec); 174 | 175 | args.GetReturnValue().SetUndefined(); 176 | } 177 | 178 | // void modbus_set_debug(modbus_t *ctx, int boolean); 179 | // Undefined set_debug(External, Integer); 180 | void js_set_debug(const v8::FunctionCallbackInfo& args) { 181 | modbus_t *ctx = static_cast(FROM_EXTERNAL(args[0])); 182 | int boolean = Local::Cast(args[1])->Int32Value(); 183 | 184 | modbus_set_debug(ctx, boolean); 185 | 186 | args.GetReturnValue().SetUndefined(); 187 | } 188 | 189 | // int modbus_set_error_recovery(modbus_t *ctx, modbus_error_recovery_mode error_recovery); 190 | // Integer set_error_recovery(External, Integer); 191 | void js_set_error_recovery(const v8::FunctionCallbackInfo& args) { 192 | modbus_t *ctx = static_cast(FROM_EXTERNAL(args[0])); 193 | int error_recovery = Local::Cast(args[1])->Int32Value(); 194 | 195 | int ret = modbus_set_error_recovery(ctx, static_cast(error_recovery)); 196 | 197 | args.GetReturnValue().Set(ret); 198 | } 199 | 200 | // int modbus_get_header_length(modbus_t *ctx); 201 | // Integer get_header_length(External); 202 | void js_get_header_length(const v8::FunctionCallbackInfo& args) { 203 | modbus_t *ctx = static_cast(FROM_EXTERNAL(args[0])); 204 | 205 | int ret = modbus_get_header_length(ctx); 206 | 207 | args.GetReturnValue().Set(ret); 208 | } 209 | 210 | // void modbus_get_response_timeout(modbus_t *ctx, struct timeval *timeout); 211 | // Undefined get_response_timeout(External, Object); 212 | void js_get_response_timeout(const v8::FunctionCallbackInfo& args) { 213 | Isolate* isolate = v8::Isolate::GetCurrent(); 214 | HandleScope scope(isolate); 215 | modbus_t *ctx = static_cast(FROM_EXTERNAL(args[0])); 216 | Local timeout_obj = Local::Cast(args[1]); 217 | 218 | uint32_t sec = 0; 219 | uint32_t usec = 0; 220 | 221 | modbus_get_response_timeout(ctx, &sec, &usec); 222 | 223 | struct timeval timeout; 224 | timeout.tv_sec = sec; 225 | timeout.tv_usec = usec; 226 | 227 | timeout_obj->Set(String::NewFromUtf8(isolate, "tv_sec"), Uint32::New(isolate, timeout.tv_sec)); 228 | timeout_obj->Set(String::NewFromUtf8(isolate, "tv_usec"), Uint32::New(isolate, timeout.tv_usec)); 229 | 230 | args.GetReturnValue().SetUndefined(); 231 | } 232 | 233 | // void modbus_set_response_timeout(modbus_t *ctx, struct timeval *timeout); 234 | // Undefined set_response_timeout(External, Object); 235 | void js_set_response_timeout(const v8::FunctionCallbackInfo& args) { 236 | Isolate* isolate = v8::Isolate::GetCurrent(); 237 | HandleScope scope(isolate); 238 | modbus_t *ctx = static_cast(FROM_EXTERNAL(args[0])); 239 | Local timeout_obj = Local::Cast(args[1]); 240 | 241 | struct timeval timeout; 242 | timeout.tv_sec = timeout_obj->Get(String::NewFromUtf8(isolate, "tv_sec"))->Uint32Value(); 243 | timeout.tv_usec = timeout_obj->Get(String::NewFromUtf8(isolate, "tv_usec"))->Uint32Value(); 244 | modbus_set_response_timeout(ctx, timeout.tv_sec, timeout.tv_usec); 245 | 246 | args.GetReturnValue().SetUndefined(); 247 | } 248 | 249 | // int modbus_set_slave(modbus_t *ctx, int slave); 250 | // Integer set_slave(External, Integer); 251 | void js_set_slave(const v8::FunctionCallbackInfo& args) { 252 | modbus_t *ctx = static_cast(FROM_EXTERNAL(args[0])); 253 | int slave = Local::Cast(args[1])->Int32Value(); 254 | 255 | int ret = modbus_set_slave(ctx, slave); 256 | 257 | args.GetReturnValue().Set(ret); 258 | } 259 | 260 | // void modbus_set_socket(modbus_t *ctx, int socket); 261 | // Undefined set_socket(External, Integer); 262 | void js_set_socket(const v8::FunctionCallbackInfo& args) { 263 | modbus_t *ctx = static_cast(FROM_EXTERNAL(args[0])); 264 | int socket = Local::Cast(args[1])->Int32Value(); 265 | 266 | modbus_set_socket(ctx, socket); 267 | 268 | args.GetReturnValue().SetUndefined(); 269 | } 270 | 271 | // int modbus_get_socket(modbus_t *ctx); 272 | // Integer get_socket(External); 273 | void js_get_socket(const v8::FunctionCallbackInfo& args) { 274 | modbus_t *ctx = static_cast(FROM_EXTERNAL(args[0])); 275 | 276 | int ret = modbus_get_socket(ctx); 277 | 278 | args.GetReturnValue().Set(ret); 279 | } 280 | 281 | // in js module 282 | // void modbus_set_bits_from_byte(uint8_t *dest, int index, const uint8_t value); 283 | // void modbus_set_bits_from_bytes(uint8_t *dest, int index, unsigned int nb_bits, const uint8_t *tab_byte); 284 | // uint8_t modbus_get_byte_from_bits(const uint8_t *src, int index, unsigned int nb_bits); 285 | // float modbus_get_float(const uint16_t *src); 286 | // void modbus_set_float(float f, uint16_t *dest); 287 | 288 | // int modbus_connect(modbus_t *ctx); 289 | // Integer connect(External); 290 | void js_connect(const v8::FunctionCallbackInfo& args) { 291 | modbus_t *ctx = static_cast(FROM_EXTERNAL(args[0])); 292 | 293 | int ret = modbus_connect(ctx); 294 | 295 | args.GetReturnValue().Set(ret); 296 | } 297 | 298 | // void modbus_close(modbus_t *ctx); 299 | // Undefined close(External); 300 | void js_close(const v8::FunctionCallbackInfo& args) { 301 | modbus_t *ctx = static_cast(FROM_EXTERNAL(args[0])); 302 | 303 | modbus_close(ctx); 304 | 305 | args.GetReturnValue().SetUndefined(); 306 | } 307 | 308 | // int modbus_flush(modbus_t *ctx); 309 | // Integer flush(External); 310 | void js_flush(const v8::FunctionCallbackInfo& args) { 311 | modbus_t *ctx = static_cast(FROM_EXTERNAL(args[0])); 312 | 313 | int ret = modbus_flush(ctx); 314 | 315 | args.GetReturnValue().Set(ret); 316 | } 317 | 318 | // int modbus_read_bits(modbus_t *ctx, int addr, int nb, uint8_t *dest); 319 | // Integer read_bits(External, Integer, Integer, Array); 320 | void js_read_bits(const v8::FunctionCallbackInfo& args) { 321 | Isolate* isolate = v8::Isolate::GetCurrent(); 322 | HandleScope scope(isolate); 323 | modbus_t *ctx = static_cast(FROM_EXTERNAL(args[0])); 324 | int addr = Local::Cast(args[1])->Int32Value(); 325 | int nb = Local::Cast(args[2])->Int32Value(); 326 | Local dest_arr = Local::Cast(args[3]); 327 | 328 | uint8_t dest[nb]; 329 | int ret = modbus_read_bits(ctx, addr, nb, dest); 330 | 331 | for (int i = 0; i < nb; i++) dest_arr->Set(i, Number::New(isolate, dest[i])); 332 | 333 | args.GetReturnValue().Set(ret); 334 | } 335 | 336 | // int modbus_read_input_bits(modbus_t *ctx, int addr, int nb, uint8_t *dest); 337 | // Integer read_input_bits(External, Integer, Integer, Array); 338 | void js_read_input_bits(const v8::FunctionCallbackInfo& args) { 339 | Isolate* isolate = v8::Isolate::GetCurrent(); 340 | HandleScope scope(isolate); 341 | modbus_t *ctx = static_cast(FROM_EXTERNAL(args[0])); 342 | int addr = Local::Cast(args[1])->Int32Value(); 343 | int nb = Local::Cast(args[2])->Int32Value(); 344 | Local dest_arr = Local::Cast(args[3]); 345 | 346 | uint8_t dest[nb]; 347 | int ret = modbus_read_input_bits(ctx, addr, nb, dest); 348 | 349 | for (int i = 0; i < nb; i++) dest_arr->Set(i, Number::New(isolate, dest[i])); 350 | 351 | args.GetReturnValue().Set(ret); 352 | } 353 | 354 | // int modbus_read_registers(modbus_t *ctx, int addr, int nb, uint16_t *dest); 355 | // Integer read_registers(External, Integer, Integer, Array); 356 | void js_read_registers(const v8::FunctionCallbackInfo& args) { 357 | Isolate* isolate = v8::Isolate::GetCurrent(); 358 | HandleScope scope(isolate); 359 | modbus_t *ctx = static_cast(FROM_EXTERNAL(args[0])); 360 | int addr = Local::Cast(args[1])->Int32Value(); 361 | int nb = Local::Cast(args[2])->Int32Value(); 362 | Local dest_arr = Local::Cast(args[3]); 363 | 364 | uint16_t dest[nb]; 365 | int ret = modbus_read_registers(ctx, addr, nb, dest); 366 | 367 | for (int i = 0; i < nb; i++) dest_arr->Set(i, Number::New(isolate, dest[i])); 368 | 369 | args.GetReturnValue().Set(ret); 370 | } 371 | 372 | // int modbus_read_input_registers(modbus_t *ctx, int addr, int nb, uint16_t *dest); 373 | // Integer read_input_registers(External, Integer, Integer, Array); 374 | void js_read_input_registers(const v8::FunctionCallbackInfo& args) { 375 | Isolate* isolate = v8::Isolate::GetCurrent(); 376 | HandleScope scope(isolate); 377 | modbus_t *ctx = static_cast(FROM_EXTERNAL(args[0])); 378 | int addr = Local::Cast(args[1])->Int32Value(); 379 | int nb = Local::Cast(args[2])->Int32Value(); 380 | Local dest_arr = Local::Cast(args[3]); 381 | 382 | uint16_t dest[nb]; 383 | int ret = modbus_read_input_registers(ctx, addr, nb, dest); 384 | 385 | for (int i = 0; i < nb; i++) dest_arr->Set(i, Number::New(isolate, dest[i])); 386 | 387 | args.GetReturnValue().Set(ret); 388 | } 389 | 390 | // int modbus_report_slave_id(modbus_t *ctx, int max_dest, uint8_t *dest); 391 | // Integer report_slave_id(External, Array, Integer); 392 | void js_report_slave_id(const v8::FunctionCallbackInfo& args) { 393 | Isolate* isolate = v8::Isolate::GetCurrent(); 394 | HandleScope scope(isolate); 395 | modbus_t *ctx = static_cast(FROM_EXTERNAL(args[0])); 396 | Local dest_obj = Local::Cast(args[1]); 397 | int max_dest = Local::Cast(args[2])->Int32Value(); 398 | 399 | uint8_t dest[REPORT_LEN]; 400 | memset(dest, 0, REPORT_LEN * sizeof(uint8_t)); 401 | 402 | int ret = modbus_report_slave_id(ctx, max_dest, dest); 403 | 404 | if (ret > 0) dest_obj->Set(0, Integer::New(isolate, dest[0])); // Slave ID 405 | if (ret > 1) dest_obj->Set(1, Integer::New(isolate, dest[1])); // Run Status Indicator 406 | if (ret > 2) { // Additional data 407 | for (int i = 2; i < ret; i++) dest_obj->Set(i, Integer::New(isolate, dest[i])); 408 | } 409 | 410 | args.GetReturnValue().Set(ret); 411 | } 412 | 413 | // int modbus_write_bit(modbus_t *ctx, int addr, int status); 414 | // Integer write_bit(External, Integer, Integer); 415 | void js_write_bit(const v8::FunctionCallbackInfo& args) { 416 | modbus_t *ctx = static_cast(FROM_EXTERNAL(args[0])); 417 | int addr = Local::Cast(args[1])->Int32Value(); 418 | int status = Local::Cast(args[2])->Int32Value(); 419 | 420 | int ret = modbus_write_bit(ctx, addr, status); 421 | 422 | args.GetReturnValue().Set(ret); 423 | } 424 | 425 | // int modbus_write_register(modbus_t *ctx, int addr, int value); 426 | // Integer write_register(External, Integer, Integer); 427 | void js_write_register(const v8::FunctionCallbackInfo& args) { 428 | modbus_t *ctx = static_cast(FROM_EXTERNAL(args[0])); 429 | int addr = Local::Cast(args[1])->Int32Value(); 430 | int value = Local::Cast(args[2])->Int32Value(); 431 | 432 | int ret = modbus_write_register(ctx, addr, value); 433 | 434 | args.GetReturnValue().Set(ret); 435 | } 436 | 437 | // int modbus_write_bits(modbus_t *ctx, int addr, int nb, const uint8_t *src); 438 | // Integer write_bits(External, Integer, Integer, Array); 439 | void js_write_bits(const v8::FunctionCallbackInfo& args) { 440 | modbus_t *ctx = static_cast(FROM_EXTERNAL(args[0])); 441 | int addr = Local::Cast(args[1])->Int32Value(); 442 | int nb = Local::Cast(args[2])->Int32Value(); 443 | Local src_arr = Local::Cast(args[3]); 444 | 445 | uint8_t src[nb]; 446 | for (int i = 0; i < nb; i++) src[i] = src_arr->Get(i)->Uint32Value(); 447 | 448 | int ret = modbus_write_bits(ctx, addr, nb, src); 449 | 450 | args.GetReturnValue().Set(ret); 451 | } 452 | 453 | // int modbus_write_registers(modbus_t *ctx, int addr, int nb, const uint16_t *src); 454 | // Integer write_registers(External, Integer, Integer, Array); 455 | void js_write_registers(const v8::FunctionCallbackInfo& args) { 456 | modbus_t *ctx = static_cast(FROM_EXTERNAL(args[0])); 457 | int addr = Local::Cast(args[1])->Int32Value(); 458 | int nb = Local::Cast(args[2])->Int32Value(); 459 | Local src_arr = Local::Cast(args[3]); 460 | 461 | uint16_t src[nb]; 462 | for (int i = 0; i < nb; i++) src[i] = src_arr->Get(i)->Uint32Value(); 463 | 464 | int ret = modbus_write_registers(ctx, addr, nb, src); 465 | 466 | args.GetReturnValue().Set(ret); 467 | } 468 | 469 | // int modbus_write_and_read_registers(modbus_t *ctx, int write_addr, int write_nb, const uint16_t *src, int read_addr, int read_nb, const uint16_t *dest); 470 | // Integer write_and_read_registers(External, Integer, Integer, Array, Integer, Integer, Array); 471 | void js_write_and_read_registers(const v8::FunctionCallbackInfo& args) { 472 | Isolate* isolate = v8::Isolate::GetCurrent(); 473 | HandleScope scope(isolate); 474 | modbus_t *ctx = static_cast(FROM_EXTERNAL(args[0])); 475 | int write_addr = Local::Cast(args[1])->Int32Value(); 476 | int write_nb = Local::Cast(args[2])->Int32Value(); 477 | Local src_arr = Local::Cast(args[3]); 478 | int read_addr = Local::Cast(args[4])->Int32Value(); 479 | int read_nb = Local::Cast(args[5])->Int32Value(); 480 | Local dest_arr = Local::Cast(args[6]); 481 | 482 | uint16_t src[write_nb]; 483 | for (int i = 0; i < write_nb; i++) src[i] = src_arr->Get(i)->Uint32Value(); 484 | 485 | uint16_t dest[read_nb]; 486 | 487 | int ret = modbus_write_and_read_registers(ctx, 488 | write_addr, write_nb, src, 489 | read_addr, read_nb, dest); 490 | 491 | for (int i = 0; i < read_nb; i++) dest_arr->Set(i, Number::New(isolate, dest[i])); 492 | 493 | args.GetReturnValue().Set(ret); 494 | } 495 | 496 | //int modbus_send_raw_request(modbus_t *ctx, uint8_t *raw_req, int raw_req_length); 497 | // Integer send_raw_request(External, Array, Integer); 498 | void js_send_raw_request(const v8::FunctionCallbackInfo& args) { 499 | modbus_t *ctx = static_cast(FROM_EXTERNAL(args[0])); 500 | Local raw_req_arr = Local::Cast(args[1]); 501 | int raw_req_length = Local::Cast(args[2])->Int32Value(); 502 | 503 | uint8_t raw_req[raw_req_length]; 504 | for (int i = 0; i < raw_req_length; i++) raw_req[i] = raw_req_arr->Get(i)->Uint32Value(); 505 | 506 | int ret = modbus_send_raw_request(ctx, raw_req, raw_req_length); 507 | 508 | args.GetReturnValue().Set(ret); 509 | } 510 | 511 | // int modbus_receive_confirmation(modbus_t *ctx, uint8_t *rsp); 512 | // Integer receive_confirmation(External, Array); 513 | void js_receive_confirmation(const v8::FunctionCallbackInfo& args) { 514 | Isolate* isolate = v8::Isolate::GetCurrent(); 515 | HandleScope scope(isolate); 516 | modbus_t *ctx = static_cast(FROM_EXTERNAL(args[0])); 517 | Local rsp_arr = Local::Cast(args[1]); 518 | 519 | uint8_t rsp[MODBUS_TCP_MAX_ADU_LENGTH]; 520 | memset(rsp, 0, MODBUS_TCP_MAX_ADU_LENGTH * sizeof(uint8_t)); 521 | 522 | int ret = modbus_receive_confirmation(ctx, rsp); 523 | 524 | if (ret > 0) { 525 | for (int i = 0; i < ret; i++) rsp_arr->Set(i, Number::New(isolate, rsp[i])); 526 | } 527 | 528 | args.GetReturnValue().Set(ret); 529 | } 530 | 531 | // int modbus_reply_exception(modbus_t *ctx, const uint8_t *req, unsigned int exception_code); 532 | // Integer reply_exception(External, Array, Integer); 533 | void js_reply_exception(const v8::FunctionCallbackInfo& args) { 534 | modbus_t *ctx = static_cast(FROM_EXTERNAL(args[0])); 535 | Local req_arr = Local::Cast(args[1]); 536 | unsigned int exception_code = Local::Cast(args[2])->Int32Value(); 537 | 538 | int req_arr_len = req_arr->InternalFieldCount(); 539 | uint8_t req[req_arr_len]; 540 | for (int i = 0; i < req_arr_len; i++) req[i] = req_arr->Get(i)->Uint32Value(); 541 | 542 | int ret = modbus_reply_exception(ctx, req, exception_code); 543 | 544 | args.GetReturnValue().Set(ret); 545 | } 546 | 547 | // modbus_mapping_t *modbus_mapping_new(int nb_bits, int nb_input_bits, int nb_registers, int nb_input_registers); 548 | // External mapping_new(Integer, Integer, Integer, Integer); 549 | void js_mapping_new(const v8::FunctionCallbackInfo& args) { 550 | int nb_bits = Local::Cast(args[0])->Int32Value(); 551 | int nb_input_bits = Local::Cast(args[1])->Int32Value(); 552 | int nb_registers = Local::Cast(args[2])->Int32Value(); 553 | int nb_input_registers = Local::Cast(args[3])->Int32Value(); 554 | 555 | modbus_mapping_t *map = modbus_mapping_new(nb_bits, nb_input_bits, nb_registers, nb_input_registers); 556 | 557 | if (map == NULL) { 558 | args.GetReturnValue().SetNull(); 559 | } else { 560 | args.GetReturnValue().Set(TO_EXTERNAL(map)); 561 | } 562 | } 563 | 564 | // void modbus_mapping_free(modbus_mapping_t *mb_mapping); 565 | // Undefined mapping_free(External); 566 | void js_mapping_free(const v8::FunctionCallbackInfo& args) { 567 | modbus_mapping_t *map = static_cast(FROM_EXTERNAL(args[0])); 568 | 569 | modbus_mapping_free(map); 570 | 571 | args.GetReturnValue().SetUndefined(); 572 | } 573 | 574 | // int modbus_receive(modbus_t *ctx, uint8_t *req); 575 | // Integer receive(External, Array); 576 | void js_receive(const v8::FunctionCallbackInfo& args) { 577 | Isolate* isolate = v8::Isolate::GetCurrent(); 578 | HandleScope scope(isolate); 579 | modbus_t *ctx = static_cast(FROM_EXTERNAL(args[0])); 580 | Local req_arr = Local::Cast(args[1]); 581 | 582 | uint8_t req[MODBUS_TCP_MAX_ADU_LENGTH]; 583 | memset(req, 0, MODBUS_TCP_MAX_ADU_LENGTH * sizeof(uint8_t)); 584 | 585 | int ret = modbus_receive(ctx, req); 586 | 587 | if (ret > 0) { 588 | for (int i = 0; i < ret; i++) req_arr->Set(i, Number::New(isolate, req[i])); 589 | } 590 | 591 | args.GetReturnValue().Set(ret); 592 | } 593 | 594 | // int modbus_reply(modbus_t *ctx, const uint8_t *req, int req_length, modbus_mapping_t *mb_mapping); 595 | // Integer reply(External, Array, Integer, External); 596 | void js_reply(const v8::FunctionCallbackInfo& args) { 597 | modbus_t *ctx = static_cast(FROM_EXTERNAL(args[0])); 598 | Local req_arr = Local::Cast(args[1]); 599 | int req_length = Local::Cast(args[2])->Int32Value(); 600 | modbus_mapping_t *mb_mapping = static_cast(FROM_EXTERNAL(args[3])); 601 | 602 | uint8_t req[req_length]; 603 | for (int i = 0; i < req_length; i++) req[i] = req_arr->Get(i)->Uint32Value(); 604 | 605 | int ret = modbus_reply(ctx, req, req_length, mb_mapping); 606 | 607 | args.GetReturnValue().Set(ret); 608 | } 609 | 610 | // const char *modbus_strerror(*int errnum); 611 | // String strerror(); 612 | void js_strerror(const v8::FunctionCallbackInfo& args) { 613 | Isolate* isolate = v8::Isolate::GetCurrent(); 614 | HandleScope scope(isolate); 615 | const char *ret = modbus_strerror(errno); 616 | 617 | args.GetReturnValue().Set(v8::String::NewFromUtf8(isolate, ret)); 618 | } 619 | 620 | // int modbus_tcp_listen(modbus_t *ctx, int nb_connection); 621 | // Integer tcp_listen(External, Integer); 622 | void js_tcp_listen(const v8::FunctionCallbackInfo& args) { 623 | modbus_t *ctx = static_cast(FROM_EXTERNAL(args[0])); 624 | int nb_connection = Local::Cast(args[1])->Int32Value(); 625 | 626 | int ret = modbus_tcp_listen(ctx, nb_connection); 627 | 628 | args.GetReturnValue().Set(ret); 629 | } 630 | 631 | // int modbus_tcp_accept(modbus_t *ctx, int *socket); 632 | // Integer tcp_accept(External, Integer); 633 | void js_tcp_accept(const v8::FunctionCallbackInfo& args) { 634 | modbus_t *ctx = static_cast(FROM_EXTERNAL(args[0])); 635 | int socket = Local::Cast(args[1])->Int32Value(); 636 | 637 | int ret = modbus_tcp_accept(ctx, &socket); 638 | 639 | args.GetReturnValue().Set(ret); 640 | } 641 | 642 | // int modbus_tcp_pi_listen(modbus_t *ctx, int nb_connection); 643 | // Integer tcp_pi_listen(External, Integer); 644 | void js_tcp_pi_listen(const v8::FunctionCallbackInfo& args) { 645 | modbus_t *ctx = static_cast(FROM_EXTERNAL(args[0])); 646 | int nb_connection = Local::Cast(args[1])->Int32Value(); 647 | 648 | int ret = modbus_tcp_pi_listen(ctx, nb_connection); 649 | 650 | args.GetReturnValue().Set(ret); 651 | } 652 | 653 | // int modbus_tcp_pi_accept(modbus_t *ctx, int *socket); 654 | // Integer tcp_pi_accept(External, Integer); 655 | void js_tcp_pi_accept(const v8::FunctionCallbackInfo& args) { 656 | modbus_t *ctx = static_cast(FROM_EXTERNAL(args[0])); 657 | int socket = Local::Cast(args[1])->Int32Value(); 658 | 659 | int ret = modbus_tcp_pi_accept(ctx, &socket); 660 | 661 | args.GetReturnValue().Set(ret); 662 | } 663 | 664 | // convert modbus_mapping_t* to json object 665 | // Undefined map_to_json(External, Object); 666 | void map_to_json(const v8::FunctionCallbackInfo& args) { 667 | Isolate* isolate = v8::Isolate::GetCurrent(); 668 | HandleScope scope(isolate); 669 | modbus_mapping_t *map = static_cast(FROM_EXTERNAL(args[0])); 670 | Local jso = Local::Cast(args[1]); 671 | 672 | jso->Set(String::NewFromUtf8(isolate, "nb_bits"), Integer::New(isolate, map->nb_bits)); 673 | jso->Set(String::NewFromUtf8(isolate, "nb_input_bits"), Integer::New(isolate, map->nb_input_bits)); 674 | jso->Set(String::NewFromUtf8(isolate, "nb_input_registers"), Integer::New(isolate, map->nb_input_registers)); 675 | jso->Set(String::NewFromUtf8(isolate, "nb_registers"), Integer::New(isolate, map->nb_registers)); 676 | 677 | Local tab_bits = Array::New(isolate); 678 | for (int i = 0; i < map->nb_bits; i++) { 679 | tab_bits->Set(i, Integer::New(isolate, map->tab_bits[i])); 680 | } 681 | 682 | Local tab_input_bits = Array::New(isolate); 683 | for (int i = 0; i < map->nb_input_bits; i++) { 684 | tab_input_bits->Set(i, Integer::New(isolate, map->tab_input_bits[i])); 685 | } 686 | 687 | Local tab_input_registers = Array::New(isolate); 688 | for (int i = 0; i < map->nb_input_registers; i++) { 689 | tab_input_registers->Set(i, Integer::New(isolate, map->tab_input_registers[i])); 690 | } 691 | 692 | Local tab_registers = Array::New(isolate); 693 | for (int i = 0; i < map->nb_registers; i++) { 694 | tab_registers->Set(i, Integer::New(isolate, map->tab_registers[i])); 695 | } 696 | 697 | jso->Set(String::NewFromUtf8(isolate, "tab_bits"), tab_bits); 698 | jso->Set(String::NewFromUtf8(isolate, "tab_input_bits"), tab_input_bits); 699 | jso->Set(String::NewFromUtf8(isolate, "tab_input_registers"), tab_input_registers); 700 | jso->Set(String::NewFromUtf8(isolate, "tab_registers"), tab_registers); 701 | 702 | args.GetReturnValue().SetUndefined(); 703 | } 704 | 705 | // convert json object to modbus_mapping_t* 706 | // Undefined json_to_map(Object, External); 707 | void json_to_map(const v8::FunctionCallbackInfo& args) { 708 | Isolate* isolate = v8::Isolate::GetCurrent(); 709 | HandleScope scope(isolate); 710 | Local jso = Local::Cast(args[0]); 711 | modbus_mapping_t *map = static_cast(FROM_EXTERNAL(args[1])); 712 | 713 | map->nb_bits = jso->Get(String::NewFromUtf8(isolate, "nb_bits"))->Int32Value(); 714 | map->nb_input_bits = jso->Get(String::NewFromUtf8(isolate, "nb_input_bits"))->Int32Value(); 715 | map->nb_input_registers = jso->Get(String::NewFromUtf8(isolate, "nb_input_registers"))->Int32Value(); 716 | map->nb_registers = jso->Get(String::NewFromUtf8(isolate, "nb_registers"))->Int32Value(); 717 | 718 | Local tab_bits = Local::Cast(jso->Get(String::NewFromUtf8(isolate, "tab_bits"))); 719 | for (int i = 0; i < map->nb_bits; i++) { 720 | map->tab_bits[i] = tab_bits->Get(i)->Int32Value(); 721 | } 722 | 723 | Local tab_input_bits = Local::Cast(jso->Get(String::NewFromUtf8(isolate, "tab_input_bits"))); 724 | for (int i = 0; i < map->nb_input_bits; i++) { 725 | map->tab_input_bits[i] = tab_input_bits->Get(i)->Int32Value(); 726 | } 727 | 728 | Local tab_input_registers = Local::Cast(jso->Get(String::NewFromUtf8(isolate, "tab_input_registers"))); 729 | for (int i = 0; i < map->nb_input_registers; i++) { 730 | map->tab_input_registers[i] = tab_input_registers->Get(i)->Int32Value(); 731 | } 732 | 733 | Local tab_registers = Local::Cast(jso->Get(String::NewFromUtf8(isolate, "tab_registers"))); 734 | for (int i = 0; i < map->nb_registers; i++) { 735 | map->tab_registers[i] = tab_registers->Get(i)->Int32Value(); 736 | } 737 | 738 | args.GetReturnValue().SetUndefined(); 739 | } 740 | 741 | struct tcp_accept_t { 742 | modbus_t *ctx; 743 | int socket; 744 | Persistent cb; 745 | int ret; 746 | }; 747 | 748 | void tcp_accept_w(uv_work_t* req) { 749 | tcp_accept_t* request = (tcp_accept_t*)req->data; 750 | request->ret = modbus_tcp_accept(request->ctx, &(request->socket)); 751 | } 752 | 753 | void tcp_accept_a(uv_work_t* req, int arg) { 754 | Isolate* isolate = v8::Isolate::GetCurrent(); 755 | HandleScope scope(isolate); 756 | tcp_accept_t* request = (tcp_accept_t*)req->data; 757 | delete req; 758 | 759 | Handle argv[1]; 760 | argv[0] = Integer::New(isolate, request->ret); 761 | 762 | v8::Local lf = v8::Local::New(isolate,request->cb); 763 | lf->Call(Null(isolate), 1, argv); 764 | 765 | request->cb.Reset(); 766 | delete request; 767 | } 768 | 769 | // Undefined tcp_accept_async(External, Integer, Function); 770 | // callback function - Function(Integer); 771 | void tcp_accept_async(const v8::FunctionCallbackInfo& args) { 772 | Isolate* isolate = v8::Isolate::GetCurrent(); 773 | HandleScope scope(isolate); 774 | modbus_t *ctx = static_cast(FROM_EXTERNAL(args[0])); 775 | int socket = Local::Cast(args[1])->Int32Value(); 776 | Local cb = Local::Cast(args[2]); 777 | 778 | tcp_accept_t* request = new tcp_accept_t; 779 | request->ctx = ctx; 780 | request->socket = socket; 781 | request->cb.Reset(isolate, cb); 782 | 783 | uv_work_t* req = new uv_work_t(); 784 | req->data = request; 785 | 786 | uv_queue_work(uv_default_loop(), req, tcp_accept_w, tcp_accept_a); 787 | 788 | args.GetReturnValue().SetUndefined(); 789 | } 790 | 791 | struct receive_t { 792 | modbus_t *ctx; 793 | uint8_t *req; 794 | int len; 795 | Persistent cb; 796 | }; 797 | 798 | void receive_w(uv_work_t* req) { 799 | receive_t* request = (receive_t*)req->data; 800 | request->len = modbus_receive(request->ctx, request->req); 801 | } 802 | 803 | void receive_a(uv_work_t* req, int arg) { 804 | Isolate* isolate = v8::Isolate::GetCurrent(); 805 | HandleScope scope(isolate); 806 | receive_t* request = (receive_t*)req->data; 807 | delete req; 808 | 809 | int len = request->len; 810 | 811 | Local req_arr = Array::New(isolate); 812 | if (len > 0) { 813 | for (int i = 0; i < len; i++) req_arr->Set(i, Number::New(isolate, request->req[i])); 814 | } 815 | 816 | delete request->req; 817 | 818 | Handle argv[2]; 819 | argv[0] = req_arr; 820 | argv[1] = Integer::New(isolate, len); 821 | 822 | v8::Local lf = v8::Local::New(isolate,request->cb); 823 | lf->Call(Null(isolate), 2, argv); 824 | 825 | request->cb.Reset(); 826 | delete request; 827 | } 828 | 829 | // Undefined receive_async(External, Function); 830 | // callback function - Function(Array, Integer); 831 | void receive_async(const v8::FunctionCallbackInfo& args) { 832 | Isolate* isolate = v8::Isolate::GetCurrent(); 833 | HandleScope scope(isolate); 834 | modbus_t *ctx = static_cast(FROM_EXTERNAL(args[0])); 835 | Local cb = Local::Cast(args[1]); 836 | 837 | uint8_t *mbreq = new uint8_t[MODBUS_TCP_MAX_ADU_LENGTH]; 838 | memset(mbreq, 0, MODBUS_TCP_MAX_ADU_LENGTH * sizeof(uint8_t)); 839 | 840 | receive_t* request = new receive_t; 841 | request->ctx = ctx; 842 | request->req = mbreq; 843 | request->len = 0; 844 | request->cb.Reset(isolate, cb); 845 | 846 | uv_work_t* req = new uv_work_t(); 847 | req->data = request; 848 | 849 | uv_queue_work(uv_default_loop(), req, receive_w, receive_a); 850 | 851 | args.GetReturnValue().SetUndefined(); 852 | } 853 | 854 | struct connect_t { 855 | modbus_t *ctx; 856 | Persistent cb; 857 | int ret; 858 | }; 859 | 860 | void connect_w(uv_work_t* req) { 861 | connect_t* request = (connect_t*)req->data; 862 | request->ret = modbus_connect(request->ctx); 863 | } 864 | 865 | void connect_a(uv_work_t* req, int arg) { 866 | Isolate* isolate = v8::Isolate::GetCurrent(); 867 | HandleScope scope(isolate); 868 | connect_t* request = (connect_t*)req->data; 869 | delete req; 870 | 871 | Handle argv[1]; 872 | argv[0] = Integer::New(isolate, request->ret); 873 | 874 | v8::Local lf = v8::Local::New(isolate,request->cb); 875 | lf->Call(Null(isolate), 1, argv); 876 | 877 | request->cb.Reset(); 878 | delete request; 879 | } 880 | 881 | // Undefined connect_async(External, Function); 882 | // callback function - Function(Integer); 883 | void connect_async(const v8::FunctionCallbackInfo& args) { 884 | Isolate* isolate = v8::Isolate::GetCurrent(); 885 | HandleScope scope(isolate); 886 | modbus_t *ctx = static_cast(FROM_EXTERNAL(args[0])); 887 | Local cb = Local::Cast(args[1]); 888 | 889 | connect_t* request = new connect_t; 890 | request->ctx = ctx; 891 | request->cb.Reset(isolate, cb); 892 | request->ret = 0; 893 | 894 | uv_work_t* req = new uv_work_t(); 895 | req->data = request; 896 | 897 | uv_queue_work(uv_default_loop(), req, connect_w, connect_a); 898 | 899 | args.GetReturnValue().SetUndefined(); 900 | } 901 | 902 | // закрыть из треда 903 | // Undefined close(External); 904 | void close_mt(const v8::FunctionCallbackInfo& args) { 905 | modbus_t *ctx = static_cast(FROM_EXTERNAL(args[0])); 906 | 907 | modbus_close(ctx); 908 | 909 | args.GetReturnValue().SetUndefined(); 910 | } 911 | 912 | // Decode HEX value to a float or double 913 | void hex_decode(const v8::FunctionCallbackInfo& args) { 914 | Isolate* isolate = v8::Isolate::GetCurrent(); 915 | HandleScope scope(isolate); 916 | int nArgs = args.Length(); 917 | 918 | if (nArgs != 2 && nArgs != 4) { 919 | isolate->ThrowException(Exception::TypeError(String::NewFromUtf8(isolate, "Need at least 2 or 4 16-bit numbers"))); 920 | return; 921 | } 922 | 923 | uint16_t input[nArgs]; 924 | for (int i = 0; i < nArgs; i++) { 925 | input[i] = (uint16_t) args[i]->ToInteger()->Value(); 926 | } 927 | 928 | if (nArgs == 2) { 929 | uint32_t raw_value = (((uint32_t) input[0]) << 16) + input[1]; 930 | float output; 931 | memcpy(&output, &raw_value, sizeof(float)); 932 | args.GetReturnValue().Set(output); 933 | } else { 934 | uint64_t raw_value = (((uint64_t) input[0]) << 48) + ((uint64_t) input[1] << 32) + ((uint32_t) input[2] << 16) + input[3]; 935 | double output; 936 | memcpy(&output, &raw_value, sizeof(double)); 937 | 938 | args.GetReturnValue().Set(output); 939 | } 940 | } 941 | 942 | extern "C" void init (Handle target) { 943 | Isolate* isolate = target->GetIsolate(); 944 | 945 | // constants 946 | target->Set(String::NewFromUtf8(isolate, "LIBMODBUS_VERSION_MAJOR"), Number::New(isolate, LIBMODBUS_VERSION_MAJOR)); 947 | target->Set(String::NewFromUtf8(isolate, "LIBMODBUS_VERSION_MINOR"), Number::New(isolate, LIBMODBUS_VERSION_MINOR)); 948 | target->Set(String::NewFromUtf8(isolate, "LIBMODBUS_VERSION_MICRO"), Number::New(isolate, LIBMODBUS_VERSION_MICRO)); 949 | target->Set(String::NewFromUtf8(isolate, "LIBMODBUS_VERSION_STRING"), String::NewFromUtf8(isolate, LIBMODBUS_VERSION_STRING)); 950 | //target->Set(String::NewFromUtf8(isolate, "LIBMODBUS_VERSION_HEX"), Number::New(isolate, LIBMODBUS_VERSION_HEX)); bug in header 951 | 952 | target->Set(String::NewFromUtf8(isolate, "FALSE"), Number::New(isolate, FALSE)); 953 | target->Set(String::NewFromUtf8(isolate, "TRUE"), Number::New(isolate, TRUE)); 954 | 955 | target->Set(String::NewFromUtf8(isolate, "OFF"), Number::New(isolate, OFF)); 956 | target->Set(String::NewFromUtf8(isolate, "ON"), Number::New(isolate, ON)); 957 | 958 | target->Set(String::NewFromUtf8(isolate, "MODBUS_BROADCAST_ADDRESS"), Number::New(isolate, MODBUS_BROADCAST_ADDRESS)); 959 | 960 | target->Set(String::NewFromUtf8(isolate, "MODBUS_MAX_READ_BITS"), Number::New(isolate, MODBUS_MAX_READ_BITS)); 961 | target->Set(String::NewFromUtf8(isolate, "MODBUS_MAX_WRITE_BITS"), Number::New(isolate, MODBUS_MAX_WRITE_BITS)); 962 | 963 | target->Set(String::NewFromUtf8(isolate, "MODBUS_MAX_READ_REGISTERS"), Number::New(isolate, MODBUS_MAX_READ_REGISTERS)); 964 | target->Set(String::NewFromUtf8(isolate, "MODBUS_MAX_WRITE_REGISTERS"), Number::New(isolate, MODBUS_MAX_WRITE_REGISTERS)); 965 | target->Set(String::NewFromUtf8(isolate, "MODBUS_MAX_WR_WRITE_REGISTERS"), Number::New(isolate, MODBUS_MAX_WR_WRITE_REGISTERS)); 966 | 967 | target->Set(String::NewFromUtf8(isolate, "MODBUS_ENOBASE"), Number::New(isolate, MODBUS_ENOBASE)); 968 | 969 | target->Set(String::NewFromUtf8(isolate, "MODBUS_EXCEPTION_ILLEGAL_FUNCTION"), Number::New(isolate, MODBUS_EXCEPTION_ILLEGAL_FUNCTION)); 970 | target->Set(String::NewFromUtf8(isolate, "MODBUS_EXCEPTION_ILLEGAL_DATA_ADDRESS"), Number::New(isolate, MODBUS_EXCEPTION_ILLEGAL_DATA_ADDRESS)); 971 | target->Set(String::NewFromUtf8(isolate, "MODBUS_EXCEPTION_ILLEGAL_DATA_VALUE"), Number::New(isolate, MODBUS_EXCEPTION_ILLEGAL_DATA_VALUE)); 972 | target->Set(String::NewFromUtf8(isolate, "MODBUS_EXCEPTION_SLAVE_OR_SERVER_FAILURE"), Number::New(isolate, MODBUS_EXCEPTION_SLAVE_OR_SERVER_FAILURE)); 973 | target->Set(String::NewFromUtf8(isolate, "MODBUS_EXCEPTION_ACKNOWLEDGE"), Number::New(isolate, MODBUS_EXCEPTION_ACKNOWLEDGE)); 974 | target->Set(String::NewFromUtf8(isolate, "MODBUS_EXCEPTION_SLAVE_OR_SERVER_BUSY"), Number::New(isolate, MODBUS_EXCEPTION_SLAVE_OR_SERVER_BUSY)); 975 | target->Set(String::NewFromUtf8(isolate, "MODBUS_EXCEPTION_NEGATIVE_ACKNOWLEDGE"), Number::New(isolate, MODBUS_EXCEPTION_NEGATIVE_ACKNOWLEDGE)); 976 | target->Set(String::NewFromUtf8(isolate, "MODBUS_EXCEPTION_MEMORY_PARITY"), Number::New(isolate, MODBUS_EXCEPTION_MEMORY_PARITY)); 977 | target->Set(String::NewFromUtf8(isolate, "MODBUS_EXCEPTION_NOT_DEFINED"), Number::New(isolate, MODBUS_EXCEPTION_NOT_DEFINED)); 978 | target->Set(String::NewFromUtf8(isolate, "MODBUS_EXCEPTION_GATEWAY_PATH"), Number::New(isolate, MODBUS_EXCEPTION_GATEWAY_PATH)); 979 | target->Set(String::NewFromUtf8(isolate, "MODBUS_EXCEPTION_GATEWAY_TARGET"), Number::New(isolate, MODBUS_EXCEPTION_GATEWAY_TARGET)); 980 | target->Set(String::NewFromUtf8(isolate, "MODBUS_EXCEPTION_MAX"), Number::New(isolate, MODBUS_EXCEPTION_MAX)); 981 | 982 | target->Set(String::NewFromUtf8(isolate, "EMBXILFUN"), Number::New(isolate, EMBXILFUN)); 983 | target->Set(String::NewFromUtf8(isolate, "EMBXILADD"), Number::New(isolate, EMBXILADD)); 984 | target->Set(String::NewFromUtf8(isolate, "EMBXILVAL"), Number::New(isolate, EMBXILVAL)); 985 | target->Set(String::NewFromUtf8(isolate, "EMBXSFAIL"), Number::New(isolate, EMBXSFAIL)); 986 | target->Set(String::NewFromUtf8(isolate, "EMBXACK"), Number::New(isolate, EMBXACK)); 987 | target->Set(String::NewFromUtf8(isolate, "EMBXSBUSY"), Number::New(isolate, EMBXSBUSY)); 988 | target->Set(String::NewFromUtf8(isolate, "EMBXNACK"), Number::New(isolate, EMBXNACK)); 989 | target->Set(String::NewFromUtf8(isolate, "EMBXMEMPAR"), Number::New(isolate, EMBXMEMPAR)); 990 | target->Set(String::NewFromUtf8(isolate, "EMBXGPATH"), Number::New(isolate, EMBXGPATH)); 991 | target->Set(String::NewFromUtf8(isolate, "EMBXGTAR"), Number::New(isolate, EMBXGTAR)); 992 | 993 | target->Set(String::NewFromUtf8(isolate, "EMBBADCRC"), Number::New(isolate, EMBBADCRC)); 994 | target->Set(String::NewFromUtf8(isolate, "EMBBADDATA"), Number::New(isolate, EMBBADDATA)); 995 | target->Set(String::NewFromUtf8(isolate, "EMBBADEXC"), Number::New(isolate, EMBBADEXC)); 996 | target->Set(String::NewFromUtf8(isolate, "EMBUNKEXC"), Number::New(isolate, EMBUNKEXC)); 997 | target->Set(String::NewFromUtf8(isolate, "EMBMDATA"), Number::New(isolate, EMBMDATA)); 998 | 999 | target->Set(String::NewFromUtf8(isolate, "MODBUS_ERROR_RECOVERY_NONE"), Number::New(isolate, MODBUS_ERROR_RECOVERY_NONE)); 1000 | target->Set(String::NewFromUtf8(isolate, "MODBUS_ERROR_RECOVERY_LINK"), Number::New(isolate, MODBUS_ERROR_RECOVERY_LINK)); 1001 | target->Set(String::NewFromUtf8(isolate, "MODBUS_ERROR_RECOVERY_PROTOCOL"), Number::New(isolate, MODBUS_ERROR_RECOVERY_PROTOCOL)); 1002 | 1003 | target->Set(String::NewFromUtf8(isolate, "MODBUS_RTU_MAX_ADU_LENGTH"), Number::New(isolate, MODBUS_RTU_MAX_ADU_LENGTH)); 1004 | target->Set(String::NewFromUtf8(isolate, "MODBUS_RTU_RS232"), Number::New(isolate, MODBUS_RTU_RS232)); 1005 | target->Set(String::NewFromUtf8(isolate, "MODBUS_RTU_RS485"), Number::New(isolate, MODBUS_RTU_RS485)); 1006 | 1007 | target->Set(String::NewFromUtf8(isolate, "MODBUS_TCP_DEFAULT_PORT"), Number::New(isolate, MODBUS_TCP_DEFAULT_PORT)); 1008 | target->Set(String::NewFromUtf8(isolate, "MODBUS_TCP_SLAVE"), Number::New(isolate, MODBUS_TCP_SLAVE)); 1009 | target->Set(String::NewFromUtf8(isolate, "MODBUS_TCP_MAX_ADU_LENGTH"), Number::New(isolate, MODBUS_TCP_MAX_ADU_LENGTH)); 1010 | 1011 | // functions 1012 | target->Set(String::NewFromUtf8(isolate, "new_rtu"), FunctionTemplate::New(isolate, js_new_rtu)->GetFunction()); 1013 | target->Set(String::NewFromUtf8(isolate, "rtu_get_serial_mode"), FunctionTemplate::New(isolate, js_rtu_get_serial_mode)->GetFunction()); 1014 | target->Set(String::NewFromUtf8(isolate, "rtu_set_serial_mode"), FunctionTemplate::New(isolate, js_rtu_set_serial_mode)->GetFunction()); 1015 | target->Set(String::NewFromUtf8(isolate, "rtu_get_rts"), FunctionTemplate::New(isolate, js_rtu_get_rts)->GetFunction()); 1016 | target->Set(String::NewFromUtf8(isolate, "rtu_set_rts"), FunctionTemplate::New(isolate, js_rtu_set_rts)->GetFunction()); 1017 | 1018 | target->Set(String::NewFromUtf8(isolate, "new_tcp"), FunctionTemplate::New(isolate, js_new_tcp)->GetFunction()); 1019 | target->Set(String::NewFromUtf8(isolate, "new_tcp_pi"), FunctionTemplate::New(isolate, js_new_tcp_pi)->GetFunction()); 1020 | 1021 | target->Set(String::NewFromUtf8(isolate, "free"), FunctionTemplate::New(isolate, js_free)->GetFunction()); 1022 | 1023 | target->Set(String::NewFromUtf8(isolate, "get_byte_timeout"), FunctionTemplate::New(isolate, js_get_byte_timeout)->GetFunction()); 1024 | target->Set(String::NewFromUtf8(isolate, "set_byte_timeout"), FunctionTemplate::New(isolate, js_set_byte_timeout)->GetFunction()); 1025 | target->Set(String::NewFromUtf8(isolate, "set_debug"), FunctionTemplate::New(isolate, js_set_debug)->GetFunction()); 1026 | target->Set(String::NewFromUtf8(isolate, "set_error_recovery"), FunctionTemplate::New(isolate, js_set_error_recovery)->GetFunction()); 1027 | target->Set(String::NewFromUtf8(isolate, "get_header_length"), FunctionTemplate::New(isolate, js_get_header_length)->GetFunction()); 1028 | target->Set(String::NewFromUtf8(isolate, "get_response_timeout"), FunctionTemplate::New(isolate, js_get_response_timeout)->GetFunction()); 1029 | target->Set(String::NewFromUtf8(isolate, "set_response_timeout"), FunctionTemplate::New(isolate, js_set_response_timeout)->GetFunction()); 1030 | target->Set(String::NewFromUtf8(isolate, "set_slave"), FunctionTemplate::New(isolate, js_set_slave)->GetFunction()); 1031 | target->Set(String::NewFromUtf8(isolate, "set_socket"), FunctionTemplate::New(isolate, js_set_socket)->GetFunction()); 1032 | target->Set(String::NewFromUtf8(isolate, "get_socket"), FunctionTemplate::New(isolate, js_get_socket)->GetFunction()); 1033 | 1034 | target->Set(String::NewFromUtf8(isolate, "connect"), FunctionTemplate::New(isolate, js_connect)->GetFunction()); 1035 | target->Set(String::NewFromUtf8(isolate, "close"), FunctionTemplate::New(isolate, js_close)->GetFunction()); 1036 | target->Set(String::NewFromUtf8(isolate, "flush"), FunctionTemplate::New(isolate, js_flush)->GetFunction()); 1037 | 1038 | target->Set(String::NewFromUtf8(isolate, "read_bits"), FunctionTemplate::New(isolate, js_read_bits)->GetFunction()); 1039 | target->Set(String::NewFromUtf8(isolate, "read_input_bits"), FunctionTemplate::New(isolate, js_read_input_bits)->GetFunction()); 1040 | target->Set(String::NewFromUtf8(isolate, "read_registers"), FunctionTemplate::New(isolate, js_read_registers)->GetFunction()); 1041 | target->Set(String::NewFromUtf8(isolate, "read_input_registers"), FunctionTemplate::New(isolate, js_read_input_registers)->GetFunction()); 1042 | target->Set(String::NewFromUtf8(isolate, "report_slave_id"), FunctionTemplate::New(isolate, js_report_slave_id)->GetFunction()); 1043 | target->Set(String::NewFromUtf8(isolate, "write_bit"), FunctionTemplate::New(isolate, js_write_bit)->GetFunction()); 1044 | target->Set(String::NewFromUtf8(isolate, "write_register"), FunctionTemplate::New(isolate, js_write_register)->GetFunction()); 1045 | target->Set(String::NewFromUtf8(isolate, "write_bits"), FunctionTemplate::New(isolate, js_write_bits)->GetFunction()); 1046 | target->Set(String::NewFromUtf8(isolate, "write_registers"), FunctionTemplate::New(isolate, js_write_registers)->GetFunction()); 1047 | target->Set(String::NewFromUtf8(isolate, "write_and_read_registers"), FunctionTemplate::New(isolate, js_write_and_read_registers)->GetFunction()); 1048 | target->Set(String::NewFromUtf8(isolate, "send_raw_request"), FunctionTemplate::New(isolate, js_send_raw_request)->GetFunction()); 1049 | target->Set(String::NewFromUtf8(isolate, "receive_confirmation"), FunctionTemplate::New(isolate, js_receive_confirmation)->GetFunction()); 1050 | target->Set(String::NewFromUtf8(isolate, "reply_exception"), FunctionTemplate::New(isolate, js_reply_exception)->GetFunction()); 1051 | 1052 | target->Set(String::NewFromUtf8(isolate, "mapping_new"), FunctionTemplate::New(isolate, js_mapping_new)->GetFunction()); 1053 | target->Set(String::NewFromUtf8(isolate, "mapping_free"), FunctionTemplate::New(isolate, js_mapping_free)->GetFunction()); 1054 | target->Set(String::NewFromUtf8(isolate, "receive"), FunctionTemplate::New(isolate, js_receive)->GetFunction()); 1055 | target->Set(String::NewFromUtf8(isolate, "reply"), FunctionTemplate::New(isolate, js_reply)->GetFunction()); 1056 | 1057 | target->Set(String::NewFromUtf8(isolate, "strerror"), FunctionTemplate::New(isolate, js_strerror)->GetFunction()); 1058 | 1059 | target->Set(String::NewFromUtf8(isolate, "tcp_listen"), FunctionTemplate::New(isolate, js_tcp_listen)->GetFunction()); 1060 | target->Set(String::NewFromUtf8(isolate, "tcp_accept"), FunctionTemplate::New(isolate, js_tcp_accept)->GetFunction()); 1061 | target->Set(String::NewFromUtf8(isolate, "tcp_pi_listen"), FunctionTemplate::New(isolate, js_tcp_pi_listen)->GetFunction()); 1062 | target->Set(String::NewFromUtf8(isolate, "tcp_pi_accept"), FunctionTemplate::New(isolate, js_tcp_pi_accept)->GetFunction()); 1063 | 1064 | // my functions 1065 | target->Set(String::NewFromUtf8(isolate, "map_to_json"), FunctionTemplate::New(isolate, map_to_json)->GetFunction()); 1066 | target->Set(String::NewFromUtf8(isolate, "json_to_map"), FunctionTemplate::New(isolate, json_to_map)->GetFunction()); 1067 | 1068 | target->Set(String::NewFromUtf8(isolate, "tcp_accept_async"), FunctionTemplate::New(isolate, tcp_accept_async)->GetFunction()); 1069 | target->Set(String::NewFromUtf8(isolate, "receive_async"), FunctionTemplate::New(isolate, receive_async)->GetFunction()); 1070 | target->Set(String::NewFromUtf8(isolate, "connect_async"), FunctionTemplate::New(isolate, connect_async)->GetFunction()); 1071 | target->Set(String::NewFromUtf8(isolate, "close_mt"), FunctionTemplate::New(isolate, close_mt)->GetFunction()); 1072 | 1073 | // HEX Decoding stuff 1074 | target->Set(String::NewFromUtf8(isolate, "hex_decode", v8::String::kInternalizedString), FunctionTemplate::New(isolate, hex_decode)->GetFunction()); 1075 | } 1076 | 1077 | void Initialize (Handle exports); 1078 | NODE_MODULE(modbus_binding, init) 1079 | -------------------------------------------------------------------------------- /wscript: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # Davydov Denis 3 | 4 | import Options, Utils 5 | 6 | srcdir = "." 7 | blddir = "build" 8 | VERSION = "0.0.1" 9 | 10 | def set_options(opt): 11 | opt.tool_options("compiler_cxx") 12 | 13 | def configure(conf): 14 | conf.check_tool("compiler_cxx") 15 | conf.check_tool("node_addon") 16 | #conf.check_cxx(lib="modbus", errmsg="Missing libmodbus") 17 | conf.env.append_unique('CXXFLAGS', ["-Wall"]) 18 | 19 | # static 20 | conf.env.append_unique('CXXFLAGS', ["-I../libmodbus/src/"]) 21 | 22 | # shared 23 | #conf.env.append_unique('CXXFLAGS', Utils.cmd_output('pkg-config --cflags --libs libmodbus').split()) 24 | 25 | def build(bld): 26 | obj = bld.new_task_gen("cxx", "shlib", "node_addon") 27 | # add static 28 | bld.env.append_value('LINKFLAGS', '../libmodbus/src/.libs/modbus.o') 29 | bld.env.append_value('LINKFLAGS', '../libmodbus/src/.libs/modbus-data.o') 30 | bld.env.append_value('LINKFLAGS', '../libmodbus/src/.libs/modbus-rtu.o') 31 | bld.env.append_value('LINKFLAGS', '../libmodbus/src/.libs/modbus-tcp.o') 32 | obj.target = "modbus_binding" 33 | obj.source = "src/main.cpp" 34 | #obj.lib = 'modbus' 35 | --------------------------------------------------------------------------------