TAK Protocol
The app implements three CoT (Cursor-on-Target) wire formats over LoRaLoRaA low-power, long-range wireless communication technology used by Meshtastic devices to enable communication over distances of several kilometers without the need for cellular, Wi-Fi, or other traditional network infrastructures.: two legacy V1 paths and one V2 path that uses the TAKPacket-SDK for zstd-dictionary compression and richer typed payloads. This page documents the choice of format, the receive dispatch, and the supporting infrastructure.
Wire Formats
| Format | Port | Payload | Used when |
|---|---|---|---|
| V1 ATAK_PLUGIN | 72 | Bare TAKPacket protobufProtobuf (Protocol Buffers). A method developed by Google for serializing structured data, used in Meshtastic for efficient communication protocol between devices. (PLI / GeoChat only) | Connected radio firmware < 2.8.0 |
| V1 ATAK_FORWARDER | 257 | zlib-compressed CoT XML, optionally Fountain (LT) coded for multi-packet payloads | Connected radio firmware < 2.8.0, CoT type other than PLI / GeoChat (Apple-to-Apple only) |
| V2 ATAK_PLUGIN_V2 | 78 | TAKPacketV2 protobufProtobuf (Protocol Buffers). A method developed by Google for serializing structured data, used in Meshtastic for efficient communication protocol between devices., compressed with the TAKPacket-SDK zstd dictionary | Connected radio firmware ≥ 2.8.0 |
V2 carries the full typed CoT vocabulary: PLI, GeoChat, shapes, markers, routes, casevac, emergency, and task. V1 ATAK_PLUGIN carries PLI and GeoChat only; everything else falls back to the V1 ATAK_FORWARDER path.
Per-send Fork
TAKMeshtasticBridge.sendToMesh(_:clientInfo:) chooses the format on every send based on AccessoryManager.supportsTAKv2, which checks the connected radio's firmware version:
if accessoryManager.supportsTAKv2 {
// V2: SDK-driven path
let parser = MeshtasticTAK.CotXmlParser()
let packet = try parser.parse(strippedXml)
let compressor = MeshtasticTAK.TakCompressor()
// `compressWithRemarksFallback` returns `Data?` — `nil` means the
// payload is still over the LoRa MTU even after `<remarks>` are
// stripped. The real `sendCoTToMeshV2` translates that into a
// thrown `AccessoryError.ioFailed(...)` so the caller's `do/catch`
// doesn't treat the silent drop as a successful send.
guard let wire = try compressor.compressWithRemarksFallback(packet, maxWireBytes: 225) else {
throw AccessoryError.ioFailed("TAK V2 payload exceeds LoRa wire size limit")
}
try await sendTAKV2Packet(wire, channel: channel)
} else {
// V1: classify, then dispatch
switch GenericCoTHandler.shared.classifySendMethod(for: cot) {
case .takPacketPLI, .takPacketChat:
let pkt = convertToTAKPacket(cot: cot)
try await sendTAKPacket(pkt, channel: channel)
case .exiDirect, .exiFountain:
try await GenericCoTHandler.shared.sendGenericCoT(cot, channel: channel)
}
}
The fork is per-send (not per-session) so a radio that upgrades mid-session jumps to V2 immediately.
Receive Dispatch
AccessoryManager.swift's exhaustive portnum switch dispatches incoming TAKTAK (Team Awareness Kit). A situational awareness ecosystem. Meshtastic bridges to it by converting mesh messages to and from Cursor on Target format. packets to handlers in AccessoryManager+TAK.swift:
| Portnum | Handler | Behavior |
|---|---|---|
.atakPlugin (72) | handleATAKPluginPacket(_:) | Decode bare TAKPacket protobufProtobuf (Protocol Buffers). A method developed by Google for serializing structured data, used in Meshtastic for efficient communication protocol between devices.; convert PLI / GeoChat to CoTMessage; forward to TAKTAK (Team Awareness Kit). A situational awareness ecosystem. Meshtastic bridges to it by converting mesh messages to and from Cursor on Target format. clients via TAKServerManager.shared.broadcast(_:). |
.atakPluginV2 (78) | handleATAKPluginV2Packet(_:) | zstd-decompress with TakCompressor; rebuild CoT XML with CotXmlBuilder; strip the XML prologue and inter-tag whitespace; forward raw XML via broadcastRawXml(_:) so shape detail (<link point> vertices, colors, stroke) survives. Route CoT (b-m-r) triggers the route data package side-effect. |
.atakForwarder (257) | handleATAKForwarderPacket(_:) | Hand off to GenericCoTHandler.handleIncomingForwarderPacket(_:), which reassembles Fountain fragments and zlib-decompresses the resulting CoT XML before broadcasting. |
TAKPacket-SDK
The TAKPacket-SDK Swift Package is pinned in Meshtastic.xcworkspace/.../Package.resolved. The bridge uses three APIs:
MeshtasticTAK.CotXmlParser().parse(_:)— parses CoT XML into aTAKPacketV2protobufProtobuf (Protocol Buffers). A method developed by Google for serializing structured data, used in Meshtastic for efficient communication protocol between devices..throws; callers musttry.MeshtasticTAK.TakCompressor().compressWithRemarksFallback(_:maxWireBytes:)— picks the zstd dictionary best suited to the payload, attempts compression, and on overflow retries with<remarks>stripped. Returnsnilif the payload is too large even without remarks;sendCoTToMeshV2translates thenilintoAccessoryError.ioFailed(...)so the caller'sdo/catchdoesn't treat the drop as a successful send.MeshtasticTAK.CotXmlBuilder().build(_:)— round-tripsTAKPacketV2back to CoT XML for forwarding to TAKTAK (Team Awareness Kit). A situational awareness ecosystem. Meshtastic bridges to it by converting mesh messages to and from Cursor on Target format. clients.
The wire MTU constant maxWirePayloadBytes = 225 reflects the LoRaLoRaA low-power, long-range wireless communication technology used by Meshtastic devices to enable communication over distances of several kilometers without the need for cellular, Wi-Fi, or other traditional network infrastructures. frame budget after the Meshtastic envelope.
Identity Admin
TAKIdentitySection (embedded in TAKServerConfig) reads node.takConfig for the current team and role values. When the node has no TAKTAK (Team Awareness Kit). A situational awareness ecosystem. Meshtastic bridges to it by converting mesh messages to and from Cursor on Target format. config cached, requestTakConfigIfNeeded() fires an admin request via AccessoryManager.requestTAKModuleConfig(fromUser:toUser:) so first-time users don't see a perma-spinner.
Saving the identity dispatches AccessoryManager.saveTAKModuleConfig(config:fromUser:toUser:), which packages a ModuleConfig.TAKConfig inside an AdminMessage and ships it on the admin port.
Offline Queue
TAKServerManager buffers outgoing CoT for delivery when a TAKTAK (Team Awareness Kit). A situational awareness ecosystem. Meshtastic bridges to it by converting mesh messages to and from Cursor on Target format. client reconnects:
private enum QueuedPayload {
case message(CoTMessage)
case rawXml(String)
}
broadcast(_:) enqueues .message payloads; broadcastRawXml(_:) enqueues .rawXml so V2 shapes / routes / markers retain their detail elements. The queue has a 5-minute TTL and a 50-entry cap. drainOfflineQueue() dispatches the right path per payload variant when a client (re)connects.
Route Data Packages
RouteDataPackageGenerator (in Meshtastic/Helpers/TAK/) converts route CoT (b-m-r) into KML-inside-zip ATAKATAK (Android Team Awareness Kit). The Android TAK client. An official Meshtastic plugin forwards its Cursor on Target traffic over the mesh. data packages that the user can sideload into iTAK (which silently ignores route CoT received over its TCPTCP (Transmission Control Protocol). One of the three ways a client reaches a node, alongside serial and Bluetooth. Clients connect over TCP on port 4403. streaming connection).
The pipeline:
generateKml(routeXml:)extracts<event uid>,<contact callsign>, and every<link point="lat,lon,hae">waypoint viaattributeValue(in:on:named:), which supports both single- and double-quoted attributes.sanitizeForFilename(_:)strips path separators, control chars, and..sequences from the route UID so it's safe to use in file names and the temp directory path.escapeXml(_:)separately escapes the value before interpolation into the manifest'svalue="..."attribute.generateDataPackage(routeXml:)writes the KML andmanifest.xmlto a temp directory and zips them withNSFileCoordinator(readingItemAt:options:.forUploading).saveToDocuments(fileName:zipData:)writes the zip toDocuments/TAK Routes/<sanitizedUid>.zip(creating the directory on first use).AccessoryManager+TAK.handleATAKPluginV2Packet(_:)posts aNotificationtitled Route Received with the route callsign as subtitle and body Saved to Files → Meshtastic → TAKTAK (Team Awareness Kit). A situational awareness ecosystem. Meshtastic bridges to it by converting mesh messages to and from Cursor on Target format. Routes. Open in iTAK to import.
Capabilities
AccessoryManager.supportsTAKv2 is the canonical gate. It enables V2 only when the active radio reports a supported, well-formed version; an unavailable, malformed, or older version uses V1.
var supportsTAKv2: Bool { Self.isTAKv2Supported(firmwareVersion: connectedVersion) }
The capability parser accepts numeric major.minor.patch versions and an optional hexadecimal build suffix, such as 2.8.0.3a0c08b. Use this property (rather than parsing the firmware version inline) anywhere a V1/V2 decision is needed. Future TAKTAK (Team Awareness Kit). A situational awareness ecosystem. Meshtastic bridges to it by converting mesh messages to and from Cursor on Target format. SDK features that require a higher firmware version should add a sibling property with a clear cut-off so the bridge stays declarative.
Related Files
Meshtastic/Helpers/TAK/TAKMeshtasticBridge.swift— V1/V2 fork insendToMesh.Meshtastic/Accessory/Accessory Manager/AccessoryManager+TAK.swift— send and receive handlers.Meshtastic/Helpers/TAK/TAKServerManager.swift— TCPTCP (Transmission Control Protocol). One of the three ways a client reaches a node, alongside serial and Bluetooth. Clients connect over TCP on port 4403. server, offline queue, certificate management.Meshtastic/Helpers/TAK/GenericCoTHandler.swift— V1 ATAK_FORWARDER classification and Fountain reassembly.Meshtastic/Helpers/TAK/RouteDataPackageGenerator.swift— KML data package writer.Meshtastic/Views/Settings/TAKServerConfig.swift— combined TAKTAK (Team Awareness Kit). A situational awareness ecosystem. Meshtastic bridges to it by converting mesh messages to and from Cursor on Target format. Server settings screen with the embeddedTAKIdentitySection.
See also Transport Layer for the AccessoryManager extension map.