Project 8: Complete Cardputer Security Toolkit (Capstone)

Integrate WiFi tools, BLE/USB HID, IR control, GPS logging, and audio spectrum into one cohesive firmware with shared services, consistent UI, and robust power management.

Quick Reference

Attribute Value
Difficulty Master
Time Estimate 2–3 months
Main Programming Language C/C++ (ESP-IDF)
Alternative Programming Languages None (integration requires full control)
Coolness Level Extreme
Business Potential High (multi-tool field platform)
Prerequisites Completed prior projects, strong RTOS skills
Key Topics subsystem arbitration, settings, power management, OTA/safe boot

1. Learning Objectives

By completing this project, you will:

  1. Integrate multiple complex subsystems without conflicts.
  2. Build a global service registry and enforce resource arbitration.
  3. Implement persistent settings with versioned migrations.
  4. Design power management strategies for a battery device.
  5. Implement OTA updates and safe boot recovery.

2. All Theory Needed (Per-Concept Breakdown)

2.1 Subsystem Arbitration and Global State Machines

Fundamentals

When multiple subsystems share hardware (WiFi, display, SD card), you must decide which one owns each resource at any time. Arbitration is the policy that prevents two modules from fighting for the same resource. A global state machine coordinates tool modes, transitions, and resource ownership so the device behaves predictably.

Deep Dive into the concept

A toolkit that combines WiFi sniffing, BLE HID, USB HID, IR, GPS, and audio must coordinate radios, buses, and CPU time. WiFi and BLE share the 2.4 GHz radio; they cannot always run at full capacity simultaneously. USB uses a separate peripheral but consumes CPU and DMA. The display and SD card share SPI bandwidth. Without arbitration, a WiFi sniffer may starve the UI or an audio analyzer may stutter when SD logging occurs.

A global state machine defines modes such as WIFI_SNIFFER, BLE_HID, IR_REMOTE, AUDIO_SPECTRUM, WARDIVE, and IDLE. Each mode declares which services it needs. The service registry then grants or denies access based on current mode and policy. For example, if WiFi sniffer is active, BLE HID might be paused or disabled. Mode transitions should include teardown and reinit steps so each subsystem is reset to a known state.

Arbitration can be implemented with a central “resource manager” that exposes acquire/release APIs. Each subsystem requests a resource and the manager checks availability. If denied, the subsystem can either wait or degrade. This makes conflicts explicit and testable. For example, if the user switches from WiFi sniffer to BLE HID, the manager should stop WiFi, wait for cleanup, then enable BLE. This is a deterministic transition, not a race.

UI should reflect arbitration decisions. If a tool cannot run because another tool is active, the UI should explain why. This reduces user confusion and prevents accidental misuse. In a capstone system, clarity is as important as raw functionality.

How this fits in projects

This builds on the mini-OS architecture from P06-custom-application-launcher-mini-os.md and integrates tools from all previous projects.

Definitions & key terms

  • Arbitration → policy for exclusive access to shared resources
  • Global state machine → central controller for mode transitions
  • Resource manager → component granting/releasing resources
  • Degrade → fallback behavior when resource is unavailable

Mental model diagram (ASCII)

[Mode Manager] -> [Resource Manager]
        |                 |
        v                 v
   [Active Tool]     [Shared Services]

How it works (step-by-step, with invariants and failure modes)

  1. User selects a tool mode.
  2. Mode manager requests required resources.
  3. Resource manager grants or denies.
  4. Tool initializes and runs.
  5. On exit, resources released and next tool can start.

Invariants: only one owner per resource; transitions are serialized. Failure modes: two tools run on same resource, causing crashes or corruption.

Minimal concrete example

if (!resource_acquire(WIFI)) return ERR_BUSY;

Common misconceptions

  • “ESP32 can handle everything at once.” → Radios and buses have limits.
  • “Conflicts are rare.” → They are common when subsystems grow.
  • “Users will understand failures.” → Without explicit UI, they won’t.

