Files
pi-pm3/FIELD_STRENGTH_REPORTING_RESEARCH.md
michael 4f35df1781 Initial commit - Phase 3/4
🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-06 13:46:22 -08:00

12 KiB

Field Strength Reporting - Firmware Modification Research

Executive Summary

Goal: Modify PM3 firmware to report real-time LF and HF field strength values to enable LED brightness control via Lua script.

Verdict: LOW IMPACT, RECOMMENDED FOR IMPLEMENTATION

The modification is straightforward, follows existing patterns, and has minimal risk. Estimated implementation time: 45-60 minutes including testing.


Current Situation

Existing hw detectreader Command

  • Uses CMD_LISTEN_READER_FIELD (0x0420)
  • Firmware function: ListenReaderField() in armsrc/appmain.c:686-850
  • Problem: Firmware only:
    • Prints values via Dbprintf() (debug output, not accessible from Lua)
    • Controls LEDs directly in firmware (hard-coded patterns)
    • Never sends field strength data back to client

What We Need

  • Continuous streaming of LF and HF field strength values (in mV)
  • Accessible from Lua scripts via reply_ng()
  • Update rate: ~20 Hz (50ms intervals)
  • Data format: Two uint16_t values (LF voltage, HF voltage)

Proposed Solution

Architecture Pattern

Follow the existing CMD_MEASURE_ANTENNA_TUNING_HF pattern:

Mode-based state machine:

Mode 1: Initialize measurement (reply with PM3_SUCCESS)
Mode 2: Measure and return data (reply with field strength values)
Mode 3: Shutdown (reply with PM3_SUCCESS)

This pattern is proven, well-tested, and already used successfully.

Implementation Approach

Extend CMD_LISTEN_READER_FIELD to support data reporting

Pros:

  • No new command ID needed
  • Leverages existing hardware code
  • Backwards compatible (mode 1 = current behavior, mode 2 = new streaming)
  • Minimal code changes

Cons:

  • Slight complexity in command handler (mode switching)

Option B: Create New Command

Add CMD_LISTEN_READER_FIELD_STREAM (0x0421)

Pros:

  • Cleaner separation of concerns
  • No risk to existing hw detectreader functionality

Cons:

  • Need to allocate new command ID
  • Duplicate some existing code
  • More changes required

Recommendation: Option A - Extend existing command with mode parameter


Required Changes

1. Firmware Changes (armsrc/appmain.c)

Location: ListenReaderField() function, line 686

Change:

// Current: void ListenReaderField(uint8_t limit)
// Modified: void ListenReaderField(uint8_t limit, uint8_t mode)

// Add mode parameter:
// mode 0: Original behavior (LED patterns, debug output)
// mode 1: Stream data mode (send values via reply_ng)

Modification in main loop (lines 744-778):

if (mode == 1) {
    // Create payload struct
    struct {
        uint16_t lf_mv;
        uint16_t hf_mv;
    } __attribute__((packed)) payload;

    payload.lf_mv = lf_av;
    payload.hf_mv = hf_av;

    // Send values back to client
    reply_ng(CMD_LISTEN_READER_FIELD, PM3_SUCCESS,
             (uint8_t *)&payload, sizeof(payload));
}

Lines of code to add: ~20 lines Lines to modify: ~5 lines Risk level: LOW (contained change, existing patterns)

2. Command Handler Changes (armsrc/appmain.c)

Location: case CMD_LISTEN_READER_FIELD: line 2543

Change:

case CMD_LISTEN_READER_FIELD: {
    if (packet->length != 2)  // Was: != 1
        break;
    uint8_t limit = packet->data.asBytes[0];
    uint8_t mode = packet->data.asBytes[1];  // NEW
    ListenReaderField(limit, mode);          // Pass mode
    reply_ng(CMD_LISTEN_READER_FIELD, PM3_EOPABORTED, NULL, 0);
    break;
}

Lines to modify: 3 lines Risk level: MINIMAL

3. Client Changes (client/src/cmdhw.c)

Location: CmdDetectReader() function, line 534

No changes required - existing hw detectreader continues to work (mode=0)

For new Lua script:

-- Send mode=1 to enable streaming
local data = string.char(limit, 1)  -- limit, mode
command = Command:newNG{
    cmd = cmds.CMD_LISTEN_READER_FIELD,
    data = data
}

