🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
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
- Prints values via
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
Option A: Modify Existing Command (RECOMMENDED)
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:
- Programmatic field detection - enables automation scripts
- Precise measurements - get exact mV values, not just on/off
- Multi-device coordination - essential for systems like Dangerous Pi
- 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 patternCMD_MEASURE_ANTENNA_TUNING_LF- dual-value reporting- Both accepted upstream
Preparation for PR
Before submitting:
- Test on multiple hardware variants (Easy, RDV4)
- Document in CHANGELOG.md
- Add usage examples in commit message
- Reference this research doc
- 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:
- Low Risk: Follows proven patterns, minimal code changes
- High Value: Enables precise field detection with programmable LED control
- Clean Design: Mode-based approach is elegant and backwards compatible
- Manageable Effort: ~1 hour total implementation time
- Upstream Potential: High probability of acceptance
Next Steps:
- Schedule implementation session (60 min)
- Prepare test equipment (LF reader, HF reader/NFC phone)
- Have backup: keep current working firmware binary
- 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