Columbus P-70 Ultra — iOS BLE Developer Guide

Audience: iOS engineers building a custom app that connects to a Columbus P-70 Ultra RTK GNSS receiver over Bluetooth Low Energy
Platform: iOS 15+ recommended (CoreBluetooth)
Receiver: Columbus P-70 Ultra (BK / Polaris BK166X family — not u-blox)
Status: Field-proven integration notes for GATT connect, NMEA download, RTCM uplink, Rover/Base role HEX, fixed Base ASCII, and Flash save

This document is a neutral third-party integration guide. It describes the BLE interface and the BK / $POLCFG… / NMEA / RTCM traffic needed to use P-70 Ultra from your own iOS app. Official Columbus manuals and the P-70 Ultra interface description remain the primary references for product policy and chip protocol details. This guide explains what to do; implement the CoreBluetooth and protocol details in your own code.

Related guide: The Columbus EX-1 iOS BLE Developer Guide covers the same BLE transport family on a u-blox ZED-F9P receiver. Do not reuse EX-1 UBX (CFG-TMODE3, CFG-MSG, CFG-CFG, NAV-PVT, NAV-SVIN) on P-70.


Table of contents

  1. What you can build
  2. Architecture overview
  3. Critical: which BLE name to use
  4. GATT profile
  5. iOS project setup
  6. Minimal path: scan → connect → NMEA
  7. Implementing the BLE client
  8. Parsing the notify stream
  9. NMEA position parsing
  10. RTK Rover: write RTCM3 corrections
  11. Command framing: BK HEX and $POLCFG…
  12. Role configuration: Rover / Base
  13. Permanent save ($POLCFGSAVE)
  14. Recommended transaction rules
  15. Accuracy estimates (HPPOSLLH)
  16. Output rate (1 / 5 / 10 / 20 Hz)
  17. Pitfalls checklist
  18. EX-1 vs P-70 quick diff

1. What you can build

Level Capability
A Discover P-70 Ultra, connect, receive NMEA, show lat/lon/fix
B Inject RTCM3 corrections over BLE (RTK Rover)
C Switch Rover / Base with official BK HEX sequences; wait for automatic Base lock (GGA quality 7); optionally set a fixed Base with $POLCFGBASE, then optionally $POLCFGSAVE

You do not send NavStarTool JSON (Config_Rover_*.Json / Config_Base.Json) over BLE. Those files are for the Windows tool over USB / SPP. Live configuration on BLE uses BK binary frames (42 4B …) and ASCII $POLCFG… lines written to the same characteristic that carries NMEA.


2. Architecture overview

iOS App (Central)  ←── Notify FFF1: NMEA (+ BK / RTCM) ──  P-70 Ultra NTRIP BLE
                   ─── Write FFF1: RTCM3 and/or BK / $POLCFG… ───►  Service FFF0 / Char FFF1
  • iPhone / iPad = BLE Central (CBCentralManager)
  • P-70 Ultra = BLE Peripheral
  • Downlink (receiver → app): primarily NMEA 0183 text (v4.11 family); may be interleaved with BK binary (sync 42 4B) and RTCM3 (preamble D3) when Base / raw modes are active
  • Uplink (app → receiver): RTCM3 binary for corrections, and/or BK HEX / $POLCFG… for configuration

Baud rate of the internal UART behind the BLE bridge is not something your app sets (factory default on the wired channel is often 230400). Use ATT MTU / maximumWriteValueLength for write chunking.

Chip protocol note: P-70 Ultra uses a BK / Polaris command set. EX-1’s u-blox UBX path does not apply.


3. Critical: which BLE name to use

P-70 Ultra advertises two Bluetooth interfaces:

Advertised name Use for your app? Notes
P-70 Ultra NTRIP BLE Yes — always use this Supports NMEA download and RTCM3 / command write (full RTK workflow)
P-70 Ultra BLE (no NTRIP) No (for RTK / config) Positioning-only channel; do not rely on it for RTCM uplink or role writes

Matching rule: connect only when the advertised / peripheral name has prefix P-70 Ultra NTRIP BLE.

Do not identify P-70 only by service UUID FFF0. Several Columbus models share FFF0 / FFF1. Always combine:

  1. Name prefix P-70 Ultra NTRIP BLE
  2. Then discover service FFF0 and characteristic FFF1

Official naming length reminder: P-70 Ultra NTRIP BLE is the NTRIP channel; P-70 Ultra BLE is the short non-NTRIP name.


4. GATT profile