4. Optional: Add Payload Structure (include/pm3_cmd.h)

Location: After line 246

Add:

// Field strength measurement payload
typedef struct {
    uint16_t lf_mv;  // LF field strength in millivolts
    uint16_t hf_mv;  // HF field strength in millivolts
} PACKED payload_field_strength_t;

Lines to add: 5 lines Risk level: ZERO (optional documentation, doesn't affect functionality)


Potential Complications & Mitigations

1. SWIG Python Wrapper

Issue: If we modify pm3_cmd.h, SWIG must be rebuilt Impact: Medium (requires manual rebuild) Mitigation:

  • Document rebuild requirement
  • Add to our build script
  • Only affects Python bindings (Lua unaffected)

Commands:

cd client/experimental_lib
./00make_swig.sh
./01make_lib.sh

2. Backwards Compatibility

Issue: Old clients won't understand mode parameter Impact: LOW Mitigation:

  • Old clients send 1 byte (mode defaults to 0)
  • New clients send 2 bytes (mode specified)
  • Firmware handles both gracefully

3. Update Rate Performance

Issue: 20 Hz update rate = 20 USB packets/sec Impact: MINIMAL Analysis:

  • Each packet: ~20 bytes (4 bytes payload + overhead)
  • Total bandwidth: 400 bytes/sec = 0.4 KB/sec
  • USB 2.0 full-speed: 12 Mbps = 1.5 MB/sec
  • Utilization: 0.027% - negligible

4. Firmware Flash Size

Issue: Adding code increases firmware size Impact: NEGLIGIBLE Analysis:

  • Adding ~20 lines ≈ 200-300 bytes compiled
  • Current firmware size: ~200 KB (typical)
  • Flash capacity: 512 KB (PM3 Easy)
  • Increase: <0.15% - safe margin

5. Testing Requirements

Issue: Need to verify on actual hardware Impact: Medium (requires physical device) Test cases:

1. LF field detection (125 kHz reader)
2. HF field detection (13.56 MHz reader/phone NFC)
3. Simultaneous LF+HF
4. Backwards compatibility (old hw detectreader still works)
5. LED brightness control from Lua

Build & Flash Process

1. Modify Code

  • Edit armsrc/appmain.c (~25 lines)
  • Optional: Edit include/pm3_cmd.h (~5 lines)

2. Compile Firmware

cd /home/work/dangerous-pi/.pm3-test/proxmark3
make clean
SKIPQT=1 make -j8 armsrc/obj/fullimage.elf

Time: ~2-3 minutes

3. Flash Firmware

./pm3-flash-all

Time: ~30 seconds

4. Test

./pm3 -c "hw detectreader"  # Old command still works
./pm3 -c "script run field_strength_test"  # New streaming

Time: ~5 minutes

5. Rebuild SWIG (if pm3_cmd.h modified)

cd client/experimental_lib
./00make_swig.sh
./01make_lib.sh

Time: ~1 minute

Total Time: 10-15 minutes


Upstreaming Potential

Why This Is a Good Upstream Contribution

Benefits to PM3 Community:

  1. Programmatic field detection - enables automation scripts
  2. Precise measurements - get exact mV values, not just on/off
  3. Multi-device coordination - essential for systems like Dangerous Pi
  4. Backwards compatible - doesn't break existing tools

Follows Iceman Fork Conventions:

  • Uses CLIParser patterns (already established)
  • reply_ng() for data transfer
  • Mode-based state machine (proven pattern)
  • Minimal, focused changes
  • No breaking changes
  • Self-documented code

Similar Precedents:

  • CMD_MEASURE_ANTENNA_TUNING_HF - exact same pattern
  • CMD_MEASURE_ANTENNA_TUNING_LF - dual-value reporting
  • Both accepted upstream

Preparation for PR

Before submitting:

  1. Test on multiple hardware variants (Easy, RDV4)
  2. Document in CHANGELOG.md
  3. Add usage examples in commit message
  4. Reference this research doc
  5. Emphasize automation/multi-device use case

Estimated acceptance probability: HIGH (70-80%)


Risk Assessment Matrix

Risk Factor Probability Impact Mitigation
Compilation errors Low Low Follow existing patterns exactly
Runtime crashes Very Low Medium Contained changes, tested pattern
SWIG rebuild required Certain Low Documented procedure, quick rebuild
Backwards compatibility broken Very Low High Dual-mode design prevents this
Flash size exceeded Very Low High Change is <1KB, plenty of margin
USB bandwidth issues Very Low Low 0.027% utilization
Upstream rejection Medium Low Feature is useful, well-implemented

Overall Risk: LOW


Implementation Timeline

Phase 1: Core Implementation (30 min)

  • Modify ListenReaderField() function
  • Update command handler
  • Optional: Add payload struct
  • Compile & flash

Phase 2: Testing (15 min)

  • Test LF field detection
  • Test HF field detection
  • Verify backwards compatibility
  • Test LED brightness control

Phase 3: Documentation (15 min)

  • Update script documentation
  • Create usage examples
  • Document SWIG rebuild if needed

Total Estimated Time: 60 minutes


Alternative Approaches Considered

Alt 1: Parse Debug Output

Rejected: Hacky, unreliable, requires USB CDC mode

Alt 2: Use Existing hw detectreader As-Is

Rejected: Can't control LEDs precisely, no programmable access

Alt 3: Create Entirely New Command

Rejected: Unnecessary duplication, more complex

Alt 4: Firmware-only LED Control

Rejected: Not flexible enough, can't adapt patterns


Decision Matrix

Criteria Weight Score (1-10) Weighted
Implementation Effort 20% 9 1.8
Code Complexity 15% 8 1.2
Risk Level 25% 9 2.25
Maintainability 15% 9 1.35
Upstream Acceptance 15% 7 1.05
Feature Completeness 10% 10 1.0

Total Score: 8.65 / 10


Recommendation

PROCEED WITH IMPLEMENTATION

Justification:

  1. Low Risk: Follows proven patterns, minimal code changes
  2. High Value: Enables precise field detection with programmable LED control
  3. Clean Design: Mode-based approach is elegant and backwards compatible
  4. Manageable Effort: ~1 hour total implementation time
  5. Upstream Potential: High probability of acceptance

Next Steps:

  1. Schedule implementation session (60 min)
  2. Prepare test equipment (LF reader, HF reader/NFC phone)
  3. Have backup: keep current working firmware binary
  4. Document changes for potential upstream PR

Code Diff Preview

armsrc/appmain.c - Function Signature

-void ListenReaderField(uint8_t limit) {
+void ListenReaderField(uint8_t limit, uint8_t mode) {

armsrc/appmain.c - Streaming Mode

         if (mode == 2) {
+        } else if (mode == 3) {
+            // Streaming mode - send values back to client
+            if (limit == LF_ONLY || limit == LF_HF_BOTH) {
+                struct {
+                    uint16_t lf_mv;
+                    uint16_t hf_mv;
+                } __attribute__((packed)) payload = {
+                    .lf_mv = lf_av,
+                    .hf_mv = hf_av
+                };
+                reply_ng(CMD_LISTEN_READER_FIELD, PM3_SUCCESS,
+                         (uint8_t *)&payload, sizeof(payload));
+            }
         }

armsrc/appmain.c - Command Handler

         case CMD_LISTEN_READER_FIELD: {
-            if (packet->length != sizeof(uint8_t))
+            if (packet->length != 1 && packet->length != 2)
                 break;
-            ListenReaderField(packet->data.asBytes[0]);
+            uint8_t limit = packet->data.asBytes[0];
+            uint8_t mode = (packet->length == 2) ? packet->data.asBytes[1] : 0;
+            ListenReaderField(limit, mode);
             reply_ng(CMD_LISTEN_READER_FIELD, PM3_EOPABORTED, NULL, 0);
             break;
         }

Conclusion

The firmware modification to enable field strength reporting is:

  • Technically sound - follows existing patterns
  • Low risk - minimal, contained changes
  • High value - enables powerful scripting capabilities
  • Reasonable effort - ~1 hour implementation
  • Upstream ready - good candidate for contribution

Confidence Level: (Very High)

Recommendation: Proceed with implementation in next session.


Research completed: 2025-12-02 Researcher: Claude (Dangerous Pi Project) Status: Ready for implementation