Skip to main content

iOS Mesh SDK

SDK Version: 1.0.0

XTalkMeshSdk implements MeshWire protocol and xTalk Mesh business payloads. The host supplies RF transmission and AT execution, feeds complete inbound RF packets to the SDK, and observes typed events. BLE/UART lifecycle, authentication, audio codec, storage, and UI are outside this product.

Add and import

Add the supplied exact-version Swift package, link XTalkMeshSdk, then:

import XTalkMeshSdk

Transport, store, and initialization

struct CustomerTransport: MeshSdk.Transport {
func sendRfPayload(_ bytes: Data) async throws {
try await radio.sendAndWaitForCompletion(bytes)
}

func runAtCommand(
_ command: String,
timeoutMs: Int,
log: Bool
) async throws -> [String] {
try await radio.runAt(command, timeoutMs: timeoutMs)
}
}

let mesh = MeshSdk(
transport: CustomerTransport(),
config: .init(
nodeId: localDeviceId,
defaultHopLimit: 3,
rebroadcastEnabled: true,
rebroadcastDelayMinMs: 200,
rebroadcastDelayMaxMs: 400,
rateMode: 7,
maxRfPayloadBytes: 105
),
learnedRouteStore: routeStore
)

Transport also supports RF-operation lease hooks when a host must arbitrate the radio. LearnedRouteStore.load() and save(routes:) persist LearnedRoute values.

Receive and observe

let cancellable = mesh.events.sink { event in
switch event {
case .textReceived(let value): showText(value.text)
case .voiceReceived(let value): saveVoice(value.voice)
case .ack(let value): updateDelivery(value.packetId, value.ok)
default: handle(event)
}
}

mesh.handleInbound(raw: packet, snr: snr, rssi: rssi)

Call handleInbound once for every complete Mesh RF packet after removing transport text framing. MeshSdk.looksLikePacket(_:) is a prefilter only.

Events cover text/voice/repair ACK, reliable ACK/timeout, trace route, friend direct text/ACK, nearby peers, friend request/ACK, location request/ACK/heartbeat/stop, and group invitation/join/roster synchronization. Event models expose IDs, route summary, and optional RSSI/SNR.

Radio profile, pairing, and keys

let rf = AiTalkMeshRadioProfile.channel(channelId: 1)
let psk16 = MeshPairingPsk.derivePsk16(pairChannel: 25, key4: "1234")

mesh.setPublicGroupPsk(publicChannel: 1, psk: groupPsk)
mesh.setFriendKey16(forNode: peerNode, key16: friendKey)

The authoritative profile has 16 explicit channel/frequency/BCNID records. RF channel, Mesh public channel, and pairing channel are independent. Passing nil to a key setter removes the override. Pairing channel 25/key 1234 yields 166bf40821e0aa173fdf424424e42b49.

Text and voice

let packetId = try await mesh.sendPublicText(
groupId: "10000001",
text: "hello mesh",
wantAck: true,
hopLimit: nil
)

let packetIds = try await mesh.sendPublicVoiceAiCodecFrames(
groupId: "10000001",
frames41: encodedFrames,
codecFamilyByte: 0,
autoPlay: false,
hopLimit: nil,
wantAckLast: false
)

Long text is fragmented automatically. Voice input must already contain 41-byte AiCodec frames. Repair uses sendRepairablePublicVoiceAiCodecFrames(...) and sendPublicVoiceRepairAck(...); results use RepairableVoiceSendResult and VoiceFragmentDispatch.

Map and friend APIs

Update local discovery data with updateMapUserName, updateMapLocation, and optional updateDiscoveryAddressByteOverride. Discover with discoverNearbyMapUsers(...).

Friend pairing uses sendMapFriendRequest and sendMapFriendAck. Direct encrypted text uses sendFriendDirectText and sendFriendDirectAck after setting the friend key.

Location sharing uses sendMapLocShareRequest, sendMapLocShareAck, sendMapLocHeartbeatBroadcast, and sendMapLocStopBroadcast. Group invitations use sendMapGroupAddMembersRequest, sendMapGroupAddMembersAck, sendMapGroupJoinNoticeBroadcast, and sendMapGroupRosterSyncBroadcast with MapGroupRosterMember values.

let peers = try await mesh.discoverNearbyMapUsers(
groupId: "10000001",
wantName: true,
wantPos: true,
hopLimit: 0
)

let messagePacket = try await mesh.sendFriendDirectText(
toNode: peerNode,
messageId: messageId,
text: "hello",
groupId: "10000001"
)

Reliability, routes, and configuration

Use updateAckEnabled, sendTraceRoute, routeSummary, predictedRouteSummary, learnedRouteSnapshot, clearLearnedRoute, and clearAllLearnedRoutes. estimateFloodSettleMs and defaultMarginMsForRateMode help schedule bursts.

Runtime setters are updateNodeId, updateRateMode, updateMaxRfPayloadBytes, updateDefaultHopLimit, updateAckEnabled, setCadEnabled, updateMapUserName, updateMapLocation, and updateDiscoveryAddressByteOverride.

The optional Internet relay surface includes InternetMeshDeveloperConfig and its relay client. Use it only with an explicitly provisioned secure relay endpoint; received raw packets still enter the same handleInbound path.

Errors

Public failures use MeshSdkError or a thrown transport error. Validate group IDs, channel ranges, key sizes, and frame sizes before sending. Stop sends and detach the old inbound path before replacing the underlying transport, so a packet is never delivered twice.