Imported from jwoglom/pumpX2 (
AGENTS.md). Install upstream withnpx skills add jwoglom/pumpX2. Copyright stays with the author.
PumpX2 repository orientation
High-level layout
- Gradle multi-module project exporting three libraries (
pumpx2-android,pumpx2-messages,pumpx2-shared) plus utilities (cliparser) and a demo Android app (sampleapp).【F:settings.gradle†L19-L20】【F:build.gradle†L1-L35】 - All modules share the
com.jwoglom.pumpx2namespace.sharedholds reusable utilities,messagesimplements the Tandem Bluetooth protocol,androidLiblayers Android/BLE integration on top, andcliparser/sampleappdemonstrate usage. - Build artifacts are configured for Maven publishing (local and GitHub Packages) and target Java 11 / Android API 26+.【F:build.gradle†L1-L35】【F:androidLib/build.gradle†L18-L65】
Build & test quick-reference
./gradlew buildbuilds every module, producing AAR/JAR artifacts for distribution.【F:README.md†L63-L88】./gradlew test(or module-specific variants) runs the Java unit tests located inmessages/src/test(JUnit 4).【F:messages/build.gradle†L20-L43】【83f740†L1-L10】./gradlew publishToMavenLocalpublishes artifacts locally; publishing destinations are configured inbuild.gradle../gradlew cliparser:run --args '<command ...>'executes the CLI parser for offline message parsing/encoding.【F:cliparser/src/main/java/com/jwoglom/pumpx2/cliparser/Main.java†L1-L208】./gradlew :sampleapp:installDebugbuilds and installs the example Android client (requires Android SDK setup).
Module breakdown
shared (shared/src/main/java/com/jwoglom/pumpx2/shared)
- Lightweight utilities used by both the Java protocol library and Android stack.
Hexsupplies a platform-independent hex encoder/decoder to avoid Androidorg.apache.http.legacyconflicts.【F:shared/src/main/java/com/jwoglom/pumpx2/shared/Hex.java†L1-L45】JavaHelperscentralizes reflection-basedtoStringhelpers and debugging utilities.【F:shared/src/main/java/com/jwoglom/pumpx2/shared/JavaHelpers.java†L1-L103】Lis a logging façade whose delegates can be rebound (e.g., to Timber in Android viaLConfigurator).【F:shared/src/main/java/com/jwoglom/pumpx2/shared/L.java†L1-L64】【F:androidLib/src/main/java/com/jwoglom/pumpx2/util/timber/LConfigurator.java†L1-L44】TriConsumer/QuadConsumerfunctional interfaces and theLOG_PREFIXconstant support cross-platform logging.
messages (messages/src/main/java/com/jwoglom/pumpx2/pump/messages)
- Implements the Tandem Bluetooth message model, packetization, and authentication primitives. Exposed as a pure-Java library (
pumpx2-messages). - Message abstraction
Messagebase class encapsulates cargo bytes,MessagePropsmetadata, and helpers for JSON/debug serialization. Requests and responses are annotated with@MessagePropsdescribing opcode, cargo size, characteristic, signing, and API/device constraints.【F:messages/src/main/java/com/jwoglom/pumpx2/pump/messages/Message.java†L1-L120】【F:messages/src/main/java/com/jwoglom/pumpx2/pump/messages/annotations/MessageProps.java†L1-L26】MessageTypedifferentiates request vs response; opcodes are even/odd pairs by convention.【F:messages/src/main/java/com/jwoglom/pumpx2/pump/messages/MessageType.java†L1-L15】Messagesenum is the authoritative opcode registry. It binds request/response classes, registers them per-characteristic, and exposes helpers to instantiate or parse by opcode. Update this enum when adding new message pairs.【F:messages/src/main/java/com/jwoglom/pumpx2/pump/messages/Messages.java†L1-L223】【F:messages/src/main/java/com/jwoglom/pumpx2/pump/messages/Messages.java†L223-L394】- When introducing a new message, ensure its annotation references the counterpart class and add the pair to
Messages. Stream responses (e.g., history logs) setstream=trueto route throughStreamPacketArrayList.
- Packet handling & authentication
Packetizeconverts aMessageinto BLE packets: adds opcode, transaction ID, length, optional HMAC-SHA1 signature (24-byte trailer), CRC16, and chunks into MTU-sizedPackets. It enforcesmodifiesInsulinDeliverygating viaPumpStateSupplier.actionsAffectingInsulinDeliveryEnabled.【F:messages/src/main/java/com/jwoglom/pumpx2/pump/messages/Packetize.java†L1-L120】TransactionIdtracks the next transaction identifier (0–255) shared across the session.【F:messages/src/main/java/com/jwoglom/pumpx2/pump/messages/TransactionId.java†L1-L33】PacketArrayList(andStreamPacketArrayListfor streaming opcodes) reassembles multi-packet responses, validates CRC/signature, and enforces expected opcode/size/transaction ID. UsePacketArrayList.buildto obtain the correct parser for a given message/characteristic.【F:messages/src/main/java/com/jwoglom/pumpx2/pump/messages/PacketArrayList.java†L1-L189】【F:messages/src/main/java/com/jwoglom/pumpx2/pump/messages/StreamPacketArrayList.java†L1-L95】PumpStateSupplierprovides Suppliers for authentication material (pairing code or JPAKE-derived secret), pump reset time, API version, and gating flags. Non-Android callers must seed these Suppliers before sending signed requests or parsing signed responses.【F:messages/src/main/java/com/jwoglom/pumpx2/pump/messages/bluetooth/PumpStateSupplier.java†L1-L58】bluetoothsubpackage supplies static metadata (Characteristic,CharacteristicUUID,ServiceUUID,BluetoothConstants) and runtime helpers (BTResponseParser,TronMessageWrapper, BLEPacket/PumpResponseMessagemodels). These utilities are reused by both the Android stack and CLI for parsing raw packets.【F:messages/src/main/java/com/jwoglom/pumpx2/pump/messages/bluetooth/BTResponseParser.java†L1-L120】【F:messages/src/main/java/com/jwoglom/pumpx2/pump/messages/bluetooth/TronMessageWrapper.java†L1-L104】
- Message catalog
- Requests/responses are grouped by domain (
authentication,currentStatus,control,controlStream,historyLog, etc.). Authentication supports both legacy 16-character pairing (CentralChallenge/PumpChallenge) and modern 6-digit JPAKE flow (Jpake1a–Jpake4).【F:messages/src/main/java/com/jwoglom/pumpx2/pump/messages/request/authentication/Jpake1aRequest.java†L1-L57】【F:messages/src/main/java/com/jwoglom/pumpx2/pump/messages/response/authentication/Jpake1aResponse.java†L1-L47】 - Control requests that alter insulin delivery set
signed=trueandmodifiesInsulinDelivery=trueto enforce safety (e.g.,InitiateBolusRequest).【F:messages/src/main/java/com/jwoglom/pumpx2/pump/messages/request/control/InitiateBolusRequest.java†L1-L104】 - History log parsing is centralized in
response/historyLog/HistoryLogParser, which maps 26-byte log records to typed subclasses annotated with@HistoryLogProps. Add new log types here for automatic discovery.【F:messages/src/main/java/com/jwoglom/pumpx2/pump/messages/response/historyLog/HistoryLogParser.java†L1-L105】 response/qualifyingEvent/QualifyingEventenumerates pump events (bitmask) and recommended follow-up requests to pull detailed state.【F:messages/src/main/java/com/jwoglom/pumpx2/pump/messages/response/qualifyingEvent/QualifyingEvent.java†L1-L157】
- Requests/responses are grouped by domain (
- Builders & higher-level logic
builderspackage houses factory helpers that choose version-appropriate messages (ControlIQInfoRequestBuilder,CurrentBatteryRequestBuilder, etc.), orchestration classes likeJpakeAuthBuilder(state machine for the JPAKE pairing handshake), and IDP management helpers. JPAKE builder progresses throughJpakeStepstages, generating requests and consuming responses while caching derived secrets/nonces.【F:messages/src/main/java/com/jwoglom/pumpx2/pump/messages/builders/JpakeAuthBuilder.java†L1-L160】【F:messages/src/main/java/com/jwoglom/pumpx2/pump/messages/builders/JpakeAuthBuilder.java†L161-L320】calculatormodels (BolusCalculator,BolusCalcComponent,BolusCalcDecision, etc.) replicate Tandem’s bolus advisor logic, using helper conversions inmodels/InsulinUnitand data fromBolusCalcDataSnapshotResponse.【F:messages/src/main/java/com/jwoglom/pumpx2/pump/messages/calculator/BolusCalculator.java†L1-L120】helpers/Bytesandhelpers/Datesencapsulate endian-aware numeric and date conversions, CRC-16 computation, and secure randomness. Always use these utilities for parsing/building cargo to avoid manual endian bugs.【F:messages/src/main/java/com/jwoglom/pumpx2/pump/messages/helpers/Bytes.java†L1-L200】util/MessageHelpersgathers reflection helpers (e.g., list all request messages) andArbitraryMessageParsercan parse raw hex by inferring characteristic/opcode, optionally overriding pump time/auth key viaPumpStateSupplier.【F:messages/src/main/java/com/jwoglom/pumpx2/pump/messages/util/ArbitraryMessageParser.java†L1-L72】
- Models & annotations
- Core value objects include
ApiVersion,KnownApiVersion,PairingCodeType,SupportedDevices,NotificationBundle,StatusMessage(responses withgetStatus()),HistoryLogbase class, and error wrappers for unexpected opcodes/transaction IDs.【F:messages/src/main/java/com/jwoglom/pumpx2/pump/messages/models/ApiVersion.java†L1-L44】【F:messages/src/main/java/com/jwoglom/pumpx2/pump/messages/models/NotificationBundle.java†L1-L170】 @ApiVersionDependentmarks classes whose usage varies between API revisions; look for companion builders.
- Core value objects include
androidLib (androidLib/src/main/java/com/jwoglom/pumpx2/pump and /util)
- Android-facing library (
pumpx2-android) that drives BLE connectivity, state persistence, and logging.TandemPumpis the abstract frontend API: override callbacks (onInitialPumpConnection,onWaitingForPairingCode,onReceiveMessage,onReceiveQualifyingEvent, etc.), callsendCommandto transmit requests, and expose pairing UX. It also exposes toggles for connection sharing with the official t:connect app and gating of insulin-affecting actions.【F:androidLib/src/main/java/com/jwoglom/pumpx2/pump/bluetooth/TandemPump.java†L1-L200】【F:androidLib/src/main/java/com/jwoglom/pumpx2/pump/bluetooth/TandemPump.java†L200-L300】TandemBluetoothHandlerowns the BLE central (via the BLESSED library). It manages scanning/bonding, sets MTU and notifications, coordinates authentication (both legacy and JPAKE flows), parses incoming packets with the sharedBTResponseParser, and forwards parsed messages/events to theTandemPumpcallbacks. It also supports connection sharing heuristics with the official app.【F:androidLib/src/main/java/com/jwoglom/pumpx2/pump/bluetooth/TandemBluetoothHandler.java†L1-L200】【F:androidLib/src/main/java/com/jwoglom/pumpx2/pump/bluetooth/TandemBluetoothHandler.java†L300-L492】PumpStateis the Android persistence layer: backs thePumpStateSuppliervia SharedPreferences, tracks request/response queues for transaction IDs, caches pairing/JPAKE secrets, manages connection-sharing flags, and stores pump metadata like serial numbers or reset time.【F:androidLib/src/main/java/com/jwoglom/pumpx2/pump/PumpState.java†L1-L200】【F:androidLib/src/main/java/com/jwoglom/pumpx2/pump/PumpState.java†L200-L314】TandemConfigcollects optional construction parameters (Bluetooth MAC filter, explicit pairing code type, periodic TimeSinceReset polling).【F:androidLib/src/main/java/com/jwoglom/pumpx2/pump/bluetooth/TandemConfig.java†L1-L40】TandemPumpFinderprovides a scanning-only abstraction to surface available pumps before connecting, using similar BLE setup but without sending commands.【F:androidLib/src/main/java/com/jwoglom/pumpx2/pump/bluetooth/TandemPumpFinder.java†L1-L200】TandemErrorenumerates user-visible error causes used by the handler to surface failures.【F:androidLib/src/main/java/com/jwoglom/pumpx2/pump/TandemError.java†L1-L34】util/timberintegrates the shared logging façade with Timber (DebugTree,LConfigurator).EventServiceis a stubServiceplaceholder for broadcast handling.
cliparser (cliparser/src/main/java/com/jwoglom/pumpx2/cliparser)
- Command-line utilities for offline analysis, testing, and message encoding/decoding.
Maindispatches subcommands such asopcode,parse,guesscargo,historylog,json,encode, andjpake. It relies on the sharedmessagesmodule for parsing and on environment variables (PUMP_AUTHENTICATION_KEY,PUMP_PAIRING_CODE,PUMP_TIME_SINCE_RESET) to configurePumpStateSupplier.【F:cliparser/src/main/java/com/jwoglom/pumpx2/cliparser/Main.java†L1-L208】【F:cliparser/src/main/java/com/jwoglom/pumpx2/cliparser/Main.java†L208-L320】- Utilities like
CharacteristicGuesserandJsonMessageParser(not shown above) assist with inference and structured output.
sampleapp (sampleapp/src/main/java/com/jwoglom/pumpx2/example)
- Reference Android application showing how to extend
TandemPumpand orchestrate UI flows.PumpX2TandemPumpsubclassesTandemPump, wires broadcast intents for UI updates, demonstrates history log streaming, bolus flows, and connection sharing enablement.【F:sampleapp/src/main/java/com/jwoglom/pumpx2/example/PumpX2TandemPump.java†L1-L200】MainActivitydrives user interaction, enumerates request message classes, issues commands (bolus permission, history log requests), and handles broadcast responses from the pump callbacks.【F:sampleapp/src/main/java/com/jwoglom/pumpx2/example/MainActivity.java†L1-L160】
- Layout resources (
sampleapp/src/main/res) and manifest configure the example UI.
Key flows & design patterns
- Authentication
- Legacy pumps (API < 3.x) use
CentralChallengeRequest→PumpChallengeRequestwith a 16-character pairing code. Newer pumps use a multi-step JPAKE handshake (Jpake1a→Jpake4).JpakeAuthBuilderdrives the state machine, caching derived secrets/nonces inPumpStatefor subsequent sessions.【F:messages/src/main/java/com/jwoglom/pumpx2/pump/messages/request/authentication/Jpake1aRequest.java†L1-L57】【F:androidLib/src/main/java/com/jwoglom/pumpx2/pump/bluetooth/TandemPump.java†L200-L300】
- Legacy pumps (API < 3.x) use
- Sending commands
TandemPump.sendCommandrecords the pending request inPumpState, packetizes it (including optional signing), and writes the resulting BLE chunks via BLESSED. Signed requests requirePumpStateSupplier.authenticationKey(pairing code or derived secret) and a recentPumpStateSupplier.pumpTimeSinceResetvalue.【F:androidLib/src/main/java/com/jwoglom/pumpx2/pump/bluetooth/TandemPump.java†L60-L135】【F:messages/src/main/java/com/jwoglom/pumpx2/pump/messages/Packetize.java†L1-L120】
- Receiving responses
TandemBluetoothHandlerreassembles packets withPacketArrayList, resolves the original request fromPumpState, parses the message viaMessages, and routes it to the appropriate callback. It tolerates concurrent traffic from the official t:connect app by inspecting unknown transaction IDs and synchronizing the globalTransactionIdcounter.【F:androidLib/src/main/java/com/jwoglom/pumpx2/pump/bluetooth/TandemBluetoothHandler.java†L300-L492】
- History logs
- Request/response flows (
HistoryLogStatusRequest,HistoryLogRequest,HistoryLogStreamResponse) stream fixed-width 26-byte records.HistoryLogParsermaps raw cargo to typed logs; logs expose timestamps relative to Jan 1 2008 viahelpers/Dates.【F:messages/src/main/java/com/jwoglom/pumpx2/pump/messages/response/historyLog/HistoryLogParser.java†L1-L105】【F:messages/src/main/java/com/jwoglom/pumpx2/pump/messages/helpers/Dates.java†L1-L40】
- Request/response flows (
- Bolus workflow
- Bolus control uses a sequence of
BolusPermissionRequest→BolusCalcDataSnapshotRequest/LastBGRequest(optional) →InitiateBolusRequest, tracked throughPumpStateSupplier.inProgressBolusId. Calculations leveragecalculator/BolusCalculatorwhen replicating pump UI logic.【F:messages/src/main/java/com/jwoglom/pumpx2/pump/messages/request/control/InitiateBolusRequest.java†L1-L120】【F:messages/src/main/java/com/jwoglom/pumpx2/pump/messages/calculator/BolusCalculator.java†L1-L120】
- Bolus control uses a sequence of
- Qualifying events
- The pump pushes bitmasks on the
QUALIFYING_EVENTScharacteristic;QualifyingEventtranslates these to enums and suggests follow-up requests. The Android handler treats them separately from standard request/response traffic.【F:messages/src/main/java/com/jwoglom/pumpx2/pump/messages/response/qualifyingEvent/QualifyingEvent.java†L1-L157】【F:androidLib/src/main/java/com/jwoglom/pumpx2/pump/bluetooth/TandemBluetoothHandler.java†L320-L370】
- The pump pushes bitmasks on the
Implementation guidance & gotchas
- Always seed
PumpStateSupplierwhen using the pure-Java library outside Android. Provide pairing code/derived secret, pump time since reset, API version, and optionally Control-IQ support before sending signed messages or verifying signatures.【F:messages/src/main/java/com/jwoglom/pumpx2/pump/messages/bluetooth/PumpStateSupplier.java†L1-L58】 - Guard insulin-delivery commands by calling
PumpState.enableActionsAffectingInsulinDelivery()(orTandemPump.enableActionsAffectingInsulinDelivery()) before invoking messages withmodifiesInsulinDelivery=true; otherwisePacketizethrows an exception.【F:messages/src/main/java/com/jwoglom/pumpx2/pump/messages/Packetize.java†L60-L101】【F:androidLib/src/main/java/com/jwoglom/pumpx2/pump/bluetooth/TandemPump.java†L230-L246】 - Updating message catalog
- Create new request/response classes with
@MessageProps, implementparse, and supply staticbuildCargohelpers for deterministic construction. - Add the pair to
Messages(respect the// IMPORT_END/// MESSAGES_ENDmarkers that scripts use) so parsing works globally.【F:messages/src/main/java/com/jwoglom/pumpx2/pump/messages/Messages.java†L1-L223】【F:messages/src/main/java/com/jwoglom/pumpx2/pump/messages/Messages.java†L223-L394】 - For new history logs, implement a
HistoryLogsubclass annotated with@HistoryLogPropsand register it inHistoryLogParser.LOG_MESSAGE_TYPES.
- Create new request/response classes with
- Packet parsing edge cases
- Some responses have variable cargo sizes (e.g.,
ErrorResponse,ApiVersionResponse).PacketArrayList.parsecontains special cases—mirror those patterns if you add new variable-length messages.【F:messages/src/main/java/com/jwoglom/pumpx2/pump/messages/PacketArrayList.java†L80-L142】 - HMAC validation can be bypassed for debugging by setting the authentication key prefix to
IGNORE_HMAC_SIGNATURE_EXCEPTION(used by the CLI when no pairing code is available).【F:messages/src/main/java/com/jwoglom/pumpx2/pump/messages/PacketArrayList.java†L156-L189】
- Some responses have variable cargo sizes (e.g.,
- Transaction ID management
PumpStatetracks outstanding requests by(Characteristic, txId). Always push requests viaTandemPump.sendCommand(or replicate its bookkeeping) to avoid parse failures on incoming responses.【F:androidLib/src/main/java/com/jwoglom/pumpx2/pump/PumpState.java†L200-L259】
- Connection sharing
PumpStateexposes flags to cooperate with the official t:connect app (e.g., rely on shared authentication, suppress critical errors). Set these early (in yourTandemPumpconstructor) if you intend to piggyback on an existing connection.【F:androidLib/src/main/java/com/jwoglom/pumpx2/pump/PumpState.java†L314-L339】【F:androidLib/src/main/java/com/jwoglom/pumpx2/pump/bluetooth/TandemPump.java†L230-L300】
- Logging
- For Android, install a Timber tree (by default
TandemBluetoothHandlerplantsDebugTree) to route shared logging through Timber viaLConfigurator. CLI utilities redirect logging to stderr viaL.getPrintln.【F:androidLib/src/main/java/com/jwoglom/pumpx2/util/timber/DebugTree.java†L1-L25】【F:cliparser/src/main/java/com/jwoglom/pumpx2/cliparser/Main.java†L1-L50】
- For Android, install a Timber tree (by default
Testing & debugging tips
- Unit tests cover byte helpers, crypto helpers, message builders, and JPAKE flows. Use them as references when implementing new features.【83f740†L1-L10】
- The CLI
cliparseris invaluable for parsing captured Bluetooth logs, testing HMAC signing (viaencode), or walking through JPAKE handshake steps (jpakecommand expects interactive input/output).【F:cliparser/src/main/java/com/jwoglom/pumpx2/cliparser/Main.java†L1-L208】 - Sample app broadcasts (constants in
PumpX2TandemPump) make it easy to instrument UI listeners without modifying library internals.【F:sampleapp/src/main/java/com/jwoglom/pumpx2/example/PumpX2TandemPump.java†L1-L120】 - When debugging connection issues, inspect logs around MTU negotiation, notification enabling, and transaction ID alignment—the handler logs every sent/received packet and opcode in verbose mode.【F:androidLib/src/main/java/com/jwoglom/pumpx2/pump/bluetooth/TandemBluetoothHandler.java†L300-L492】
Additional resources in the repo
- Markdown guides such as
mobile_bolus.mdandfill_cart_tubing_cannula.mddocument observed pump behavior for specific workflows (bolus, fill tubing/cannula). Reference these when implementing higher-level flows. messages/src/main/java/.../README.mdsummarizes the initial handshake steps (CentralChallenge,PumpChallenge,ApiVersion).【F:messages/src/main/java/com/jwoglom/pumpx2/pump/messages/README.md†L1-L15】- Shell/Python scripts in
scripts/assist with parsing captured BLE traffic; inspect them if you need concrete examples of encoded packets.
Working in this repository
- Follow the existing formatting and helper patterns; use the
Byteshelper for all numeric conversions and preferJavaHelpers.autoToStringfortoStringimplementations. - Respect the safety gates around insulin-affecting commands and ensure new features continue to enforce them.
- Update this
AGENTS.mdif you discover additional architectural conventions that would help future contributors.
