node-red-contrib-ntrip 0.2.3 → 0.2.7
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/.github/dependabot.yml +23 -0
- package/.github/workflows/node.js.yml +22 -21
- package/.github/workflows/release.yml +65 -0
- package/.prettierignore +20 -0
- package/.prettierrc.json +9 -0
- package/CHANGELOG.md +61 -0
- package/CLAUDE.md +73 -0
- package/README.md +145 -18
- package/doc/architecture/README.md +19 -0
- package/doc/architecture/adr/0001-single-registration-file.md +64 -0
- package/doc/architecture/adr/0002-ntrip-uploader-extension.md +71 -0
- package/doc/architecture/adr/0003-two-output-decoder-design.md +73 -0
- package/doc/architecture/adr/0004-stateful-handshake-interception.md +74 -0
- package/doc/architecture/adr/0005-rtcm-partial-frame-buffer.md +87 -0
- package/doc/architecture/adr/0006-nmea-multi-sentence-split.md +66 -0
- package/doc/architecture/adr/0007-mocha-test-helper-stack.md +67 -0
- package/doc/architecture/adr/0008-coordinate-gating-sentinel.md +76 -0
- package/doc/architecture/adr/README.md +18 -0
- package/doc/architecture/architecture-decisions.md +60 -0
- package/doc/architecture/behavioural-design.md +226 -0
- package/doc/architecture/errors-and-weaknesses.md +71 -0
- package/doc/architecture/future-improvements.md +130 -0
- package/doc/architecture/overview.md +77 -0
- package/doc/architecture/refactoring-recommendations.md +114 -0
- package/doc/architecture/statistics.md +118 -0
- package/doc/architecture/structural-design.md +141 -0
- package/eslint.config.js +36 -0
- package/ntrip/99-ntrip.html +207 -31
- package/ntrip/99-ntrip.js +12 -12
- package/ntrip/lib/ntrip-client.js +23 -18
- package/ntrip/nodes/nmea-decoder-node.js +77 -34
- package/ntrip/nodes/nmea-encoder-node.js +68 -47
- package/ntrip/nodes/ntrip-client-node.js +143 -123
- package/ntrip/nodes/rtcm-decoder-node.js +65 -47
- package/package.json +20 -2
- package/test/nmea-decoder.spec.js +146 -0
- package/test/nmea-encoder.spec.js +104 -0
- package/test/rtcm-decoder.spec.js +116 -0
- package/.github/workflows/npm-publish.yml +0 -33
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
# Statistics
|
|
2
|
+
|
|
3
|
+
Snapshot taken at **v0.2.6** (commit `ecf02ba`).
|
|
4
|
+
|
|
5
|
+
## Lines of code
|
|
6
|
+
|
|
7
|
+
### Source
|
|
8
|
+
|
|
9
|
+
| File | LOC |
|
|
10
|
+
|------|----:|
|
|
11
|
+
| [ntrip/99-ntrip.html](../../ntrip/99-ntrip.html) | 467 |
|
|
12
|
+
| [ntrip/nodes/ntrip-client-node.js](../../ntrip/nodes/ntrip-client-node.js) | 182 |
|
|
13
|
+
| [ntrip/nodes/nmea-encoder-node.js](../../ntrip/nodes/nmea-encoder-node.js) | 177 |
|
|
14
|
+
| [ntrip/lib/ntrip-client.js](../../ntrip/lib/ntrip-client.js) | 114 |
|
|
15
|
+
| [ntrip/nodes/nmea-decoder-node.js](../../ntrip/nodes/nmea-decoder-node.js) | 98 |
|
|
16
|
+
| [ntrip/nodes/rtcm-decoder-node.js](../../ntrip/nodes/rtcm-decoder-node.js) | 91 |
|
|
17
|
+
| [ntrip/99-ntrip.js](../../ntrip/99-ntrip.js) | 26 |
|
|
18
|
+
| **Total** | **1155** |
|
|
19
|
+
|
|
20
|
+
- JavaScript-only source: **688 LOC** across 6 files.
|
|
21
|
+
- HTML editor UI: **467 LOC** in one file.
|
|
22
|
+
|
|
23
|
+
### Tests
|
|
24
|
+
|
|
25
|
+
| File | LOC | Tests |
|
|
26
|
+
|------|----:|------:|
|
|
27
|
+
| [test/nmea-decoder.spec.js](../../test/nmea-decoder.spec.js) | 134 | 6 |
|
|
28
|
+
| [test/rtcm-decoder.spec.js](../../test/rtcm-decoder.spec.js) | 108 | 4 |
|
|
29
|
+
| [test/nmea-encoder.spec.js](../../test/nmea-encoder.spec.js) | 96 | 4 |
|
|
30
|
+
| **Total** | **338** | **14** |
|
|
31
|
+
|
|
32
|
+
### Ratios
|
|
33
|
+
|
|
34
|
+
| Metric | Value |
|
|
35
|
+
|--------|------:|
|
|
36
|
+
| Test LOC / JS source LOC | 49 % |
|
|
37
|
+
| Tests per JS source file (4 of 6 covered by specs) | 3.5 avg |
|
|
38
|
+
| Comments + blank lines (rough estimate) | ~20 % of source |
|
|
39
|
+
|
|
40
|
+
## Test suite
|
|
41
|
+
|
|
42
|
+
Run with `npm test`. Latest local run: **14 passing, 0 failing, ~500 ms**.
|
|
43
|
+
|
|
44
|
+
Breakdown:
|
|
45
|
+
|
|
46
|
+
- **NmeaDecoder** (6 specs) — golden GGA decode, multi-sentence split, Buffer
|
|
47
|
+
input, `payload.nmeaMessage` shape, Buffer preservation in error output, no
|
|
48
|
+
`node.error` flood (regression).
|
|
49
|
+
- **NmeaEncoder** (4 specs) — `NmeaMessage` instance passthrough, unknown
|
|
50
|
+
`messageType` routed to error output, missing fields routed to error output,
|
|
51
|
+
empty payload handled.
|
|
52
|
+
- **RtcmDecoder** (4 specs) — golden RTCM 1005 decode, two concatenated frames
|
|
53
|
+
fan out, frame split across two input events reassembled, no `node.error`
|
|
54
|
+
flood under garbage (regression).
|
|
55
|
+
|
|
56
|
+
3 of the 14 specs are explicitly tagged `(regression: …)` and lock in
|
|
57
|
+
previously-shipped bug fixes. Run them in isolation with
|
|
58
|
+
`npx mocha test/**/*.spec.js -g regression`.
|
|
59
|
+
|
|
60
|
+
NtripClient is *not* covered by the suite — it requires a fake TCP server.
|
|
61
|
+
See [Future Improvements](future-improvements.md).
|
|
62
|
+
|
|
63
|
+
## Coverage
|
|
64
|
+
|
|
65
|
+
**Not measured.** No `c8` / `nyc` / Istanbul integration is configured. To
|
|
66
|
+
enable, add `c8` as a dev dep and a `coverage` script (`c8 --reporter=text
|
|
67
|
+
--reporter=html mocha test/**/*.spec.js`). Statement coverage of the three
|
|
68
|
+
spec'd nodes should be ≥ 85 % at the current spec count; the missing 15 % is
|
|
69
|
+
mostly edge-case branches inside `RtcmTransport.decode` failures.
|
|
70
|
+
|
|
71
|
+
## Repository history
|
|
72
|
+
|
|
73
|
+
Snapshot from `git log`:
|
|
74
|
+
|
|
75
|
+
| Metric | Value |
|
|
76
|
+
|--------|------:|
|
|
77
|
+
| Total commits on `main` | 28 |
|
|
78
|
+
| Commits matching `/fix/i` | 8 |
|
|
79
|
+
| Releases tagged in [CHANGELOG.md](../../CHANGELOG.md) | 9 (0.1.0 → 0.2.6) |
|
|
80
|
+
| Bug-fix-only releases (0.2.4 / 0.2.5 / 0.2.6) | 3 (last 14 days) |
|
|
81
|
+
|
|
82
|
+
## Dependencies
|
|
83
|
+
|
|
84
|
+
| Class | Count | Names |
|
|
85
|
+
|-------|------:|-------|
|
|
86
|
+
| Runtime | 3 | `@gnss/nmea`, `@gnss/rtcm`, `ntrip-client` |
|
|
87
|
+
| Dev | 4 | `mocha`, `chai`, `node-red`, `node-red-node-test-helper` |
|
|
88
|
+
| Transitive (dev tree) | ~600 | from `npm audit` |
|
|
89
|
+
|
|
90
|
+
After installing dev deps: `6 vulnerabilities (1 low, 2 moderate, 3 high)` —
|
|
91
|
+
all inside the `node-red` dev tree, none reachable from the published package
|
|
92
|
+
because the runtime dep set is just three packages.
|
|
93
|
+
|
|
94
|
+
## Quality Index
|
|
95
|
+
|
|
96
|
+
A composite, intentionally rough — a way to track movement over time, not an
|
|
97
|
+
absolute scale. Each criterion is scored 0–10; the index is the unweighted
|
|
98
|
+
mean.
|
|
99
|
+
|
|
100
|
+
| Criterion | Score | Reasoning |
|
|
101
|
+
|-----------|------:|-----------|
|
|
102
|
+
| Test coverage (proxy: spec count vs node count) | 7 | 14 specs over 3 of 4 nodes. `NtripClient` untested. |
|
|
103
|
+
| Bug-fix cadence (lower is better, scored inversely) | 5 | 3 patch releases in 2 weeks indicates churn from recent rewrite — settling now. |
|
|
104
|
+
| Documentation completeness | 8 | Per-node help text, README usage notes, this architecture doc. |
|
|
105
|
+
| Type safety | 2 | No TypeScript or JSDoc-with-`@ts-check`. |
|
|
106
|
+
| Lint / style enforcement | 1 | No `eslint` or `prettier`. Style is consistent by convention only. |
|
|
107
|
+
| Dependency hygiene | 7 | 3 runtime deps, 0 known runtime vulns. Dev tree carries `node-red` itself. |
|
|
108
|
+
| CI rigour | 6 | Builds + tests on three Node versions. No coverage gate, no lint gate. |
|
|
109
|
+
| Bus factor | 4 | Single primary maintainer (`Karl-Heinz Wind`). 1 active contributor. |
|
|
110
|
+
| **Overall** | **5.0** | Median: 5.5. Headroom in lint, types, and `NtripClient` coverage. |
|
|
111
|
+
|
|
112
|
+
### How to improve the index quickly
|
|
113
|
+
|
|
114
|
+
- **+1.0 each** — adopting `eslint` (covers Type safety bump via `@ts-check`
|
|
115
|
+
on JSDoc) and adding coverage reporting.
|
|
116
|
+
- **+0.5** — writing one round of `NtripClient` integration specs against a
|
|
117
|
+
fake caster.
|
|
118
|
+
- **+0.5** — pinning dev deps in `package.json` more strictly (`~` instead of `^`).
|
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
# Structural Design
|
|
2
|
+
|
|
3
|
+
## Repository layout
|
|
4
|
+
|
|
5
|
+
```
|
|
6
|
+
node-red-contrib-ntrip/
|
|
7
|
+
├── ntrip/
|
|
8
|
+
│ ├── 99-ntrip.js # Node-RED registration entry point
|
|
9
|
+
│ ├── 99-ntrip.html # Editor UI for all four nodes (forms + help text)
|
|
10
|
+
│ ├── nodes/
|
|
11
|
+
│ │ ├── ntrip-client-node.js
|
|
12
|
+
│ │ ├── rtcm-decoder-node.js
|
|
13
|
+
│ │ ├── nmea-decoder-node.js
|
|
14
|
+
│ │ └── nmea-encoder-node.js
|
|
15
|
+
│ └── lib/
|
|
16
|
+
│ └── ntrip-client.js # Local extension of the upstream ntrip-client package
|
|
17
|
+
├── examples/ # Sample flows (ntripclient.json, sapos.json, upload.json, …)
|
|
18
|
+
├── test/ # Mocha specs (one per node, suffixed .spec.js)
|
|
19
|
+
├── images/ # Screenshots referenced by README.md
|
|
20
|
+
├── doc/architecture/ # This documentation tree
|
|
21
|
+
├── package.json
|
|
22
|
+
├── package-lock.json
|
|
23
|
+
├── CHANGELOG.md
|
|
24
|
+
├── CLAUDE.md
|
|
25
|
+
└── README.md
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
## Module dependency graph
|
|
29
|
+
|
|
30
|
+
```
|
|
31
|
+
┌────────────────────────┐
|
|
32
|
+
│ ntrip/99-ntrip.js │ (Node-RED entry, registerType x 4)
|
|
33
|
+
└─────────┬──────────────┘
|
|
34
|
+
│ require
|
|
35
|
+
┌─────────┴────────────────────────────────────────────────────────┐
|
|
36
|
+
▼ ▼ ▼ ▼ │
|
|
37
|
+
ntrip-client- rtcm-decoder- nmea-decoder- nmea-encoder- │
|
|
38
|
+
node.js node.js node.js node.js │
|
|
39
|
+
│ │ │ │ │
|
|
40
|
+
│ require │ require │ require │ require │
|
|
41
|
+
▼ ▼ ▼ ▼ │
|
|
42
|
+
lib/ntrip- @gnss/rtcm @gnss/nmea @gnss/nmea │
|
|
43
|
+
client.js │
|
|
44
|
+
│ │
|
|
45
|
+
│ require │
|
|
46
|
+
▼ │
|
|
47
|
+
ntrip-client (npm package, upstream) │
|
|
48
|
+
│
|
|
49
|
+
▼
|
|
50
|
+
package.json reads
|
|
51
|
+
version into log line
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
## File responsibilities
|
|
55
|
+
|
|
56
|
+
### Entry layer
|
|
57
|
+
|
|
58
|
+
| File | Responsibility |
|
|
59
|
+
|------|----------------|
|
|
60
|
+
| [ntrip/99-ntrip.js](../../ntrip/99-ntrip.js) | Imports each node implementation. Registers the four types with `RED.nodes.registerType`. Declares the `credentials` block for `NtripClient`. Reads the package version from `package.json` and logs it. |
|
|
61
|
+
| [ntrip/99-ntrip.html](../../ntrip/99-ntrip.html) | Per-node `registerType` call (client side), the configuration `<template>`, and the help text shown in Node-RED's info sidebar. The credentials block is duplicated here — Node-RED requires both. |
|
|
62
|
+
|
|
63
|
+
### Node implementations
|
|
64
|
+
|
|
65
|
+
| File | Type | Inputs | Outputs |
|
|
66
|
+
|------|------|--------|---------|
|
|
67
|
+
| [ntrip/nodes/ntrip-client-node.js](../../ntrip/nodes/ntrip-client-node.js) | `NtripClient` | 1 | 1 (data from caster + optional pass-through of writes) |
|
|
68
|
+
| [ntrip/nodes/rtcm-decoder-node.js](../../ntrip/nodes/rtcm-decoder-node.js) | `RtcmDecoder` | 1 | 2 (decoded, error) |
|
|
69
|
+
| [ntrip/nodes/nmea-decoder-node.js](../../ntrip/nodes/nmea-decoder-node.js) | `NmeaDecoder` | 1 | 2 (decoded, error) |
|
|
70
|
+
| [ntrip/nodes/nmea-encoder-node.js](../../ntrip/nodes/nmea-encoder-node.js) | `NmeaEncoder` | 1 | 2 (encoded, error) |
|
|
71
|
+
|
|
72
|
+
All four follow the same skeleton:
|
|
73
|
+
|
|
74
|
+
```javascript
|
|
75
|
+
module.exports = function (RED) {
|
|
76
|
+
function Node(config) {
|
|
77
|
+
RED.nodes.createNode(this, config);
|
|
78
|
+
const node = this;
|
|
79
|
+
node.<counter>Received = 0;
|
|
80
|
+
node.invalidMessagesReceived = 0;
|
|
81
|
+
|
|
82
|
+
// ... wire up the on('input') handler, possibly an external resource
|
|
83
|
+
|
|
84
|
+
this.on('close', function (done) {
|
|
85
|
+
// cleanup
|
|
86
|
+
node.status({});
|
|
87
|
+
done();
|
|
88
|
+
});
|
|
89
|
+
}
|
|
90
|
+
return Node;
|
|
91
|
+
};
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
### Library layer
|
|
95
|
+
|
|
96
|
+
[ntrip/lib/ntrip-client.js](../../ntrip/lib/ntrip-client.js) — a thin local
|
|
97
|
+
adapter around the upstream `ntrip-client` npm package. Exposes two factories:
|
|
98
|
+
|
|
99
|
+
- `createDownloader(options)` — returns the upstream `NtripClient` unchanged.
|
|
100
|
+
- `createUploader(options)` — returns a subclass `NtripClientUploader` that
|
|
101
|
+
overrides `_connect()` to switch the handshake string by `authmode`
|
|
102
|
+
(`legacy`, `hybrid`, `ntripv1`, `ntripv2`). The constructor also rejects
|
|
103
|
+
CR/LF in `mountpoint`/`username`/`password` to prevent header injection.
|
|
104
|
+
|
|
105
|
+
The override pattern is a full replacement of the parent's `_connect`, not a
|
|
106
|
+
delegation — see [ADR-0002](adr/0002-ntrip-uploader-extension.md) for the
|
|
107
|
+
rationale and trade-offs.
|
|
108
|
+
|
|
109
|
+
## Class / type hierarchy
|
|
110
|
+
|
|
111
|
+
```
|
|
112
|
+
ntrip-client (npm)
|
|
113
|
+
└── NtripClient # download
|
|
114
|
+
└── NtripClientUploader (lib/ntrip-client.js) # upload
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
No other classes are defined in this package; every Node-RED node is a plain
|
|
118
|
+
function passed to `registerType`, and decoder/encoder state lives on the node
|
|
119
|
+
instance via simple property assignment (`node.pendingBuffer`, `node.messagesReceived`).
|
|
120
|
+
|
|
121
|
+
## Coupling
|
|
122
|
+
|
|
123
|
+
- **High cohesion within each node file.** A node's input handler, status
|
|
124
|
+
updates, and close handler are co-located. There is no shared mutable state
|
|
125
|
+
across node instances.
|
|
126
|
+
- **No cross-node imports.** The decoders do not know about `NtripClient` and
|
|
127
|
+
vice versa; they communicate only through Node-RED wires at flow runtime.
|
|
128
|
+
- **Two seams to the outside world:**
|
|
129
|
+
- The `ntrip-client` upstream package (via [lib/ntrip-client.js](../../ntrip/lib/ntrip-client.js)).
|
|
130
|
+
- `@gnss/rtcm` and `@gnss/nmea` for codec work.
|
|
131
|
+
- **Implicit coupling between [99-ntrip.js](../../ntrip/99-ntrip.js) and [99-ntrip.html](../../ntrip/99-ntrip.html)** — both must declare the `credentials` block, and the registered node-type names must match exactly. The HTML form field IDs (`node-input-host`, `node-input-port`, …) must align with the property names read in the JS (`config.host`, `config.port`, …).
|
|
132
|
+
|
|
133
|
+
## Distribution shape
|
|
134
|
+
|
|
135
|
+
- `node-red.nodes` in [package.json](../../package.json) points only at
|
|
136
|
+
`ntrip/99-ntrip.js` — Node-RED loads that file, which transitively pulls in
|
|
137
|
+
everything else.
|
|
138
|
+
- Runtime dependencies: `@gnss/nmea`, `@gnss/rtcm`, `ntrip-client`. No transient
|
|
139
|
+
runtime dependency on Node-RED itself.
|
|
140
|
+
- Dev-only dependencies: `mocha`, `chai` (CJS v4), `node-red`,
|
|
141
|
+
`node-red-node-test-helper`.
|
package/eslint.config.js
ADDED
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const js = require('@eslint/js');
|
|
4
|
+
const globals = require('globals');
|
|
5
|
+
const prettierConfig = require('eslint-config-prettier');
|
|
6
|
+
|
|
7
|
+
module.exports = [
|
|
8
|
+
{
|
|
9
|
+
ignores: ['node_modules/**', 'examples/**', 'doc/**', 'ntrip/99-ntrip.html'],
|
|
10
|
+
},
|
|
11
|
+
js.configs.recommended,
|
|
12
|
+
prettierConfig,
|
|
13
|
+
{
|
|
14
|
+
languageOptions: {
|
|
15
|
+
ecmaVersion: 2022,
|
|
16
|
+
sourceType: 'commonjs',
|
|
17
|
+
globals: {
|
|
18
|
+
...globals.node,
|
|
19
|
+
},
|
|
20
|
+
},
|
|
21
|
+
rules: {
|
|
22
|
+
'no-unused-vars': ['warn', { argsIgnorePattern: '^_', varsIgnorePattern: '^_' }],
|
|
23
|
+
'no-console': 'off',
|
|
24
|
+
'no-prototype-builtins': 'off',
|
|
25
|
+
},
|
|
26
|
+
},
|
|
27
|
+
{
|
|
28
|
+
files: ['test/**/*.js'],
|
|
29
|
+
languageOptions: {
|
|
30
|
+
globals: {
|
|
31
|
+
...globals.node,
|
|
32
|
+
...globals.mocha,
|
|
33
|
+
},
|
|
34
|
+
},
|
|
35
|
+
},
|
|
36
|
+
];
|
package/ntrip/99-ntrip.html
CHANGED
|
@@ -13,8 +13,8 @@
|
|
|
13
13
|
passthrough: { value: false, required: false },
|
|
14
14
|
|
|
15
15
|
port: { value: 2101, required: false, validate:function(v) { return ((v === "") || (RED.validators.number(v) && (v >= 0) && (v <= 65535))) }},
|
|
16
|
-
host: { value:"" },
|
|
17
|
-
mountpoint: { value:"" },
|
|
16
|
+
host: { value:"", required: true, validate: function(v) { return typeof v === "string" && v.trim().length > 0; } },
|
|
17
|
+
mountpoint: { value:"", required: true, validate: function(v) { return typeof v === "string" && v.trim().length > 0; } },
|
|
18
18
|
interval: { value: 1000, required: false, validate:function(v) { return ((v === "") || (RED.validators.number(v) && (v >= 0) && (v <= 100000))) }},
|
|
19
19
|
xcoordinate: { value: 0, required: false, validate:function(v) { return ((v === "") || (RED.validators.number(v) )) }},
|
|
20
20
|
ycoordinate: { value: 0, required: false, validate:function(v) { return ((v === "") || (RED.validators.number(v) )) }},
|
|
@@ -108,7 +108,7 @@
|
|
|
108
108
|
</div>
|
|
109
109
|
<div class="form-row">
|
|
110
110
|
<label for="node-input-password"><i class="fa fa-key"></i> Password</label>
|
|
111
|
-
<input type="
|
|
111
|
+
<input type="password" id="node-input-password" placeholder="Enter the password here">
|
|
112
112
|
</div>
|
|
113
113
|
|
|
114
114
|
<hr align="middle"/>
|
|
@@ -140,18 +140,83 @@
|
|
|
140
140
|
</script>
|
|
141
141
|
|
|
142
142
|
<script type="text/x-red" data-help-name="NtripClient">
|
|
143
|
-
<p>
|
|
143
|
+
<p>Connects to an NTRIP caster as either a client (download) or a server (upload).
|
|
144
|
+
In download mode the node emits the bytes received from the caster (typically
|
|
145
|
+
RTCM correction data). In upload mode the node forwards bytes from its input
|
|
146
|
+
to the caster on the configured mountpoint.</p>
|
|
144
147
|
|
|
145
148
|
<h3>Configuration</h3>
|
|
149
|
+
<dl class="message-properties">
|
|
150
|
+
<dt>Host <span class="property-type">string</span></dt>
|
|
151
|
+
<dd>Hostname or IP address of the NTRIP caster (e.g. <code>rtk2go.com</code>).</dd>
|
|
152
|
+
|
|
153
|
+
<dt>Port <span class="property-type">number</span></dt>
|
|
154
|
+
<dd>TCP port of the caster. Defaults to <code>2101</code>.</dd>
|
|
155
|
+
|
|
156
|
+
<dt>Mountpoint <span class="property-type">string</span></dt>
|
|
157
|
+
<dd>The stream name on the caster. Enter the name without a leading slash.</dd>
|
|
158
|
+
|
|
159
|
+
<dt>Mode <span class="property-type">"download" | "upload"</span></dt>
|
|
160
|
+
<dd><b>Download</b>: receive correction data from the caster.<br>
|
|
161
|
+
<b>Upload</b>: push correction data to a mountpoint on the caster.</dd>
|
|
162
|
+
|
|
163
|
+
<dt>Authentication Mode <span class="property-type">string</span></dt>
|
|
164
|
+
<dd>Upload only. Selects the handshake the caster expects:
|
|
165
|
+
<ul>
|
|
166
|
+
<li><b>Legacy (Plain Text)</b> — <code>SOURCE</code> with no auth header, accepted by rtk2go.</li>
|
|
167
|
+
<li><b>Legacy (Basic Auth)</b> — <code>SOURCE</code> plus an <code>Authorization: Basic</code> header, accepted by SNIP.</li>
|
|
168
|
+
<li><b>NTRIP V1</b> — <code>POST</code> over HTTP/1.0 with Basic Auth.</li>
|
|
169
|
+
<li><b>NTRIP V2</b> — <code>POST</code> over HTTP/1.1 with Basic Auth and <code>Ntrip-Version: Ntrip/2.0</code>.</li>
|
|
170
|
+
</ul>
|
|
171
|
+
</dd>
|
|
172
|
+
|
|
173
|
+
<dt>Pass through data <span class="property-type">boolean</span></dt>
|
|
174
|
+
<dd>Upload only. If enabled, bytes written to the caster are also re-emitted
|
|
175
|
+
on the node's output for downstream processing.</dd>
|
|
176
|
+
|
|
177
|
+
<dt>Username / Password <span class="property-type">credential</span></dt>
|
|
178
|
+
<dd>Caster credentials. Stored encrypted by Node-RED.</dd>
|
|
179
|
+
|
|
180
|
+
<dt>X / Y / Z <span class="property-type">number</span></dt>
|
|
181
|
+
<dd>Optional ECEF coordinate triple. If set (i.e. not all zero) the underlying
|
|
182
|
+
client generates and periodically sends a NMEA <code>GGA</code> sentence to
|
|
183
|
+
the caster — required by some VRS / network-RTK services.</dd>
|
|
184
|
+
|
|
185
|
+
<dt>Interval <span class="property-type">number (ms)</span></dt>
|
|
186
|
+
<dd>Period between <code>GGA</code> emissions when X/Y/Z are configured.</dd>
|
|
187
|
+
</dl>
|
|
146
188
|
|
|
147
|
-
<p>Description of the device.</p>
|
|
148
|
-
|
|
149
189
|
<h3>Inputs</h3>
|
|
150
|
-
<
|
|
151
|
-
|
|
190
|
+
<dl class="message-properties">
|
|
191
|
+
<dt>payload <span class="property-type">Buffer | string</span></dt>
|
|
192
|
+
<dd>Written verbatim to the caster (upload mode). In download mode the input
|
|
193
|
+
is typically only used to refresh the position via the form below.</dd>
|
|
194
|
+
|
|
195
|
+
<dt>payload <span class="property-type">number[]</span></dt>
|
|
196
|
+
<dd>An array <code>[x, y, z]</code> is interpreted as a coordinate update and
|
|
197
|
+
forwarded to <code>client.setXYZ()</code> rather than being written to the
|
|
198
|
+
caster. Useful for streaming position fixes into the GGA emitter.</dd>
|
|
199
|
+
</dl>
|
|
200
|
+
|
|
152
201
|
<h3>Outputs</h3>
|
|
153
|
-
<
|
|
154
|
-
|
|
202
|
+
<dl class="message-properties">
|
|
203
|
+
<dt>payload <span class="property-type">Buffer</span></dt>
|
|
204
|
+
<dd>Bytes received from the caster. In download mode this is the correction
|
|
205
|
+
stream (RTCM). In upload mode with <i>Pass through data</i> enabled, written
|
|
206
|
+
bytes are also re-emitted here.</dd>
|
|
207
|
+
</dl>
|
|
208
|
+
|
|
209
|
+
<h3>Status</h3>
|
|
210
|
+
<p>The node shows <code>connecting…</code> until the caster acknowledges the
|
|
211
|
+
handshake with <code>ICY 200 OK</code>. After that it shows the running
|
|
212
|
+
<code>Rx</code> / <code>Tx</code> counters. A red badge indicates a rejected
|
|
213
|
+
connection, a missing mountpoint, or a write failure.</p>
|
|
214
|
+
|
|
215
|
+
<h3>Details</h3>
|
|
216
|
+
<p>The first <code>ICY 200 OK</code>, <code>ICY 406</code>, or
|
|
217
|
+
<code>SOURCETABLE 200 OK</code> reply is consumed by the node to set its
|
|
218
|
+
status; any RTCM bytes that arrive in the same TCP segment as the
|
|
219
|
+
<code>ICY 200 OK</code> reply are forwarded on the output.</p>
|
|
155
220
|
</script>
|
|
156
221
|
|
|
157
222
|
|
|
@@ -186,18 +251,52 @@
|
|
|
186
251
|
</script>
|
|
187
252
|
|
|
188
253
|
<script type="text/x-red" data-help-name="RtcmDecoder">
|
|
189
|
-
<p>
|
|
254
|
+
<p>Decodes binary RTCM (Radio Technical Commission for Maritime Services)
|
|
255
|
+
correction frames using the <code>@gnss/rtcm</code> library. One input
|
|
256
|
+
message may contain a single frame or several concatenated frames; each
|
|
257
|
+
decoded frame is emitted as its own output message.</p>
|
|
258
|
+
<p>The node keeps an internal buffer so frames that straddle TCP packet
|
|
259
|
+
boundaries are reassembled across consecutive input events.</p>
|
|
190
260
|
|
|
191
261
|
<h3>Configuration</h3>
|
|
262
|
+
<dl class="message-properties">
|
|
263
|
+
<dt>Description <span class="property-type">string</span></dt>
|
|
264
|
+
<dd>Optional label shown in the flow editor.</dd>
|
|
265
|
+
</dl>
|
|
192
266
|
|
|
193
|
-
<p>Description of the device.</p>
|
|
194
|
-
|
|
195
267
|
<h3>Inputs</h3>
|
|
196
|
-
<
|
|
197
|
-
|
|
268
|
+
<dl class="message-properties">
|
|
269
|
+
<dt>payload <span class="property-type">Buffer</span></dt>
|
|
270
|
+
<dd>Raw RTCM bytes, typically produced by the upstream <i>NTRIP Client</i>
|
|
271
|
+
node. Strings are accepted but converted via <code>Buffer.from</code>.</dd>
|
|
272
|
+
</dl>
|
|
273
|
+
|
|
198
274
|
<h3>Outputs</h3>
|
|
199
|
-
<p
|
|
200
|
-
<
|
|
275
|
+
<p>Two outputs: successfully decoded frames go to the first; decode failures go to the second.</p>
|
|
276
|
+
<ol class="node-ports">
|
|
277
|
+
<li>Decoded
|
|
278
|
+
<dl class="message-properties">
|
|
279
|
+
<dt>payload.rtcm <span class="property-type">number</span></dt>
|
|
280
|
+
<dd>The RTCM message type identifier (e.g. <code>1005</code>, <code>1077</code>).</dd>
|
|
281
|
+
<dt>payload.messageType <span class="property-type">string</span></dt>
|
|
282
|
+
<dd>The constructor name of the decoded message (e.g. <code>1005</code> → <code>Stationary</code>).</dd>
|
|
283
|
+
<dt>payload.message <span class="property-type">object</span></dt>
|
|
284
|
+
<dd>The decoded message object with all fields.</dd>
|
|
285
|
+
<dt>payload.input <span class="property-type">Buffer</span></dt>
|
|
286
|
+
<dd>The bytes consumed for this frame.</dd>
|
|
287
|
+
</dl>
|
|
288
|
+
</li>
|
|
289
|
+
<li>Error
|
|
290
|
+
<dl class="message-properties">
|
|
291
|
+
<dt>payload.error <span class="property-type">Error</span></dt>
|
|
292
|
+
<dd>The exception thrown by the decoder.</dd>
|
|
293
|
+
<dt>payload.input <span class="property-type">Buffer</span></dt>
|
|
294
|
+
<dd>The remaining buffer at the point of failure.</dd>
|
|
295
|
+
<dt>payload.inputString <span class="property-type">string</span></dt>
|
|
296
|
+
<dd>A debug string representation of the buffer.</dd>
|
|
297
|
+
</dl>
|
|
298
|
+
</li>
|
|
299
|
+
</ol>
|
|
201
300
|
</script>
|
|
202
301
|
|
|
203
302
|
<!-- ------------------------------------------------------------------------------------------ -->
|
|
@@ -231,18 +330,52 @@
|
|
|
231
330
|
</script>
|
|
232
331
|
|
|
233
332
|
<script type="text/x-red" data-help-name="NmeaDecoder">
|
|
234
|
-
<p>
|
|
333
|
+
<p>Decodes NMEA 0183 sentences (<code>GGA</code>, <code>RMC</code>,
|
|
334
|
+
<code>GSV</code>, …) using the <code>@gnss/nmea</code> library. A single
|
|
335
|
+
input message may contain several <code>\r\n</code>-delimited sentences;
|
|
336
|
+
each is decoded individually and emitted as its own output message.</p>
|
|
235
337
|
|
|
236
338
|
<h3>Configuration</h3>
|
|
339
|
+
<dl class="message-properties">
|
|
340
|
+
<dt>Description <span class="property-type">string</span></dt>
|
|
341
|
+
<dd>Optional label shown in the flow editor.</dd>
|
|
342
|
+
</dl>
|
|
237
343
|
|
|
238
|
-
<p>Description of the device.</p>
|
|
239
|
-
|
|
240
344
|
<h3>Inputs</h3>
|
|
241
|
-
<
|
|
242
|
-
|
|
345
|
+
<dl class="message-properties">
|
|
346
|
+
<dt>payload <span class="property-type">string | Buffer</span></dt>
|
|
347
|
+
<dd>A NMEA sentence or a chunk containing several sentences. Buffers are
|
|
348
|
+
decoded as UTF-8.</dd>
|
|
349
|
+
<dt>payload.nmeaMessage <span class="property-type">string | Buffer</span></dt>
|
|
350
|
+
<dd>Alternative location for the input. If <code>msg.payload</code> is an
|
|
351
|
+
object with an <code>nmeaMessage</code> property, that value is used
|
|
352
|
+
instead of <code>msg.payload</code> itself.</dd>
|
|
353
|
+
</dl>
|
|
354
|
+
|
|
243
355
|
<h3>Outputs</h3>
|
|
244
|
-
<p
|
|
245
|
-
<
|
|
356
|
+
<p>Two outputs: successfully decoded sentences go to the first; decode failures go to the second.</p>
|
|
357
|
+
<ol class="node-ports">
|
|
358
|
+
<li>Decoded
|
|
359
|
+
<dl class="message-properties">
|
|
360
|
+
<dt>payload.messageType <span class="property-type">string</span></dt>
|
|
361
|
+
<dd>Sentence type in upper case, e.g. <code>GGA</code>, <code>RMC</code>, <code>GSV</code>.</dd>
|
|
362
|
+
<dt>payload.nmeaMessage <span class="property-type">object</span></dt>
|
|
363
|
+
<dd>The decoded sentence object with all fields.</dd>
|
|
364
|
+
<dt>payload.input <span class="property-type">string</span></dt>
|
|
365
|
+
<dd>The raw sentence as it was parsed.</dd>
|
|
366
|
+
</dl>
|
|
367
|
+
</li>
|
|
368
|
+
<li>Error
|
|
369
|
+
<dl class="message-properties">
|
|
370
|
+
<dt>payload.error <span class="property-type">Error | string</span></dt>
|
|
371
|
+
<dd>The exception or reason for the decode failure.</dd>
|
|
372
|
+
<dt>payload.input <span class="property-type">string</span></dt>
|
|
373
|
+
<dd>The sentence that failed to decode.</dd>
|
|
374
|
+
<dt>payload.inputString <span class="property-type">string</span></dt>
|
|
375
|
+
<dd>String representation of the input for logging.</dd>
|
|
376
|
+
</dl>
|
|
377
|
+
</li>
|
|
378
|
+
</ol>
|
|
246
379
|
</script>
|
|
247
380
|
|
|
248
381
|
<!-- ------------------------------------------------------------------------------------------ -->
|
|
@@ -276,16 +409,59 @@
|
|
|
276
409
|
</script>
|
|
277
410
|
|
|
278
411
|
<script type="text/x-red" data-help-name="NmeaEncoder">
|
|
279
|
-
<p>
|
|
412
|
+
<p>Encodes a NMEA sentence object back to its textual form using the
|
|
413
|
+
<code>@gnss/nmea</code> library. The inverse of the <i>NMEA Decoder</i>
|
|
414
|
+
node — useful for round-tripping or for emitting handcrafted sentences
|
|
415
|
+
(e.g. a <code>GGA</code> fix into an NTRIP uploader).</p>
|
|
280
416
|
|
|
281
417
|
<h3>Configuration</h3>
|
|
418
|
+
<dl class="message-properties">
|
|
419
|
+
<dt>Description <span class="property-type">string</span></dt>
|
|
420
|
+
<dd>Optional label shown in the flow editor.</dd>
|
|
421
|
+
</dl>
|
|
282
422
|
|
|
283
|
-
<p>Description of the device.</p>
|
|
284
|
-
|
|
285
423
|
<h3>Inputs</h3>
|
|
286
|
-
<
|
|
287
|
-
|
|
424
|
+
<dl class="message-properties">
|
|
425
|
+
<dt>payload.messageType <span class="property-type">string</span></dt>
|
|
426
|
+
<dd>Sentence type, e.g. <code>GGA</code>, <code>RMC</code>, <code>VTG</code>,
|
|
427
|
+
<code>GSV</code>, <code>ZDA</code>. Case-insensitive. Supported types:
|
|
428
|
+
<code>DTM</code>, <code>GBS</code>, <code>GGA</code>, <code>GLL</code>,
|
|
429
|
+
<code>GNS</code>, <code>GRS</code>, <code>GSA</code>, <code>GST</code>,
|
|
430
|
+
<code>GSV</code>, <code>RMC</code>, <code>THS</code>, <code>TXT</code>,
|
|
431
|
+
<code>VHW</code>, <code>VLW</code>, <code>VPW</code>, <code>VTG</code>,
|
|
432
|
+
<code>ZDA</code>, plus <code>OBJECT</code> for the generic
|
|
433
|
+
<code>NmeaMessageUnknown</code> form.</dd>
|
|
434
|
+
<dt>payload.nmeaMessage <span class="property-type">object | NmeaMessage</span></dt>
|
|
435
|
+
<dd>The sentence content. Either a plain field object that matches the
|
|
436
|
+
target sentence schema, or an already-constructed <code>NmeaMessage</code>
|
|
437
|
+
instance (which is forwarded as-is to <code>NmeaTransport.encode</code>).</dd>
|
|
438
|
+
</dl>
|
|
439
|
+
|
|
288
440
|
<h3>Outputs</h3>
|
|
289
|
-
<p
|
|
290
|
-
<
|
|
441
|
+
<p>Two outputs: successfully encoded sentences go to the first; failures go to the second.</p>
|
|
442
|
+
<ol class="node-ports">
|
|
443
|
+
<li>Encoded
|
|
444
|
+
<dl class="message-properties">
|
|
445
|
+
<dt>payload.nmeaMessage <span class="property-type">string</span></dt>
|
|
446
|
+
<dd>The encoded NMEA sentence (including <code>$</code> prefix and
|
|
447
|
+
checksum).</dd>
|
|
448
|
+
<dt>payload.messageType <span class="property-type">string</span></dt>
|
|
449
|
+
<dd>The sentence type, echoed back as it was supplied.</dd>
|
|
450
|
+
<dt>payload.input <span class="property-type">object</span></dt>
|
|
451
|
+
<dd>The original input object.</dd>
|
|
452
|
+
</dl>
|
|
453
|
+
</li>
|
|
454
|
+
<li>Error
|
|
455
|
+
<dl class="message-properties">
|
|
456
|
+
<dt>payload.error <span class="property-type">Error | string</span></dt>
|
|
457
|
+
<dd>The exception or reason for the failure. Unknown
|
|
458
|
+
<code>messageType</code> values, missing input fields, and
|
|
459
|
+
encoder errors all surface here.</dd>
|
|
460
|
+
<dt>payload.input <span class="property-type">any</span></dt>
|
|
461
|
+
<dd>The offending input.</dd>
|
|
462
|
+
<dt>payload.inputString <span class="property-type">string</span></dt>
|
|
463
|
+
<dd>String representation of the input for logging.</dd>
|
|
464
|
+
</dl>
|
|
465
|
+
</li>
|
|
466
|
+
</ol>
|
|
291
467
|
</script>
|
package/ntrip/99-ntrip.js
CHANGED
|
@@ -1,27 +1,27 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Created by Karl-Heinz Wind
|
|
3
|
-
**/
|
|
2
|
+
* Created by Karl-Heinz Wind
|
|
3
|
+
**/
|
|
4
4
|
|
|
5
5
|
module.exports = function (RED) {
|
|
6
|
-
|
|
7
|
-
|
|
6
|
+
'use strict';
|
|
7
|
+
|
|
8
8
|
const pkg = require('./../package.json');
|
|
9
9
|
RED.log.info('node-red-contrib-ntrip version: v' + pkg.version);
|
|
10
10
|
|
|
11
11
|
const NtripClientNode = require('./nodes/ntrip-client-node.js')(RED);
|
|
12
|
-
RED.nodes.registerType(
|
|
12
|
+
RED.nodes.registerType('NtripClient', NtripClientNode, {
|
|
13
13
|
credentials: {
|
|
14
|
-
username: { type:
|
|
15
|
-
password: { type:
|
|
16
|
-
}
|
|
14
|
+
username: { type: 'text' },
|
|
15
|
+
password: { type: 'password' },
|
|
16
|
+
},
|
|
17
17
|
});
|
|
18
18
|
|
|
19
19
|
const RtcmDecoderNode = require('./nodes/rtcm-decoder-node.js')(RED);
|
|
20
|
-
RED.nodes.registerType(
|
|
20
|
+
RED.nodes.registerType('RtcmDecoder', RtcmDecoderNode);
|
|
21
21
|
|
|
22
22
|
const NmeaDecoderNode = require('./nodes/nmea-decoder-node.js')(RED);
|
|
23
|
-
RED.nodes.registerType(
|
|
23
|
+
RED.nodes.registerType('NmeaDecoder', NmeaDecoderNode);
|
|
24
24
|
|
|
25
25
|
const NmeaEncoderNode = require('./nodes/nmea-encoder-node.js')(RED);
|
|
26
|
-
RED.nodes.registerType(
|
|
27
|
-
}
|
|
26
|
+
RED.nodes.registerType('NmeaEncoder', NmeaEncoderNode);
|
|
27
|
+
};
|