Check-your-understanding questions

  1. Why can’t WiFi sniffer and BLE HID always run together?
  2. What does a resource manager do?
  3. Why is a global state machine necessary?

Check-your-understanding answers

  1. They share the radio and timing resources, causing conflicts.
  2. It grants or denies exclusive access to shared hardware.
  3. It ensures deterministic transitions and avoids race conditions.

Real-world applications

  • Multi-tool industrial handhelds.
  • Security assessment devices.

Where you’ll apply it

  • This project: see §4.1 architecture and §5.10 Phase 1.
  • Also used in: P06-custom-application-launcher-mini-os.md.

References

  • Embedded systems resource arbitration patterns.
  • Making Embedded Systems – system integration chapters.

Key insight

Integration is mostly about enforcing boundaries, not adding features.

Summary

Centralize resource ownership and use a state machine to keep subsystems from colliding.

Homework/Exercises to practice the concept

  1. Define a table of resources required by each tool.
  2. Implement a resource acquire/release API.

Solutions to the homework/exercises

  1. List WiFi, BLE, USB, SD, Display, Audio, IR.
  2. Implement a bitmask and return ERR_BUSY if occupied.

2.2 Persistent Settings, Schema Migration, and Data Integrity

Fundamentals

A toolkit must remember settings across reboots: user preferences, last used tool, WiFi channels, and macro profiles. Settings storage must be versioned so you can change formats without breaking old data. This requires a schema version and migration logic.

Deep Dive into the concept

Settings are a form of data storage. Unlike logs, settings must survive updates and power loss. The ESP32 provides NVS (non-volatile storage), which stores key-value pairs with integrity checks. You should define a settings struct with a version field. On boot, read the version; if it’s older than the current schema, run a migration function that upgrades or resets fields. For example, if you add a new “default channel” setting in version 2, the migration should set it to a safe default when reading a version 1 record.

Data integrity requires validation. If settings are corrupt, you should reset to defaults and inform the user. Use checksums if you store binary blobs on SD. For settings stored in NVS, rely on NVS integrity, but still validate ranges (e.g., channel must be 1–13). For complex data like macro scripts or IR profiles, keep them as separate files with their own checksums. This isolates corruption and avoids breaking the entire system.

Migration must be deterministic. Define a migration path from each previous version to the current. Avoid “best effort” guessing. If you cannot migrate, reset and inform the user. This keeps the system predictable. Also consider exporting/importing settings as JSON so users can back up configurations. This aligns with the project’s emphasis on durability.

How this fits in projects

Settings storage builds on the logging and storage work from P01-wifi-packet-sniffer-network-analyzer.md and P05-wardriving-wifi-mapper.md.

Definitions & key terms

  • Schema version → number indicating settings format
  • Migration → transformation from old schema to new
  • NVS → non-volatile storage on ESP32
  • Validation → range checks and integrity checks

Mental model diagram (ASCII)

[Settings v1] -> [Migration] -> [Settings v2] -> [Validation]

How it works (step-by-step, with invariants and failure modes)

  1. Load settings blob and version.
  2. If version < current, run migrations.
  3. Validate fields and ranges.
  4. Save updated settings back to NVS.

Invariants: version always stored; migrations deterministic. Failure modes: corrupt data resets to defaults; invalid ranges cause crashes if unchecked.

Minimal concrete example

if (settings.version == 1) migrate_v1_to_v2(&settings);

Common misconceptions

  • “Settings never change.” → They will as features grow.
  • “NVS data is always valid.” → Validate ranges anyway.
  • “Migration is optional.” → Without it, updates break users.

Check-your-understanding questions

  1. Why include a schema version?
  2. What should you do if migration fails?
  3. Why validate settings ranges?

Check-your-understanding answers

  1. To know how to interpret stored data and upgrade it.
  2. Reset to safe defaults and notify the user.
  3. To prevent invalid values from crashing subsystems.

Real-world applications

  • Consumer devices with firmware updates.
  • Industrial tools requiring long-term stability.