Item Value
Service UUID 0000FFF0-0000-1000-8000-00805F9B34FB (16-bit FFF0)
Characteristic UUID 0000FFF1-0000-1000-8000-00805F9B34FB (16-bit FFF1)
Notify / Indicate Required for GNSS stream
Write Same characteristic; P-70 documents Notify + Write Without Response

Documented Columbus behavior for this family: one characteristic for both directions (UART-over-GATT style). The BLE hardware design is in the same family as EX-1; the command language behind the bridge differs.

Connection sequence:

  1. Scan peripherals (do not filter by service UUID alone).
  2. Keep only names with prefix P-70 Ultra NTRIP BLE.
  3. Connect; discover service FFF0, then characteristic FFF1.
  4. Verify notify or indicate is available; enable notifications.
  5. Start buffering and parsing notification data.
  6. Use a connection timeout around 20 seconds.

5. iOS project setup

Info.plist

  • Set NSBluetoothAlwaysUsageDescription to a clear user-facing reason (connect to a Columbus P-70 Ultra GNSS receiver).
  • Optionally add UIBackgroundModes → bluetooth-central if you need brief background streaming or reconnect.

Capabilities

  • Enable Background Modes → Uses Bluetooth LE accessories only if you need background central reconnect / notify.
  • Background scanning is restricted on iOS; plan for foreground discovery and optional restore identifier if you need reconnect after kill/relaunch.

Entitlements / privacy

No special Apple entitlement beyond the standard Bluetooth usage description is required for central mode. Test on a physical iPhone; Simulator is not useful for real P-70 hardware.


6. Minimal path: scan → connect → NMEA

Goal: show a live fix outdoors.

  1. Power on P-70 Ultra with clear sky view.
  2. Scan and select P-70 Ultra NTRIP BLE.
  3. Subscribe to FFF1 notifications.
  4. Buffer bytes into lines ending with CR/LF.
  5. Parse GGA / RMC sentences (talker may be GN, GP, GL, etc.).
  6. Display latitude, longitude, altitude, fix quality.

Factory / default Rover-style profiles typically emit RMC / GGA / GSA / GSV. Example address forms: $GNGGA, $GNRMC.

You may also see Polaris proprietary $… / $BKCHIP,… lines; treat them as identity / diagnostics, not as a substitute for GGA.


7. Implementing the BLE client

Build a small CoreBluetooth central that:

  1. Creates CBCentralManager and waits for .poweredOn.
  2. Scans without relying on service UUID filters for discovery (name filter is primary).
  3. Connects the chosen peripheral and discovers FFF0 / FFF1.
  4. Enables notify on FFF1 and forwards each update to your parsers.
  5. Exposes a write path that chunks payloads with maximumWriteValueLength(for:) (floor around 20 bytes is a safe minimum if the stack reports a tiny value).

Write type guidance: P-70’s NTRIP BLE characteristic is documented as write without response. Prefer that property when present. If a firmware build also exposes with-response, either is acceptable for short ASCII commands; for continuous RTCM, without-response is the expected path. Always fall back to whichever write property exists.

Cancel an in-flight connect after ~20 seconds if the link never reaches connected + notifying.

After connect, P-70 may need 1–3 seconds before a steady NMEA stream appears — do not treat the first quiet window as an immediate data-silence failure.


8. Parsing the notify stream

Notifications are not guaranteed to be one NMEA sentence per callback. A single callback may contain a partial sentence, multiple sentences, or NMEA mixed with BK frames and/or RTCM3.

Practical demux strategy

  1. Position-only app: keep printable ASCII plus CR/LF; replace other bytes with a line break so binary traffic does not corrupt UTF-8 line assembly; emit complete lines that start with $.
  2. Base / command ACK / RTCM verification / accuracy: keep a raw byte buffer and run parallel framers:
    • NMEA / ASCII: starts with $, ends with \r\n (or detect $OK / $FAIL tokens even when fragmented)
    • BK: sync 42 4B, then class/length/payload per the interface description
    • RTCM3: preamble D3, 10-bit length, payload, 24-bit CRC
    • Optional accuracy frames: BK BK_PNT_NAV and/or a UBX-compatible HPPOSLLH-shaped frame (see §15)

Never force an entire notification through UTF-8 decoding without filtering.


9. NMEA position parsing

Coordinate format

NMEA lat/lon fields are ddmm.mmmm / dddmm.mmmm, not decimal degrees. Convert: degrees = floor(value / 100), minutes = remainder, decimal = degrees + minutes / 60; negate for S/W.

GGA fields (common)

Index Meaning
1 UTC time hhmmss.ss
2–3 Latitude + N/S
4–5 Longitude + E/W
6 Fix quality (0 invalid, 1 GPS, 2 DGPS, 4 RTK fixed, 5 RTK float, 7 Base mode, …)
7 Satellites
8 HDOP
9 Altitude (often orthometric / MSL — check your product notes)
11 Geoid separation

