BLE TRANSFER Packet🔗
The KTag TRANSFER packet (hex 0x08) implements a type of two-phase commit protocol to transfer items from device to device.
First Use Case: K-Point Collection🔗
The Transfer packet was first implemented to enable a game feature called K-Point Collection. The feature works like this: there are one or more K-Point Fountains, usually implemented as phones running the Android KTag Apps, which periodically offer K-Points by means of the Offer Unlimited subtype of the Transfer packet. Each KTag device which receives such a packet addressed to it (or broadcast) will add the quantity of each item in the packet to it's own inventory. The Transaction Number is used to limit the number of actual transmissions at the application level, since the BLE advertisement gets repeated by the Fountain for robustness.
Once a player has obtained a K-Point (or K-Points) on his device, he can return to his Collection Point (again, usually a (different) phone running the Android KTag Apps), where the Collection Point will initiate a Transfer automatically by means of the Request Involuntary Friendly subtype of the Transfer packet. The player's device then responds by initiating a two-phase commit transfer of the K-Points in its inventory (see the example below).
Before the Transfer: Discovering Your Own Address (Echo BD_ADDR)🔗
Most Transfer packets are addressed to one device by its BD_ADDR, so a device needs to know its own address to tell whether a packet is meant for it. An Android app can't find this out directly: Android reports 02:00:00:00:00:00 as the device's address, and the real advertising address is only available to privileged system apps. An app that doesn't know its own address can't tell its packets from those meant for another phone. If two Collection Points are in range of each other, both would credit the same player's K-Points.
The Echo BD_ADDR subtype (0x0B) and its reply, Acknowledge Echo BD_ADDR (0x0C), solve this by asking another device what address it sees:
- The requester advertises an
Echo BD_ADDRpacket addressed to one nearby KTag device. Each of the three item slots has the item ID0xFFFE(Transfer nonce) and a random, nonzero 16-bit nonce in the quantity field, which makes 48 random bits in all. - The target replies with an
Acknowledge Echo BD_ADDRpacket. ItsTarget BD_ADDRis the address the target saw the request come from (which is the requester's own address), and its item slots are copied unchanged from the request. TheTransaction Numberis 0. - The requester accepts the reply only if all three nonces match the ones it sent. Because other devices can't know those nonces, a requester that overhears a reply meant for someone else won't mistake that address for its own.
The Transfer nonce is a protocol element, not a game item: it is never added to or deducted from any inventory.
A KTag device running SystemK handles Echo BD_ADDR like this:
- It answers only when it's in the Interacting or Tagged Out state, which are the only states that handle
Transferpackets, and only when no transfer of its own is in progress. Nothing answers before a game starts. - It never answers a broadcast
Echo BD_ADDR. Otherwise, every device in range would replace its advertisement to reply, and the requester needs just one answer. - It answers each
Event Numberfrom a requester only once, because the request is repeated on every advertising interval. A requester must use a newEvent Numberfor each probe, from the same counter it uses for its otherTransferpackets. Otherwise, a device may ignore a later request as a repeat. - It ignores the
Team ID, since a device's address has nothing to do with its team. - It answers at any RSSI. Like
Request InventoryandInventory, theEcho BD_ADDRsubtypes are exempt from theMin_RSSI_To_Initiate_Transfersetting, because they don't move any items. - It ignores any
Acknowledge Echo BD_ADDRit receives. Only address-discovering apps use the reply.
A probe that gets no answer tells the requester nothing, since the target might be out of range, mid-transfer, not playing, or running older firmware. The Android KTag Apps retry a few times, rotating among nearby devices, and send the probe from the same advertising set they use for their other traffic, so the address they learn is the one their transfers come from. Android also changes a phone's advertising address periodically (roughly every 15 minutes), so the apps repeat the probe regularly. Until an app knows its address, it refuses to collect, because a missed collection can simply be retried, but a double-counted one can't be undone.
Before the Transfer: Querying and Reporting Inventory🔗
It is sometimes useful for one KTag device to ask another KTag device about what items it is carrying. This is accomplished with the Request Inventory subtype of the Transfer packet. Devices, upon receiving a new Request Inventory addressed to them or broadcast, should respond with an Inventory subtype of the Transfer packet. Note that neither of these results in the transfer of any items; these packets are informational only.
Initiating a Transfer🔗
Request Voluntary (Ask)🔗
This subtype attempts to initiate a TPC transfer by requesting it of a device. The receiving device prompts its operator for permission; if agreed to, the transfer can proceed.
Request Involuntary Friendly (Unload)🔗
This subtype initiates a TPC transfer by requesting it of a device on the same team. The receiving device confirms the same team, and then proceeds automatically.
Request Involuntary Unfriendly (Steal)🔗
This subtype initiates a TPC transfer by requesting it of a device on a different team. The receiving device confirms the team is not the same as its own, and then proceeds automatically. Other features of the game control when and if stealing items is allowed.
Example TPC Transfer initiated by Request Involuntary Friendly (Unload)🔗
It the example below, Device A wished to send an item to Device B.
sequenceDiagram
participant A as Device A (Sender)
participant L as BLE
participant B as Device B (Receiver)
Note over A,B: Item transfer begins
A->>L: 1. Offer with transaction number = 1 (request to send item)
L-->>B: 1. Offer (tn=1, delivered)
B->>L: 2. Offer Acknowledged (tn=1, ready to receive)
L-->>A: 2. Offer Acknowledged (tn=1, delivered)
Note over A: Send item
A->>L: 3. Commit (tn=1, payload)
Note over A: A deducts the item from its inventory.
L-xB: 3. Commit lost in transit ❌
Note over B: Timeout — no token received, so resend acknowledgement
B->>L: 4. Offer Acknowledged (tn=1, ready to receive)
L-->>A: 4. Offer Acknowledged (tn=1, delivered)
Note over A: Duplicate acknowledgement — Retransmit commit
A->>L: 5. Commit (tn=1, payload)
Note over A: A DOES NOT deduct the item again, since the tn is the same.
L-->>B: 5. Commit (tn=1, delivered) ✓
Note over B: B credits the item to its inventory, and sends acknowledgment
B->>L: 6. Commit Acknowledged (tn=1 confirmed)
L-xA: 6. Acknowledgement lost in transit ❌
Note over A: No Acknowledgement — retransmit commit
A->>L: 7. Commit (tn=1, payload)
L-->>B: 7. Commit (duplicate, tn=1)
Note over B: Duplicate detected — discard & re-ACK
B->>L: 8. Commit Acknowledged (tn=1, re-sent)
L-->>A: 8. Commit Acknowledged (delivered) ✓
Note over A,B: Item successfully transferred