Where you’ll apply it

  • This project: see §3.2 requirement 3 and §5.10 Phase 2.
  • Also used in: P06-custom-application-launcher-mini-os.md for settings persistence.

References

  • ESP-IDF NVS documentation.
  • Embedded data migration patterns.

Key insight

Settings are a contract with your users; breaking them breaks trust.

Summary

Version your settings, validate ranges, and implement deterministic migrations.

Homework/Exercises to practice the concept

  1. Define a settings struct with version and defaults.
  2. Write a migration from v1 to v2 that adds a field.

Solutions to the homework/exercises

  1. Include version, default_mode, brightness, channel.
  2. Add channel with default 6 when migrating.

2.3 Power Management, OTA Updates, and Safe Boot

Fundamentals

A battery-powered toolkit must manage power. It should dim the display, disable radios when idle, and sleep when inactive. OTA (over-the-air) updates let you deliver fixes without physical access, but they introduce risk: a failed update can brick the device. Safe boot strategies ensure recovery.

Deep Dive into the concept

Power management begins with measurement. You must know the current draw of each subsystem (WiFi, BLE, display, audio). Implement a power profile table and track active components. For example, when switching from WiFi sniffer to BLE HID, you can disable WiFi, reducing draw. The display is often the largest consumer; implement auto-dim and a “low power” mode with reduced refresh.

Sleep modes can extend battery life. Light sleep keeps RAM and wake sources (buttons, timers); deep sleep resets the CPU but saves more power. In a toolkit, you might use light sleep when idle and deep sleep for long inactivity. Provide a setting to configure timeout. If you enter sleep, ensure you flush logs and save settings.

OTA updates require a dual-partition strategy. ESP-IDF supports OTA partitions: you download firmware into the inactive partition, verify it, then reboot into it. If the new firmware fails, a rollback should occur. A safe boot counter can detect repeated crashes and revert to the previous firmware. Additionally, keep a “safe mode” boot: if the user holds a key during boot, the system boots with minimal services (no WiFi, no OTA) to allow recovery.

Power management and OTA are deeply linked. During OTA, you must ensure sufficient battery to avoid interruption. If the battery is low, defer the update. Log update status to the SD card or NVS. These details are what make a field-ready product.

How this fits in projects

Power and OTA concerns are the final integration layer on top of all previous projects.

Definitions & key terms

  • Light sleep → low-power mode with RAM retained
  • Deep sleep → lowest power mode, resets CPU
  • OTA partition → inactive slot for firmware update
  • Rollback → revert to previous firmware after failure

Mental model diagram (ASCII)

[Active Firmware] -> [OTA Download] -> [Verify] -> [Reboot]
            ^                               |
            +--------- Rollback ------------+

How it works (step-by-step, with invariants and failure modes)

  1. Check battery level and network availability.
  2. Download OTA to inactive partition.
  3. Verify checksum and signature.
  4. Reboot into new partition.
  5. If boot fails, rollback to previous firmware.

Invariants: never update on low battery; always verify image. Failure modes: power loss during OTA, corrupted image, boot loops.

Minimal concrete example

if (battery_pct < 30) return ERR_LOW_BATT;

Common misconceptions

  • “OTA is just download and reboot.” → Verification and rollback are critical.
  • “Sleep is optional.” → Battery devices demand power management.
  • “Safe boot isn’t needed.” → Recovery is essential in the field.

Check-your-understanding questions

  1. Why use dual OTA partitions?
  2. What triggers a rollback?
  3. Why avoid OTA on low battery?

Check-your-understanding answers

  1. To keep a known-good firmware while updating.
  2. Repeated boot failures or explicit validation failure.
  3. Power loss during update can brick the device.

Real-world applications

  • Consumer IoT devices and handheld tools.
  • Industrial devices requiring safe firmware updates.

Where you’ll apply it

  • This project: see §3.2 requirement 5 and §5.10 Phase 3.

References

  • ESP-IDF OTA documentation.
  • Power management guidelines for ESP32.

Key insight

A toolkit that can’t update or conserve power won’t survive real-world use.

Summary