P-70-specific: GGA quality 7 means the receiver is in Base mode (automatic survey lock or fixed Base). That is the primary Base-readiness signal — there is no u-blox NAV-SVIN on P-70.

RMC

Use status field A (active). Provides speed (knots) and course.

Talker IDs

Parse by the last three characters of the address field (GGA, RMC, …), not by assuming $GN only.


10. RTK Rover: write RTCM3 corrections

Once notify is active on P-70 Ultra NTRIP BLE:

  1. Connect your app to an NTRIP caster (TCP) as a client.
  2. Decode the HTTP response body to a pure RTCM3 byte stream (if the caster uses HTTP chunked encoding, strip chunk framing first).
  3. Write those bytes to FFF1, preserving packet order and chunking to the platform writable length.

No special “start RTCM” init command is required before uplink. Ensure the chip is in Rover mode (not Base) before injecting corrections.

Write tips

Topic Recommendation
Characteristic Same FFF1
Write type for RTCM Write without response when that is what the characteristic exposes
Chunk size Use maximumWriteValueLength — never assume 20 forever; official notes say there is no special chunk policy beyond the stack default
Ordering Preserve RTCM packet order
During Base / Survey lock Do not inject Rover corrections into a unit that is still locking Base (GGA quality heading toward / at 7 with RTCM output)

How you know RTK is working

Watch GGA fix quality: 4 = RTK Fixed, 5 = RTK Float, 1 / 2 = single / DGPS. Also watch age of differential in GGA when present.


11. Command framing: BK HEX and $POLCFG…

P-70 configuration over BLE uses two families:

A. BK binary frames

Sync prefix 42 4B, followed by length / class / payload / checksum fields as defined in the P-70 Ultra interface description (document series such as UG01-BK166X-…).

For App work you normally paste official HEX sequences from Columbus (Common Commands / command table) rather than hand-building every CFG key. Successful apply replies with ASCII $OK; failure replies with $FAIL.

B. ASCII plaintext commands

CRLF-terminated lines, for example:

Command Purpose
$POLCFGBASE,<lat>,<lon>,<height>\r\n Set fixed Base coordinate (immediate)
$POLCFGBASE,0,0,0\r\n Clear fixed Base
$POLCFGSAVE\r\n Save current configuration to Flash
$POLCFGPTVER\r\n / $POLCFGPTSYS\r\n Query helpers (firmware-dependent)

Important: $OK / $FAIL can span BLE notifications. Buffer raw bytes and search for the tokens $OK and $FAIL (prefer detecting $FAIL before treating a bare $OK substring incorrectly if your buffer is overly greedy).

Suggested ACK timeout: 10–15 seconds on BLE; one bounded retry on timeout only.

One command (or one logical HEX step) in flight: wait for $OK / $FAIL (or timeout) before the next exclusive configuration write. Do not interleave RTCM uplink or optional accuracy-enable HEX with a POLCFG transaction.

Equivalent Flash-save HEX (same effect as $POLCFGSAVE):

42 4B CC 17 26 04 00 00

Official Rover/Base HEX tables often append this save frame at the end. For lab / temporary Apply UX, omit the trailing save and only send $POLCFGSAVE after user confirmation (recommended).


12. Role configuration: Rover / Base

12.1 Official HEX sequences (temporary Apply — without trailing save)

Use the same payloads as Columbus Common Commands, but drop the final 42 4B CC 17 26 04 00 00 when you want RAM-only apply.

42 4B AC 06 26 02 00 0C 55 55 00 01 00 00 00 03 00 00 00 01
42 4B 25 00 26 02 00 0C 55 55 00 01 00 00 00 07 00 00 00 01
42 4B 99 5A 26 02 00 0C 55 55 00 01 00 00 00 0C 00 00 00 04
42 4B 73 8F 26 02 00 0C 55 55 00 01 00 00 00 0D 00 00 00 00
42 4B F4 4A 26 02 00 0C 55 55 00 01 00 00 00 31 00 00 00 00
42 4B C9 D8 26 02 00 0C 55 55 00 01 00 00 00 0E 00 00 00 27
42 4B AC 06 26 02 00 0C 55 55 00 01 00 00 00 03 00 00 00 01
42 4B 25 00 26 02 00 0C 55 55 00 01 00 00 00 07 00 00 00 01
42 4B 99 5A 26 02 00 0C 55 55 00 01 00 00 00 0C 00 00 00 04
42 4B B2 03 26 02 00 0C 55 55 00 01 00 00 00 0D 00 00 00 0C
42 4B C4 29 26 02 00 0C 55 55 00 01 00 00 00 31 00 00 00 03
42 4B 46 8E 26 02 00 0C 55 55 00 01 00 00 00 10 00 00 00 01
42 4B A9 1E 26 02 00 0C 55 55 00 01 00 00 00 0E 00 00 00 21

