Developer reference for connecting base stations and rover clients to PrairieRTK.
PrairieRTK operates an NTRIP (Networked Transport of RTCM via Internet Protocol) caster that distributes centimeter-level GNSS correction data across Alberta's base station network. The caster runs as a TCP server on port 2101 and supports up to 200 concurrent connections.
The system provides both single-base corrections (raw RTCM3 from physical stations) and Virtual Reference Station (VRS) corrections interpolated from the full network to your rover's exact position.
prairiertk.polsia.app:2101
PrairieRTK supports both NTRIP v1 and NTRIP v2 request formats.
| Feature | NTRIP v1 | NTRIP v2 |
|---|---|---|
| Source table request | GET / HTTP/1.0 |
GET / HTTP/1.1 |
| Rover (client) request | GET /MOUNT HTTP/1.0 |
GET /MOUNT HTTP/1.1 orPOST /MOUNT HTTP/1.1 |
| Base station (source) | SOURCE password /MOUNT |
|
| Authentication | HTTP Basic (Authorization: Basic <base64>) |
|
| GGA position | Ntrip-GGA: header or NMEA in body |
|
| Success response (client) | ICY 200 OK |
ICY 200 OK |
| Success response (source) | HTTP/1.1 200 OK |
|
Rover clients authenticate via HTTP Basic Authentication. Encode your
credentials as Base64(username:password) and include them in the
Authorization header.
GET /VRS_AB HTTP/1.1 Host: prairiertk.polsia.app Authorization: Basic cm92ZXI6cnRrX3JvdmVy Ntrip-Version: Ntrip/2.0 Ntrip-GGA: $GPGGA,142305.00,...*XX
| Mode | Behavior |
|---|---|
| Authenticated | Users defined in config/users.json — credentials required. Invalid credentials return 401 Unauthorized. |
| Open access | If no users file exists or is empty, all connections are accepted without credentials. |
| HTTP Status | Meaning |
|---|---|
401 Unauthorized | Missing or invalid credentials |
404 Not Found | Mountpoint does not exist |
503 Service Unavailable | Server at max connection capacity |
400 Bad Request | Unrecognized request format |
Request the source table to discover available mountpoints. Send a
GET / request (no mountpoint path) to the caster.
# NTRIP v1 GET / HTTP/1.0 User-Agent: NTRIP MyClient/1.0 # NTRIP v2 GET / HTTP/1.1 Host: prairiertk.polsia.app Ntrip-Version: Ntrip/2.0
SOURCETABLE 200 OK Content-Type: text/plain Server: PrairieRTK-NTRIP/1.0 Content-Length: 432 STR;EDMO_RTCM3;Edmonton;RTCM 3.3;;2;GPS+GLO;PrairieRTK;CAN;53.5461;-113.4938;0;0;PrairieRTK;none;B;N;0; STR;CALG_RTCM3;Calgary;RTCM 3.3;;2;GPS+GLO;PrairieRTK;CAN;51.0447;-114.0719;0;0;PrairieRTK;none;B;N;0; STR;VRS_AB;VRS_AB;RTCM 3.3;;2;GPS+GLO;PrairieRTK;CAN;52.0000;-113.5000;0;0;PrairieRTK;none;B;N;0; ENDSOURCETABLE
| Position | Field | Example | Description |
|---|---|---|---|
| 1 | Type | STR | Always "STR" for stream records |
| 2 | Mountpoint | EDMO_RTCM3 | Name used in GET request path |
| 3 | Identifier | Edmonton | Human-readable city/location |
| 4 | Format | RTCM 3.3 | Data format |
| 6 | Carrier | 2 | 0=None, 1=L1, 2=L1+L2 |
| 7 | Nav System | GPS+GLO | Satellite constellations |
| 8 | Network | PrairieRTK | Network operator |
| 9 | Country | CAN | ISO 3166 code |
| 10 | Latitude | 53.5461 | Station latitude (degrees) |
| 11 | Longitude | -113.4938 | Station longitude (degrees) |
| 16 | Auth | B | B=Basic, N=None, D=Digest |
| 17 | Fee | N | N=No fee, Y=Fee required |
PrairieRTK provides two types of mountpoints:
Direct RTCM3 streams from individual base stations. Each station broadcasts GPS and GLONASS observations. Best when your rover is within ~30 km of the station.
| Mountpoint | Station | Latitude | Longitude | Height (m) |
|---|---|---|---|---|
EDMO_RTCM3 | Edmonton | 53.5461 | -113.4938 | 668.0 |
CALG_RTCM3 | Calgary | 51.0447 | -114.0719 | 1045.0 |
RDDR_RTCM3 | Red Deer | 52.2681 | -113.8112 | 847.0 |
LETH_RTCM3 | Lethbridge | 49.6942 | -112.8328 | 920.0 |
GRDP_RTCM3 | Grande Prairie | 55.1707 | -118.7946 | 669.0 |
| Mountpoint | Type | Description |
|---|---|---|
VRS_AB |
Virtual Reference Station | Network-interpolated corrections computed for your rover's exact position. Requires GGA sentence in the initial request. Works anywhere within the station network. |
VRS_AB for best accuracy across
Alberta. The VRS engine interpolates ionospheric, tropospheric, and geometric corrections
from the 3 nearest base stations using inverse distance weighting (IDW).
To receive RTCM3 corrections as a rover client:
Open a TCP connection to the caster host on port 2101.
# v1 GET request GET /VRS_AB HTTP/1.0 User-Agent: NTRIP MyRover/1.0 Authorization: Basic cm92ZXI6cnRrX3JvdmVy Ntrip-GGA: $GPGGA,142305.00,5232.8086,N,11343.5180,W,4,12,0.8,857.0,M,0.0,M,,*5B # v2 POST request (GGA in body) POST /VRS_AB HTTP/1.1 Host: prairiertk.polsia.app Ntrip-Version: Ntrip/2.0 Authorization: Basic cm92ZXI6cnRrX3JvdmVy $GPGGA,142305.00,5232.8086,N,11343.5180,W,4,12,0.8,857.0,M,0.0,M,,*5B
On success, the caster responds with ICY 200 OK followed by a continuous binary
RTCM3 stream. Each RTCM3 frame starts with the sync byte 0xD3, followed by a
10-bit length field, the message payload, and a 24-bit CRC.
When connected to a VRS mountpoint, periodically send updated GGA sentences as your rover moves. The caster re-computes corrections for the new position. Send the NMEA sentence as raw ASCII on the same TCP connection:
# Send updated position every 10-60 seconds
$GPGGA,142315.00,5232.8100,N,11343.5200,W,4,12,0.8,858.2,M,0.0,M,,*5A
The caster detects $GPGGA or $GNGGA prefixes and triggers new
VRS corrections automatically.
To push RTCM3 observation data from a base station (NTRIP server/source), use the
SOURCE command:
SOURCE <password> /<mountpoint> Source-Agent: NTRIP MyBase/1.0
SOURCE prairie2024 /EDMO_RTCM3 Source-Agent: NTRIP Trimble/5.0
On success, the caster responds with HTTP/1.1 200 OK. After that, send raw
RTCM3 binary frames on the connection. The caster relays data to all subscribed rover clients
on that mountpoint.
NMEA GGA (Global Positioning System Fix Data) sentences tell the VRS engine where your rover is located. This is essential for VRS mountpoints — the caster interpolates corrections specific to your position.
$GPGGA — GPS only$GNGGA — Multi-GNSS (GPS + GLONASS + …)$GLGGA — GLONASS$GPGGA,HHMMSS.ss,DDMM.MMMMM,N|S,DDDMM.MMMMM,E|W,Q,NN,H.H,AAA.A,M,GG.G,M,A.A,RRRR*CC
Field breakdown:
1 HHMMSS.ss UTC time
2 DDMM.MMMMM Latitude (degrees + minutes)
3 N|S North or South
4 DDDMM.MMMMM Longitude (degrees + minutes)
5 E|W East or West
6 Q Fix quality (1=GPS, 2=DGPS, 4=RTK fixed, 5=RTK float)
7 NN Number of satellites
8 H.H HDOP
9 AAA.A Altitude above MSL (meters)
10 M Altitude units
11 GG.G Geoid separation (meters)
12 M Geoid units
13 A.A Age of DGPS data
14 RRRR Reference station ID
* CC Checksum (XOR of chars between $ and *)
You can send your GGA position in two ways:
Ntrip-GGA: $GPGGA,... as an HTTP header in your initial connection request.$GPGGA or $GNGGA and re-triggers VRS computation.PrairieRTK encodes and decodes the following RTCM3 message types:
| Message | Name | Content | Used For |
|---|---|---|---|
1004 |
Extended L1/L2 GPS | GPS pseudorange & carrier-phase on L1 + L2 | Primary GPS corrections |
1005 |
Station ARP | Antenna Reference Point (ECEF X, Y, Z) | Station/VRS position |
1006 |
Station ARP + Height | ECEF position + antenna height | Station position with height |
1012 |
Extended L1/L2 GLONASS | GLONASS pseudorange & carrier-phase on L1 + L2 | GLONASS corrections |
1033 |
Receiver/Antenna Descriptor | Equipment make, model, serial, firmware | Station metadata |
1077 |
GPS MSM7 | Full GPS observations (all signals, high resolution) | High-precision GPS |
1087 |
GLONASS MSM7 | Full GLONASS observations (all signals, high resolution) | High-precision GLONASS |
┌──────────┬────────────┬──────────────┬──────────┐
│ Preamble │ Length │ Payload │ CRC-24Q │
│ 0xD3 │ 10 bits │ N bytes │ 3 bytes │
│ 1 byte │ 2 bytes │ (variable) │ │
└──────────┴────────────┴──────────────┴──────────┘
Total frame size = 3 (header) + N (payload) + 3 (CRC) = N + 6 bytes
The Virtual Reference Station engine creates a synthetic base station at your rover's location by interpolating observations from the surrounding physical network.
minStations)When you connect to VRS_AB, you receive:
| Message | Purpose |
|---|---|
1005 | VRS station position (ECEF) — set to your rover's location |
1004 | GPS L1/L2 observations interpolated for your position |
1012 | GLONASS L1/L2 observations interpolated for your position |
The caster reads from config/config.json on startup:
{
"caster": {
"port": 2101, // TCP listen port
"maxConnections": 200 // Max simultaneous clients
},
"vrs": {
"updateInterval": 1000, // VRS refresh interval (ms)
"minStations": 3, // Minimum bases for VRS computation
"idwPower": 2 // IDW interpolation exponent
},
"logging": {
"level": "info", // error | warn | info | debug
"directory": "logs"
},
"auth": {
"usersFile": "config/users.json"
}
}
Define users in config/users.json:
{
"users": [
{ "username": "rover1", "password": "secure_pass" },
{ "username": "survey", "password": "another_pass" }
]
}
Base stations are registered in config/stations.json:
{
"stations": [
{
"id": "EDMO",
"name": "Edmonton",
"lat": 53.5461,
"lon": -113.4938,
"height": 668.0,
"mountpoint": "EDMO_RTCM3",
"expected_messages": [1004, 1012, 1077, 1087, 1005],
"active": true
}
]
}
# Connect to VRS mountpoint str2str -in ntrip://rover:rtk_rover@prairiertk.polsia.app:2101/VRS_AB \ -out serial://ttyUSB0:115200 # Connect to single-base mountpoint str2str -in ntrip://rover:rtk_rover@prairiertk.polsia.app:2101/EDMO_RTCM3 \ -out serial://ttyUSB0:115200
| Setting | Value |
|---|---|
| Input Type | NTRIP Client |
| Address | prairiertk.polsia.app |
| Port | 2101 |
| Mountpoint | VRS_AB |
| User | Your username |
| Password | Your password |
| Send GGA | Yes (set interval to 10s) |
| Setting | Value |
|---|---|
| Correction Source | Internet (NTRIP) |
| Caster Address | prairiertk.polsia.app |
| Caster Port | 2101 |
| Mountpoint | VRS_AB (or select from source table) |
| Username | Your username |
| Password | Your password |
# Using ntripclient (Linux)
ntripclient \
-s prairiertk.polsia.app \
-r 2101 \
-m VRS_AB \
-u rover \
-p rtk_rover \
-D /dev/ttyACM0 \
-n "$GPGGA,120000.00,5232.8086,N,11343.5180,W,4,12,0.8,857.0,M,0.0,M,,*5B"
const net = require('net');
const socket = net.createConnection({
host: 'prairiertk.polsia.app',
port: 2101
}, () => {
const auth = Buffer.from('rover:rtk_rover').toString('base64');
const gga = '$GPGGA,142305.00,5232.8086,N,11343.5180,W,4,12,0.8,857.0,M,0.0,M,,*5B';
socket.write(
`GET /VRS_AB HTTP/1.1\r\n` +
`Host: prairiertk.polsia.app\r\n` +
`Authorization: Basic ${auth}\r\n` +
`Ntrip-Version: Ntrip/2.0\r\n` +
`Ntrip-GGA: ${gga}\r\n\r\n`
);
});
socket.on('data', (data) => {
// First response: ICY 200 OK\r\n\r\n
// Then: continuous RTCM3 binary frames
console.log(`Received ${data.length} bytes`);
});
socket.on('error', (err) => console.error(err.message));
import socket
import base64
host = 'prairiertk.polsia.app'
port = 2101
mount = 'VRS_AB'
auth = base64.b64encode(b'rover:rtk_rover').decode()
gga = '$GPGGA,142305.00,5232.8086,N,11343.5180,W,4,12,0.8,857.0,M,0.0,M,,*5B'
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect((host, port))
request = (
f'GET /{mount} HTTP/1.1\r\n'
f'Host: {host}\r\n'
f'Authorization: Basic {auth}\r\n'
f'Ntrip-Version: Ntrip/2.0\r\n'
f'Ntrip-GGA: {gga}\r\n\r\n'
)
s.send(request.encode())
# Read response header
header = s.recv(256)
print(header.decode())
# Read RTCM3 binary frames
while True:
data = s.recv(4096)
if not data:
break
print(f'Received {len(data)} bytes of RTCM3 data')