Combine power profiling, sleep strategies, and OTA rollback to build a resilient device.

Homework/Exercises to practice the concept

  1. Measure current draw in each mode and log results.
  2. Implement a safe boot key combo that bypasses modules.

Solutions to the homework/exercises

  1. Use a USB power meter and record draw per mode.
  2. Check key state on boot and skip module init if pressed.

3. Project Specification

3.1 What You Will Build

A unified toolkit that:

  • provides a home screen with multiple tools,
  • shares services and settings,
  • logs data to SD with consistent structure,
  • supports OTA updates and safe boot.

3.2 Functional Requirements

  1. Mode manager: switch tools without reboot.
  2. Resource arbitration: enforce ownership of WiFi, BLE, SD, display.
  3. Settings persistence: versioned settings with migration.
  4. Power management: dim display, manage radios, sleep.
  5. OTA updates: safe update with rollback.

3.3 Non-Functional Requirements

  • Reliability: stable mode switching under load.
  • Performance: UI remains responsive across tools.
  • Safety: OTA never bricks device.

3.4 Example Usage / Output

1) Boot to toolkit home screen
2) Switch between WiFi and BLE tools
3) Update firmware via OTA

3.5 Data Formats / Schemas / Protocols

  • Shared settings schema (versioned).
  • Unified logs folder structure (per tool).

3.6 Edge Cases

  • Switch modes while SD is writing.
  • OTA update interrupted by low battery.
  • WiFi and BLE requested simultaneously.

3.7 Real World Outcome

A successful build behaves like a polished product: tools switch instantly, settings persist, battery life is acceptable, and OTA updates are safe. Logs are organized by tool and date.

3.7.1 How to Run (Copy/Paste)

idf.py set-target esp32s3
idf.py build
idf.py -p /dev/ttyUSB0 flash monitor

3.7.2 Golden Path Demo (Deterministic)

  • Boot, switch between three tools 10 times.
  • Perform OTA update with battery > 50%.
  • Verify rollback works by simulating failure.

Failure demo (deterministic):

  • Start OTA update with battery at 20%. Expected: OTA is refused, UI shows “LOW BATTERY,” and no partition switch occurs. Exit code: 2.

3.7.3 If CLI: exact terminal transcript

I (8100) toolkit: mode=WiFiSniffer
I (8101) toolkit: switch->BLEHID ok
I (8102) ota: download ok verify ok
I (8103) ota: rebooting into slot 1

Exit codes: 0 = success, 2 = OTA blocked (low battery), 3 = resource conflict, 4 = OTA verify failure.

3.7.4 If Web App

Not applicable.

3.7.5 If API

Not applicable.

3.7.6 If Library

Not applicable.

3.7.7 If GUI / Desktop / Mobile

Not applicable.

3.7.8 If TUI

+----------------------------+
| CARDPUTER TOOLKIT          |
| [1] WiFi Sniffer           |
| [2] Wardrive               |
| [3] BLE HID                |
| [4] USB HID                |
| [5] IR Remote              |
| [6] Spectrum               |
+----------------------------+

4. Solution Architecture

4.1 High-Level Design

[Launcher] -> [Mode Manager] -> [Tool Modules]
                 |
                 v
          [Resource Manager]

4.2 Key Components

Component Responsibility Key Decisions
Mode manager tool switching serialized transitions
Resource manager arbitration deny conflicting access
Settings service persistent config versioned schema
Power manager sleep + dim policies per mode
OTA manager updates + rollback dual partitions

4.3 Data Structures (No Full Code)

typedef struct {
    uint8_t version;
    uint8_t default_mode;
    uint8_t brightness;
} settings_t;

4.4 Algorithm Overview

Key Algorithm: Mode Transition

  1. Stop current tool and release resources.
  2. Apply new mode power profile.
  3. Acquire resources for new tool.
  4. Start tool and update UI.

Complexity Analysis:

  • Time: O(1) per transition
  • Space: O(1)

5. Implementation Guide

5.1 Development Environment Setup

idf.py set-target esp32s3
idf.py build