An MSM7 Base variant also exists in official tables. Prefer MSM4 for interoperability unless you control both Base and Rover stacks. Do not mix MSM4 and MSM7 casually on a shared caster.

Send one HEX frame at a time, wait for $OK, then the next.

12.2 Automatic Survey-In (no duration / accuracy knobs)

Unlike EX-1, P-70 Ultra does not expose adjustable Survey-In duration or accuracy limits over BLE.

When BASE Mode HEX is applied:

  1. The chip evaluates whether the current position is accurate enough.
  2. When ready, it locks the reference and GGA quality becomes 7.
  3. Coordinates should remain stable while quality stays at 7.
  4. You may then optionally refine with $POLCFGBASE,….

App readiness policy (practical):

  • Wait for GGA quality 7.
  • Require several consecutive epochs and a short stability window (for example ≥3 epochs over ≥3 seconds with horizontal wander under a few centimetres).
  • Base mode floods BLE with RTCM, so NMEA may arrive slower than 1 Hz — use a generous stale timeout (on the order of 15 s).
  • Only then start NTRIP server upload of Base RTCM extracted from the notify stream.

12.3 Fixed Base ($POLCFGBASE)

$POLCFGBASE,<lat>,<lon>,<height>\r\n
Field Rule
Latitude Decimal degrees; north positive, south negative
Longitude Decimal degrees; east positive, west negative
Height Meters. Marketing / web text may say “above mean sea level”; field verification on P-70 Ultra shows ellipsoidal height semantics for $POLCFGBASE (compare against a known site / EX-1 ellipsoidal reference). Send ellipsoidal meters unless Columbus confirms otherwise for your firmware.
Clear $POLCFGBASE,0,0,0\r\n

Formatting tips:

  • Use POSIX / en_US_POSIX decimal points (never locale commas).
  • Keep high precision (apps often use ~9 decimal places for lat/lon and ~4 for height).
  • Always terminate with \r\n.

$POLCFGBASE takes effect immediately in RAM. Persist only with $POLCFGSAVE (next section).

  1. Pause RTCM uplink / NTRIP client if active.
  2. Send Rover HEX sequence (desired rate) without trailing save — serial $OK each.
  3. Confirm GGA quality is not stuck at 7 (unless a leftover Flash fixed Base is still locking — clear + save + power-cycle may be required).
  4. Start NTRIP client and write RTCM uplink.
  1. Pause Rover RTCM uplink.
  2. If a stale Flash $POLCFGBASE may exist and you want receiver-managed / automatic survey, clear it ($POLCFGBASE,0,0,0), $POLCFGSAVE, and often power-cycle once so Flash reload is empty.
  3. Send Base MSM4 HEX without trailing save — serial $OK each.
  4. Wait for GGA quality 7 + coordinate stability.
  5. Optionally apply $POLCFGBASE,… for a known fixed point.
  6. Confirm RTCM3 appears in the notify stream; then start NTRIP server upload.
  1. Apply temporarily — HEX role + optional $POLCFGBASE; verify; do not save yet.
  2. Save permanently — only after verification, on user confirmation ($POLCFGSAVE).

Temporary settings can be lost on power cycle. That is intentional for lab testing.


13. Permanent save ($POLCFGSAVE)

Send either:

$POLCFGSAVE\r\n

or the HEX equivalent 42 4B CC 17 26 04 00 00.

This writes the receiver’s current configuration to Flash so it survives power-off.

Warnings you should surface to your users:

  • Do not auto-save.
  • Do not save before temporary apply verification.
  • $OK means the command was accepted — still verify after a power cycle if persistence is a product requirement.
  • A saved $POLCFGBASE can re-lock Base after reboot (GGA quality 7 at the saved coordinate). Clearing for a fresh automatic survey may require clear → save → power-cycle.

Do not brand this as u-blox “BBR/Flash CFG-CFG”. UI copy such as “Save to P-70” / “Save P-70 Configuration” is clearer.


