node-red-contrib-ntrip 0.1.2 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,6 +1,9 @@
1
1
  # Changelog
2
2
  All notable changes to this project will be documented in this file.
3
3
 
4
+ ## [0.2.0]
5
+ ### Refactored nodes: data can be forwarded to NTRIP caster now.
6
+
4
7
  ## [0.1.2]
5
8
  ### Fixed readme
6
9
 
@@ -0,0 +1 @@
1
+ [{"id":"86db72067d6de6eb","type":"debug","z":"95fe791a9c2e02fb","name":"debug 42","active":false,"tosidebar":true,"console":false,"tostatus":false,"complete":"false","statusVal":"","statusType":"auto","x":1100,"y":260,"wires":[]},{"id":"bcb4f78f38f73614","type":"debug","z":"95fe791a9c2e02fb","name":"debug 44","active":false,"tosidebar":true,"console":false,"tostatus":false,"complete":"false","statusVal":"","statusType":"auto","x":1100,"y":300,"wires":[]},{"id":"ce248cbbb81fedc7","type":"debug","z":"95fe791a9c2e02fb","name":"debug 45","active":false,"tosidebar":true,"console":false,"tostatus":false,"complete":"false","statusVal":"","statusType":"auto","x":1100,"y":360,"wires":[]},{"id":"1e5f02ac026876e5","type":"debug","z":"95fe791a9c2e02fb","name":"debug 46","active":false,"tosidebar":true,"console":false,"tostatus":false,"complete":"false","statusVal":"","statusType":"auto","x":1100,"y":420,"wires":[]},{"id":"51cd0b92e167630a","type":"function","z":"95fe791a9c2e02fb","name":"1005","func":"if(msg.payload.rtcm == 1005)\n{\n return msg;\n}\n","outputs":1,"timeout":0,"noerr":0,"initialize":"","finalize":"","libs":[],"x":1070,"y":140,"wires":[["19d95eb7c3fc0838"]]},{"id":"19d95eb7c3fc0838","type":"debug","z":"95fe791a9c2e02fb","name":"debug 48","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"false","statusVal":"","statusType":"auto","x":1220,"y":140,"wires":[]},{"id":"307341cb4389ee70","type":"NtripClient","z":"95fe791a9c2e02fb","description":"RTK2Go Westendorf","port":"2101","host":"rtk2go.com","mountpoint":"Westendorf","interval":1000,"x":590,"y":340,"wires":[["91bc83d1480be9ce","fa8ecd8584cd2497"]]},{"id":"91bc83d1480be9ce","type":"RtcmDecoder","z":"95fe791a9c2e02fb","description":"","x":880,"y":260,"wires":[["86db72067d6de6eb","51cd0b92e167630a"],["bcb4f78f38f73614"]]},{"id":"fa8ecd8584cd2497","type":"NmeaDecoder","z":"95fe791a9c2e02fb","description":"","x":880,"y":400,"wires":[["ce248cbbb81fedc7"],["1e5f02ac026876e5"]]}]
@@ -0,0 +1 @@
1
+ [{"id":"86db72067d6de6eb","type":"debug","z":"95fe791a9c2e02fb","name":"debug 42","active":false,"tosidebar":true,"console":false,"tostatus":false,"complete":"false","statusVal":"","statusType":"auto","x":1100,"y":260,"wires":[]},{"id":"bcb4f78f38f73614","type":"debug","z":"95fe791a9c2e02fb","name":"debug 44","active":false,"tosidebar":true,"console":false,"tostatus":false,"complete":"false","statusVal":"","statusType":"auto","x":1100,"y":300,"wires":[]},{"id":"ce248cbbb81fedc7","type":"debug","z":"95fe791a9c2e02fb","name":"debug 45","active":false,"tosidebar":true,"console":false,"tostatus":false,"complete":"false","statusVal":"","statusType":"auto","x":1100,"y":360,"wires":[]},{"id":"1e5f02ac026876e5","type":"debug","z":"95fe791a9c2e02fb","name":"debug 46","active":false,"tosidebar":true,"console":false,"tostatus":false,"complete":"false","statusVal":"","statusType":"auto","x":1100,"y":420,"wires":[]},{"id":"51cd0b92e167630a","type":"function","z":"95fe791a9c2e02fb","name":"1005","func":"if(msg.payload.rtcm == 1005)\n{\n return msg;\n}\n","outputs":1,"timeout":0,"noerr":0,"initialize":"","finalize":"","libs":[],"x":1070,"y":140,"wires":[["19d95eb7c3fc0838"]]},{"id":"19d95eb7c3fc0838","type":"debug","z":"95fe791a9c2e02fb","name":"debug 48","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"false","statusVal":"","statusType":"auto","x":1220,"y":140,"wires":[]},{"id":"91bc83d1480be9ce","type":"RtcmDecoder","z":"95fe791a9c2e02fb","description":"","x":880,"y":260,"wires":[["86db72067d6de6eb","51cd0b92e167630a"],["bcb4f78f38f73614"]]},{"id":"fa8ecd8584cd2497","type":"NmeaDecoder","z":"95fe791a9c2e02fb","description":"","x":880,"y":400,"wires":[["ce248cbbb81fedc7"],["1e5f02ac026876e5"]]},{"id":"ae86ea193a1bd420","type":"NtripClient","z":"95fe791a9c2e02fb","description":"Sapos Bayern","port":"2101","host":"sapos-rtk.bayern.de","mountpoint":"VRS_3_4G_BY","interval":1000,"x":560,"y":320,"wires":[["fa8ecd8584cd2497","91bc83d1480be9ce"]]},{"id":"41c59401a86de38e","type":"function","z":"95fe791a9c2e02fb","name":"SetXYZ","func":"// Setting XYZ sends a GGA sentence to the NTRIP caster.\n// This is needed to start RTCM streaming.\n// These are only example coordinates. Replace them with yours.\nmsg.payload = [4200023.620, 778279.450, 4721519.716];\nreturn msg;","outputs":1,"timeout":0,"noerr":0,"initialize":"","finalize":"","libs":[],"x":360,"y":320,"wires":[["ae86ea193a1bd420"]]},{"id":"9694b5cce6bfc44c","type":"inject","z":"95fe791a9c2e02fb","name":"","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"","payloadType":"date","x":180,"y":320,"wires":[["41c59401a86de38e"]]}]
@@ -0,0 +1 @@
1
+ [{"id":"381976b4de0e6794","type":"tcp in","z":"95fe791a9c2e02fb","name":"","server":"client","host":"r4c.fritz.box","port":"5016","datamode":"stream","datatype":"buffer","newline":"","topic":"","trim":false,"base64":false,"tls":"","x":210,"y":100,"wires":[["bb4a5f23f761c055"]]},{"id":"9f96be356ff5bf3f","type":"debug","z":"95fe791a9c2e02fb","name":"debug 58","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","statusVal":"","statusType":"auto","x":660,"y":100,"wires":[]},{"id":"bb4a5f23f761c055","type":"NtripClient","z":"95fe791a9c2e02fb","description":"SNIP","mode":"upload","port":"3000","host":"localhost","mountpoint":"Westendorf","interval":1000,"x":430,"y":100,"wires":[["9f96be356ff5bf3f"]]}]
@@ -8,6 +8,7 @@
8
8
  color: '#C0DEED',
9
9
  defaults: {
10
10
  description: { value:"" },
11
+ mode: { value: "download", required: true },
11
12
  port: { value: 2101, required: false, validate:function(v) { return ((v === "") || (RED.validators.number(v) && (v >= 0) && (v <= 65535))) }},
12
13
  host: { value:"" },
13
14
  mountpoint: { value:"" },
@@ -20,7 +21,7 @@
20
21
  username: { type: "text" },
21
22
  password: { type: "password" },
22
23
  },
23
- inputs: 0,
24
+ inputs: 1,
24
25
  outputs: 1,
25
26
  icon: "bridge.png",
26
27
  paletteLabel: "NTRIP Client",
@@ -29,6 +30,21 @@
29
30
  },
30
31
  labelStyle: function() {
31
32
  return this.description?"node_label_italic":"";
33
+ },
34
+ oneditprepare: function() {
35
+ // download or upload
36
+ var updateMode = function() {
37
+ var mode = $("#node-input-mode").val();
38
+ if (mode == "download") {
39
+ //$("#coordinates").show();
40
+ } else if (mode == "upload"){
41
+ //$("#coordinates").hide();
42
+ } else {
43
+ //$("#coordinates").hide();
44
+ }
45
+ };
46
+ updateMode();
47
+ $("#node-input-mode").change(updateMode);
32
48
  }
33
49
  });
34
50
 
@@ -36,11 +52,26 @@
36
52
 
37
53
  <script type="text/x-red" data-template-name="NtripClient">
38
54
 
55
+ <div class="form-row">
56
+ <label for="node-input-description"><i class="fa fa-comment"></i> Description</label>
57
+ <input type="text" id="node-input-description" placeholder="The description of the node (optional)">
58
+ </div>
59
+
39
60
  <div class="form-row">
40
61
  <label for="node-input-host"><i class="fa fa-tag"></i> NTRIP Server</label>
41
62
  <input type="text" id="node-input-host" placeholder="The hostname or the IP address of the NTRIP server">
42
63
  </div>
43
64
 
65
+ <div class="form-row">
66
+ <label for="node-input-mode"><i class="fa fa-link"></i> Mode</label>
67
+ <select id="node-input-mode" style="width:70%">
68
+ <option value="download">Download</option>
69
+ <option value="upload">Upload</option>
70
+ </select>
71
+ </div>
72
+
73
+ <hr align="middle"/>
74
+
44
75
  <div class="form-row">
45
76
  <label for="node-input-port"><i class="fa fa-phone"></i> Port</label>
46
77
  <input type="text" id="node-input-port" placeholder="The network port to open e.g. 2101">
@@ -87,12 +118,6 @@
87
118
  </div>
88
119
  </div>
89
120
 
90
- <hr align="middle"/>
91
-
92
- <div class="form-row">
93
- <label for="node-input-description"><i class="fa fa-comment"></i> Description</label>
94
- <input type="text" id="node-input-description" placeholder="The description of the node (optional)">
95
- </div>
96
121
  </script>
97
122
 
98
123
  <script type="text/x-red" data-help-name="NtripClient">
@@ -103,10 +128,10 @@
103
128
  <p>Description of the device.</p>
104
129
 
105
130
  <h3>Inputs</h3>
106
- <p>.</p>
131
+ <p>Content is directly passed to the ntrip server.</p>
107
132
 
108
133
  <h3>Outputs</h3>
109
- <p>.</p>
134
+ <p>Messages received from the ntrip server.</p>
110
135
  <p><code>msg.payload</code></p>
111
136
  </script>
112
137
 
package/ntrip/99-ntrip.js CHANGED
@@ -5,76 +5,10 @@
5
5
  module.exports = function (RED) {
6
6
  "use strict";
7
7
 
8
- const { RtcmTransport, RtcmMessage, RtcmMessageType } = require('@gnss/rtcm');
9
- const { NmeaTransport, NmeaMessageUnknown } = require('@gnss/nmea');
10
- const { NtripClient } = require('ntrip-client');
8
+ const pkg = require('./../package.json');
9
+ RED.log.info('node-red-contrib-ntrip version: v' + pkg.version);
11
10
 
12
- // --------------------------------------------------------------------------------------------
13
- // NTRIP client node.
14
- function NtripClientNode(config) {
15
- RED.nodes.createNode(this, config);
16
- let node = this;
17
- node.messagesReceived = 0;
18
-
19
- if(config.host !== undefined ) {
20
-
21
- let options = {
22
- host: config.host,
23
- port: config.port || 2101,
24
- mountpoint: config.mountpoint,
25
- username: node.credentials.username,
26
- password: node.credentials.password,
27
- interval: config.interval,
28
- };
29
-
30
- let x = config.xcoordinate;
31
- let y = config.ycoordinate;
32
- let z = config.zcoordinate;
33
-
34
- if (x !== undefined && x !== 0 &&
35
- y !== undefined && y !== 0 &&
36
- z !== undefined && z !== 0) {
37
- options.xyz = [x, y, z];
38
- }
39
-
40
- const client = new NtripClient(options);
41
-
42
- client.on('data', (data) => {
43
- node.messagesReceived++;
44
- node.status({
45
- fill: 'green',
46
- shape: 'ring',
47
- text: 'Messages ' + node.messagesReceived,
48
- });
49
-
50
- let msg = {
51
- payload : data
52
- }
53
- node.send(msg);
54
- });
55
-
56
- client.on('close', () => {
57
- node.log('Closed NTRIP connection.');
58
- });
59
-
60
- client.on('error', (err) => {
61
- node.log(err);
62
- });
63
-
64
- client.run();
65
- node.status({
66
- fill: 'green',
67
- shape: 'ring',
68
- text: 'ok',
69
- });
70
-
71
- this.on('close', function(done) {
72
- client.close();
73
- node.status({});
74
- done();
75
- });
76
- }
77
- }
11
+ const NtripClientNode = require('./nodes/ntrip-client-node.js')(RED);
78
12
  RED.nodes.registerType("NtripClient", NtripClientNode, {
79
13
  credentials: {
80
14
  username: { type: "text" },
@@ -82,127 +16,9 @@ module.exports = function (RED) {
82
16
  }
83
17
  });
84
18
 
85
-
86
- // --------------------------------------------------------------------------------------------
87
- // RTCM decoder node.
88
- function RtcmDecoderNode(config) {
89
- RED.nodes.createNode(this, config);
90
- let node = this;
91
- node.rtcmMessagesReceived = 0;
92
- node.invalidMessagesReceived = 0;
93
-
94
- this.on('input', function (msg) {
95
-
96
- let buffer = msg.payload;
97
- try
98
- {
99
- do {
100
- let message;
101
- let length;
102
- [message, length] = RtcmTransport.decode(buffer);
103
-
104
- let messageType = message.constructor.name.replace('RtcmMessage', '');
105
-
106
- let msg = {
107
- payload : {
108
- rtcm : message.messageType,
109
- messageType : messageType,
110
- message : message,
111
- input : buffer,
112
- length : length
113
- }
114
- };
115
-
116
- node.send([msg, null]);
117
- node.rtcmMessagesReceived++;
118
-
119
- // find next message in buffer.
120
- buffer = buffer.slice(length);
121
- if(buffer.length == 0){
122
- done = true;
123
- }
124
- } while(!done);
125
- }
126
- catch(ex)
127
- {
128
- let msg = {
129
- payload : {
130
- error : ex,
131
- input : buffer,
132
- }
133
- };
134
- node.send([null, msg]);
135
- node.invalidMessagesReceived++;
136
- }
137
-
138
- node.status({
139
- fill: 'green',
140
- shape: 'ring',
141
- text: 'RTCM: ' + node.rtcmMessagesReceived + ' Invalid: ' + node.invalidMessagesReceived,
142
- });
143
- });
144
-
145
- this.on('close', function(done) {
146
- node.status({});
147
- done();
148
- });
149
- }
19
+ const RtcmDecoderNode = require('./nodes/rtcm-decoder-node.js')(RED);
150
20
  RED.nodes.registerType("RtcmDecoder", RtcmDecoderNode);
151
21
 
152
- // --------------------------------------------------------------------------------------------
153
- // NMEA decoder node.
154
- function NmeaDecoderNode(config) {
155
- RED.nodes.createNode(this, config);
156
- let node = this;
157
- node.nmeaMessagesReceived = 0;
158
- node.invalidMessagesReceived = 0;
159
-
160
- this.on('input', function (msg) {
161
-
162
- let buffer = msg.payload;
163
- if(Buffer.isBuffer(buffer)){
164
- buffer = buffer.toString();
165
- }
166
-
167
- try
168
- {
169
- let message = NmeaTransport.decode(buffer);
170
- let messageType = message.constructor.name.replace('NmeaMessage', '').toUpperCase();
171
-
172
- let msg = {
173
- payload : {
174
- messageType : messageType,
175
- message : message,
176
- input : buffer
177
- },
178
- };
179
-
180
- node.send([msg, null]);
181
- node.nmeaMessagesReceived++;
182
- }
183
- catch(ex)
184
- {
185
- let msg = {
186
- payload : {
187
- error : ex,
188
- input : buffer,
189
- }
190
- };
191
- node.send([null, msg]);
192
- node.invalidMessagesReceived++;
193
- }
194
-
195
- node.status({
196
- fill: 'green',
197
- shape: 'ring',
198
- text: 'NMEA: ' + node.nmeaMessagesReceived + ' Invalid: ' + node.invalidMessagesReceived,
199
- });
200
- });
201
-
202
- this.on('close', function(done) {
203
- node.status({});
204
- done();
205
- });
206
- }
22
+ const NmeaDecoderNode = require('./nodes/nmea-decoder-node.js')(RED);
207
23
  RED.nodes.registerType("NmeaDecoder", NmeaDecoderNode);
208
24
  }
@@ -0,0 +1,87 @@
1
+ // Code is a modified client taken from here https://github.com/dxhbiz/ntrip-client.
2
+ 'use strict';
3
+
4
+ const { NtripClient } = require('ntrip-client');
5
+ const net = require('net');
6
+
7
+ // Orginal class is extended to be able to send data to the caster.
8
+ class NtripClientUploader extends NtripClient {
9
+ constructor(options) {
10
+ super(options);
11
+ }
12
+
13
+ _connect() {
14
+ if (this.isClose) {
15
+ return;
16
+ }
17
+
18
+ // init connection of client
19
+ this.client = net.createConnection({
20
+ host: this.host,
21
+ port: this.port
22
+ });
23
+
24
+ // on timeout event
25
+ this.client.on('timeout', () => {
26
+ this._onError('socket timeouted');
27
+ });
28
+
29
+ // on connect event
30
+ this.client.on('connect', () => {
31
+ const mountpoint = this.mountpoint;
32
+ const username = this.username;
33
+ const password = this.password;
34
+
35
+ let data;
36
+ if (this.username === '' && this.password === '') {
37
+ data = `SOURCE ${mountpoint}\r\n\r\n`;
38
+ }
39
+ else {
40
+ const authorization = Buffer.from(
41
+ username + ':' + password,
42
+ 'utf8'
43
+ ).toString('base64');
44
+
45
+ data = `SOURCE ${mountpoint}\r\nAuthorization: Basic ${authorization}\r\n\r\n`;
46
+ }
47
+
48
+ this.client.write(data);
49
+ });
50
+
51
+ // on data event
52
+ this.client.on('data', (data) => {
53
+ this._onData(data);
54
+ });
55
+
56
+ // on end event
57
+ this.client.on('end', () => {
58
+ this._onError('socket ended');
59
+ });
60
+
61
+ // on close event
62
+ this.client.on('close', () => {
63
+ this._onError('socket closed');
64
+ });
65
+
66
+ // on error event
67
+ this.client.on('error', (err) => {
68
+ // TODO: check for code = ECONNREFUSED
69
+ this._onError(err);
70
+ });
71
+
72
+ this.client.setTimeout(this.timeout);
73
+ }
74
+ }
75
+
76
+ function createDownloader(options) {
77
+ return new NtripClient(options)
78
+ }
79
+
80
+ function createUploader(options) {
81
+ return new NtripClientUploader(options)
82
+ }
83
+
84
+ module.exports = {
85
+ createDownloader,
86
+ createUploader
87
+ };
@@ -0,0 +1,62 @@
1
+ module.exports = function (RED) {
2
+ 'use strict';
3
+
4
+ const { NmeaTransport, NmeaMessageUnknown } = require('@gnss/nmea');
5
+
6
+ function NmeaDecoderNode(config) {
7
+ RED.nodes.createNode(this, config);
8
+ let node = this;
9
+ node.nmeaMessagesReceived = 0;
10
+ node.invalidMessagesReceived = 0;
11
+
12
+ this.on('input', function (msg) {
13
+
14
+ let buffer = msg.payload;
15
+ if(Buffer.isBuffer(buffer)){
16
+ buffer = buffer.toString();
17
+ }
18
+
19
+ try
20
+ {
21
+ let message = NmeaTransport.decode(buffer);
22
+ let messageType = message.constructor.name.replace('NmeaMessage', '').toUpperCase();
23
+
24
+ let msg = {
25
+ payload : {
26
+ messageType : messageType,
27
+ message : message,
28
+ input : buffer
29
+ },
30
+ };
31
+
32
+ node.send([msg, null]);
33
+ node.nmeaMessagesReceived++;
34
+ }
35
+ catch(ex)
36
+ {
37
+ let msg = {
38
+ payload : {
39
+ error : ex,
40
+ input : buffer,
41
+ inputString : buffer.toString()
42
+ }
43
+ };
44
+ node.send([null, msg]);
45
+ node.invalidMessagesReceived++;
46
+ }
47
+
48
+ node.status({
49
+ fill: 'green',
50
+ shape: 'ring',
51
+ text: 'NMEA: ' + node.nmeaMessagesReceived + ' Invalid: ' + node.invalidMessagesReceived,
52
+ });
53
+ });
54
+
55
+ this.on('close', function(done) {
56
+ node.status({});
57
+ done();
58
+ });
59
+ }
60
+
61
+ return NmeaDecoderNode;
62
+ };
@@ -0,0 +1,136 @@
1
+ module.exports = function (RED) {
2
+ 'use strict';
3
+
4
+ const NtripClient = require("../lib/ntrip-client.js");
5
+ const NtripServerOkReply = 'ICY 200 OK';
6
+ const NtripServerMissingMountpoint = 'SOURCETABLE 200 OK';
7
+
8
+ function NtripClientNode(config) {
9
+ RED.nodes.createNode(this, config);
10
+ let node = this;
11
+ node.messagesReceived = 0;
12
+ let host = config.host;
13
+ let port = config.port || 2101;
14
+ let mountpoint = config.mountpoint;
15
+ let mode = config.mode || "download";
16
+
17
+ let client;
18
+ if(host !== undefined ) {
19
+
20
+ let options = {
21
+ host: host,
22
+ port: port,
23
+ mountpoint: mountpoint,
24
+ username: node.credentials.username,
25
+ password: node.credentials.password,
26
+ interval: config.interval,
27
+ };
28
+
29
+ // Depending on the caster the clients need to provide the location via GGA sentence.
30
+ let x = config.xcoordinate;
31
+ let y = config.ycoordinate;
32
+ let z = config.zcoordinate;
33
+
34
+ if (x !== undefined && x !== 0 &&
35
+ y !== undefined && y !== 0 &&
36
+ z !== undefined && z !== 0) {
37
+ options.xyz = [x, y, z];
38
+ }
39
+
40
+ if (mode === 'download') {
41
+ // Clients only consume ntrip data.
42
+ client = NtripClient.createDownloader(options);
43
+ }
44
+ else if (mode === 'upload') {
45
+ // Uploaders send RTCM data to a mountpoint so that clients can consume it.
46
+ client = NtripClient.createUploader(options);
47
+ }
48
+ else {
49
+ node.error('Mode not supported ' + mode);
50
+ }
51
+
52
+ client.on('data', (data) => {
53
+ node.messagesReceived++;
54
+ node.status({
55
+ fill: 'green',
56
+ shape: 'ring',
57
+ text: 'Messages ' + node.messagesReceived,
58
+ });
59
+
60
+ let msg = {
61
+ payload : data
62
+ }
63
+
64
+ // check if ICY 200 OK
65
+ const response = data.toString();
66
+ if (response.startsWith(NtripServerOkReply)) {
67
+ node.status({
68
+ fill: 'green',
69
+ shape: 'ring',
70
+ text: 'NTRIP server connected.',
71
+ });
72
+ }
73
+ else if (response.startsWith(NtripServerMissingMountpoint)) {
74
+ node.status({
75
+ fill: 'red',
76
+ shape: 'ring',
77
+ text: 'No mountpont ' + mountpoint,
78
+ });
79
+ node.error('No mountpoint: ' + response);
80
+ }
81
+ else {
82
+ node.send(msg);
83
+ }
84
+ });
85
+
86
+ client.on('close', () => {
87
+ node.log('Closed NTRIP connection.');
88
+ });
89
+
90
+ client.on('error', (error) => {
91
+ if (error instanceof AggregateError) {
92
+ error.errors.forEach((e, i) => {
93
+ node.log(`Error ${i + 1}: ${e.message}`);
94
+ node.error('Error: ' + e.message);
95
+ });
96
+ } else {
97
+ node.log(error);
98
+ node.error('Error: ' + error);
99
+ }
100
+ });
101
+
102
+ client.run();
103
+ node.status({
104
+ fill: 'green',
105
+ shape: 'ring',
106
+ text: 'ok',
107
+ });
108
+
109
+ this.on('input', async function (msg) {
110
+ if (msg.payload) {
111
+ try {
112
+ let data = msg.payload;
113
+ if (Array.isArray(data)) {
114
+ client.setXYZ(data);
115
+ }
116
+ else {
117
+ client.write(data);
118
+ }
119
+
120
+ } catch (error) {
121
+ node.status({ fill: 'red', shape: 'ring', text: error });
122
+ node.error('Failed to write data: ' + error, error);
123
+ }
124
+ }
125
+ });
126
+
127
+ this.on('close', function(done) {
128
+ client.close();
129
+ node.status({});
130
+ done();
131
+ });
132
+ }
133
+ }
134
+
135
+ return NtripClientNode;
136
+ };
@@ -0,0 +1,72 @@
1
+ module.exports = function (RED) {
2
+ 'use strict';
3
+
4
+ const { RtcmTransport, RtcmMessage, RtcmMessageType } = require('@gnss/rtcm');
5
+
6
+ function RtcmDecoderNode(config) {
7
+ RED.nodes.createNode(this, config);
8
+ let node = this;
9
+ node.rtcmMessagesReceived = 0;
10
+ node.invalidMessagesReceived = 0;
11
+
12
+ this.on('input', function (msg) {
13
+
14
+ let done = false;
15
+ let buffer = msg.payload;
16
+ try
17
+ {
18
+ do {
19
+ let message;
20
+ let length;
21
+ [message, length] = RtcmTransport.decode(buffer);
22
+
23
+ let messageType = message.constructor.name.replace('RtcmMessage', '');
24
+
25
+ let msg = {
26
+ payload : {
27
+ rtcm : message.messageType,
28
+ messageType : messageType,
29
+ message : message,
30
+ input : buffer,
31
+ length : length
32
+ }
33
+ };
34
+
35
+ node.send([msg, null]);
36
+ node.rtcmMessagesReceived++;
37
+
38
+ // find next message in buffer.
39
+ buffer = buffer.slice(length);
40
+ if(buffer.length == 0){
41
+ done = true;
42
+ }
43
+ } while(!done);
44
+ }
45
+ catch(ex)
46
+ {
47
+ let msg = {
48
+ payload : {
49
+ error : ex,
50
+ input : buffer,
51
+ inputString : buffer.toString()
52
+ }
53
+ };
54
+ node.send([null, msg]);
55
+ node.invalidMessagesReceived++;
56
+ }
57
+
58
+ node.status({
59
+ fill: 'green',
60
+ shape: 'ring',
61
+ text: 'RTCM: ' + node.rtcmMessagesReceived + ' Invalid: ' + node.invalidMessagesReceived,
62
+ });
63
+ });
64
+
65
+ this.on('close', function(done) {
66
+ node.status({});
67
+ done();
68
+ });
69
+ }
70
+
71
+ return RtcmDecoderNode;
72
+ };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "node-red-contrib-ntrip",
3
- "version": "0.1.2",
3
+ "version": "0.2.0",
4
4
  "description": "Node for ntrip and rtcm handling.",
5
5
  "node-red": {
6
6
  "version": ">=0.1.0",
@@ -19,7 +19,7 @@
19
19
  ],
20
20
  "repository": {
21
21
  "type": "git",
22
- "url": "https://github.com/windkh/node-red-contrib-ntrip"
22
+ "url": "git+https://github.com/windkh/node-red-contrib-ntrip.git"
23
23
  },
24
24
  "author": "Karl-Heinz Wind",
25
25
  "license": "MIT",