5.2 Project Structure

project-root/
├── main/
│   ├── mode_manager.c
│   ├── resource_manager.c
│   ├── settings.c
│   ├── power.c
│   ├── ota.c
│   └── ui.c
└── README.md

5.3 The Core Question You’re Answering

“How do I integrate multiple complex subsystems into one stable product?”

5.4 Concepts You Must Understand First

  1. Resource arbitration.
  2. Settings migration.
  3. Power management + OTA.

5.5 Questions to Guide Your Design

  1. Which tools can coexist, and which are mutually exclusive?
  2. How will you migrate settings across versions?
  3. How do you prevent OTA on low battery?

5.6 Thinking Exercise

Design a table of tool modes and required resources, then identify conflicts.

5.7 The Interview Questions They Will Ask

  1. How do you manage resource conflicts on embedded devices?
  2. What is your OTA rollback strategy?
  3. How do you ensure settings compatibility across versions?

5.8 Hints in Layers

Hint 1: Start with a launcher that switches between two tools.

Hint 2: Add a resource manager that denies conflicts.

Hint 3: Add settings and OTA last.

5.9 Books That Will Help

Topic Book Chapter
Systems integration Making Embedded Systems Ch. 9–10
Software architecture Clean Architecture Ch. 1–3

5.10 Implementation Phases

Phase 1: Mode manager + resource arbitration (3–4 weeks)

Phase 2: Settings + persistence (2–3 weeks)

Phase 3: Power + OTA + safe boot (3–4 weeks)

5.11 Key Implementation Decisions

Decision Options Recommendation Rationale
Resource conflicts deny or degrade deny unless safe predictable behavior
Settings NVS or file NVS + file for large data durability
OTA policy always only if battery > 30% reduce risk

6. Testing Strategy

6.1 Test Categories

Category Purpose Examples
Integration Tests mode switches 100 transitions
Reliability Tests OTA rollback forced failure
Power Tests battery draw per-mode measurement

6.2 Critical Test Cases

  1. Rapid mode switching without crashes.
  2. OTA update rollback after simulated failure.
  3. Power consumption within target range.

6.3 Test Data

Synthetic mode switch script
OTA test images

7. Common Pitfalls & Debugging

7.1 Frequent Mistakes

Pitfall Symptom Solution
No resource arbitration random crashes enforce resource manager
No settings migration upgrade breaks configs add schema version
OTA without checks bricked device add verification + rollback

7.2 Debugging Strategies

  • Log mode transitions and resource grants.
  • Simulate OTA failures to validate rollback.

7.3 Performance Traps

  • Running WiFi + BLE + UI at max load without power budgeting.

8. Extensions & Challenges

8.1 Beginner Extensions

  • Add per-tool themes or UI skins.

8.2 Intermediate Extensions

  • Add backup/restore of settings to SD.

8.3 Advanced Extensions

  • Add plug-in system for external modules.

9. Real-World Connections

9.1 Industry Applications

  • Multi-tool cybersecurity devices.
  • Field diagnostics platforms.
  • ESP32 OTA examples.

9.3 Interview Relevance

  • Systems integration and reliability engineering.

10. Resources

10.1 Essential Reading

  • ESP-IDF OTA and power management docs.

10.2 Video Resources

  • Embedded OTA update talks.

10.3 Tools & Documentation

  • ESP-IDF resource manager patterns.
  • P01-wifi-packet-sniffer-network-analyzer.md
  • P06-custom-application-launcher-mini-os.md

11. Self-Assessment Checklist

11.1 Understanding

  • I can explain resource arbitration.
  • I can explain OTA rollback.

11.2 Implementation

  • Modes switch without conflicts.
  • Settings persist across reboots.

11.3 Growth

  • I can design safe boot recovery flows.

12. Submission / Completion Criteria

Minimum Viable Completion:

  • Mode manager and two integrated tools.

Full Completion:

  • All tools integrated with resource arbitration and settings.

Excellence (Going Above & Beyond):

  • Safe OTA updates and power management policies.