Rule Why
One exclusive config write in flight $OK does not identify which command succeeded if several overlap
Serial HEX list with per-frame ACK Prevents false “all done”
Pause RTCM uplink during role / POLCFG transactions Avoid mixed Base/Rover traffic on the shared pipe
Pause optional HPPOSLLH enable during POLCFG Same shared notify / write pipe
Name gate: P-70 Ultra NTRIP BLE only Wrong interface has no reliable RTCM write
Wait for GGA quality 7 (+ stability) before Base “ready” Automatic survey has no NAV-SVIN
No Rover RTCM while locking Base Contaminates base solution
Separate Apply vs $POLCFGSAVE Official HEX tables often include save; apps should not surprise users

A full Base apply (many HEX frames + readiness wait) over BLE commonly takes tens of seconds. Show progress (command i of n, then “waiting for Base fix”).


15. Accuracy estimates (HPPOSLLH)

Do not treat NMEA HDOP / GST as centimetre RTK accuracy on P-70 Ultra.

Official guidance for this product family: enable high-precision position / accuracy output and read the horizontal / vertical accuracy estimates from that stream (tools may label the view similarly to u-blox HPPOSLLH even though the chip is BK/Polaris).

Temporary enable (do not save)

42 4B BE A5 26 02 00 0C 55 55 00 01 00 00 00 0F 00 00 08 00

Disable (optional):

42 4B 37 0C 26 02 00 0C 55 55 00 01 00 00 00 0F 00 00 00 00

Leaving this unsaved is intentional: it reverts after power cycle and avoids permanent side effects.

Decoder notes

  • Keep a raw buffer; frames may be BK 42 4B navigation/accuracy messages and/or a UBX-shaped B5 62 HPPOSLLH-compatible layout depending on firmware / bridge behaviour.
  • Validate checksums; handle BLE fragmentation.
  • Until a valid accuracy frame arrives, show “—” / waiting — do not fake RTK hAcc/vAcc from HDOP.

16. Output rate (1 / 5 / 10 / 20 Hz)

P-70 Ultra RTK Rover supports 1 / 5 / 10 / 20 Hz via official Rover HEX variants (same structure as §12.1; rate bytes change). Highest rate is 20 Hz; throughput, log size, and battery cost rise quickly.

Rate Notes
1 Hz Default / highest stability for most apps
5 Hz Vehicles, robots
10 Hz Higher dynamics
20 Hz UAV / high dynamics; large BLE load

Apply rate by sending the matching Rover HEX sequence without trailing save; verify observed GGA cadence; only then $POLCFGSAVE if persistence is required. Prefer changing rate only while confirmed Rover and without an active NTRIP session.


17. Pitfalls checklist

  1. Connecting to P-70 Ultra BLE instead of P-70 Ultra NTRIP BLE.
  2. Assuming FFF0 alone means P-70 Ultra.
  3. Sending u-blox UBX (CFG-TMODE3, CFG-MSG, CFG-CFG, …) — wrong chip.
  4. Treating every notify as UTF-8 text.
  5. Writing RTCM without removing HTTP chunked framing.
  6. Parallel HEX / $POLCFG… writes without waiting for $OK.
  7. Expecting adjustable Survey-In duration/accuracy like EX-1.
  8. Declaring Base ready before GGA quality 7 (and stable coordinates).
  9. Using MSL height for $POLCFGBASE when the unit expects ellipsoidal height (verify on your firmware).
  10. Auto-including the trailing Flash-save HEX from official tables during “temporary apply”.
  11. Hard-coding ATT payload size to 20 forever.
  12. Expecting Simulator + real BLE hardware to work.
  13. Changing UART baud from the app “just in case” — do not.
  14. Leaving a Flash $POLCFGBASE in place and wondering why automatic survey never restarts after Base start.

18. EX-1 vs P-70 quick diff

Topic EX-1 P-70 Ultra
GNSS chip / protocol u-blox ZED-F9P / UBX BK / Polaris BK166X
BLE name (RTK) EX-1 NTRIP BLE P-70 Ultra NTRIP BLE
GATT FFF0 / FFF1 Same
Config language UBX binary BK HEX (42 4B) + $POLCFG…
Command ACK UBX ACK/NAK (05 01 / 05 00) $OK / $FAIL
Rover / Base CFG-TMODE3 + CFG-MSG RTCM rates Official HEX sequences
Survey-In Configurable duration + accuracy; NAV-SVIN Automatic; GGA quality 7
Fixed Base UBX TMODE3 Fixed (ellipsoidal) $POLCFGBASE (use ellipsoidal; verify)
Permanent save CFG-CFG BBR+Flash $POLCFGSAVE
Accuracy estimate NAV-PVT poll Enable HPPOSLLH / BK accuracy output
Rover rates (typical) Product-specific 1 / 5 / 10 / 20 Hz

Official Columbus references (keep bookmarked):


End of guide.

Leave a Reply