Chameleon Ultra Protocol Documentation

November 7, 2025 · View on GitHub

Protocol Overview

The Chameleon Ultra uses a binary protocol over serial communication (USB/UART) and Bluetooth BLE.

Frame Structure

Every command and response follows this structure:

┌─────┬──────┬──────┬────────┬─────┬──────┬──────────┬──────┐
│ SOF │ LRC1 │ CMD  │ STATUS │ LEN │ LRC2 │   DATA   │ LRC3 │
├─────┼──────┼──────┼────────┼─────┼──────┼──────────┼──────┤
│ 1B  │  1B  │  2B  │   2B   │ 2B  │  1B  │ 0-512B   │  1B  │
└─────┴──────┴──────┴────────┴─────┴──────┴──────────┴──────┘

Total: 10 + LEN bytes (10-522 bytes)

Field Descriptions

  • SOF (Start of Frame): Always 0x11
  • LRC1: Always 0xEF (checksum of SOF)
  • CMD: Command ID (Big Endian, 2 bytes)
  • STATUS: Response status (Big Endian, 2 bytes)
    • Client → Device: Always 0x0000
    • Device → Client: Status code
  • LEN: Data payload length (Big Endian, 2 bytes, max 512)
  • LRC2: Checksum of CMD|STATUS|LEN (1 byte)
  • DATA: Command/response payload (variable, 0-512 bytes)
  • LRC3: Checksum of DATA (1 byte)

Checksum Calculation (LRC)

LRC (Longitudinal Redundancy Check) is calculated as:

LRC = ~(sum of all bytes) + 1
    = two's complement of sum modulo 256

Example in C:

uint8_t calculate_lrc(const uint8_t* data, size_t len) {
    uint32_t sum = 0;
    for(size_t i = 0; i < len; i++) {
        sum += data[i];
    }
    return (uint8_t)(~sum + 1);
}

Command Categories

Device Management (1000-1037)

CMDNameDescription
1000GET_APP_VERSIONGet firmware version
1001CHANGE_DEVICE_MODESwitch Reader/Emulator mode
1002GET_DEVICE_MODEQuery current mode
1003SET_ACTIVE_SLOTSet active slot (0-7)
1004SET_SLOT_TAG_TYPEConfigure slot tag type
1006SET_SLOT_ENABLEEnable/disable HF or LF
1007SET_SLOT_TAG_NICKSet slot nickname (UTF-8)
1011GET_DEVICE_CHIP_IDRead nRF52840 chip ID
1017GET_GIT_VERSIONGet git version string
1019GET_SLOT_INFOGet all slots configuration
1024DELETE_SLOT_SENSE_TYPEClear slot configuration
1033GET_DEVICE_MODELGet model (Ultra=0, Lite=1)
1035GET_DEVICE_CAPABILITIESList supported commands

HF Operations (2000-2012)

CMDNameDescription
2000HF14A_SCANScan for ISO14443A tags
2001MF1_DETECT_SUPPORTCheck Mifare Classic support
2007MF1_AUTH_ONE_KEY_BLOCKAuthenticate sector with key
2008MF1_READ_ONE_BLOCKRead 16-byte block
2009MF1_WRITE_ONE_BLOCKWrite 16-byte block
2012MF1_CHECK_KEYS_OF_SECTORSBulk key verification

LF Operations (3000-3003)

CMDNameDescription
3000EM410X_SCANRead EM4100 tag
3002HIDPROX_SCANRead HID Prox card

Emulator Configuration (4000-4030)

CMDNameDescription
4000MF1_WRITE_EMU_BLOCK_DATALoad Mifare Classic data
4009MF1_GET_EMULATOR_CONFIGGet emulation settings

LF Emulator (5000-5003)

CMDNameDescription
5000EM410X_SET_EMU_IDConfigure EM4100 emulation
5002HIDPROX_SET_EMU_IDConfigure HID Prox emulation

Status Codes

CodeNameDescription
0x0000STATUS_SUCCESSCommand succeeded
0x0001STATUS_INVALID_CMDUnknown command
0x0002STATUS_INVALID_PARAMInvalid parameters
0x0200STATUS_HF_TAG_OKHF operation succeeded
0x0201STATUS_HF_TAG_NONo HF tag detected
0x0206STATUS_MF_ERR_AUTHMifare authentication failed
0x0300STATUS_LF_TAG_OKLF operation succeeded
0x0401STATUS_FLASH_READ_FAILFlash read error
0x0402STATUS_FLASH_WRITE_FAILFlash write error

Example Commands

Get App Version (CMD 1000)

Request:

11 EF 03 E8 00 00 00 00 18 00
│  │  └─┬─┘ └─┬─┘ └─┬─┘ │  │
│  │    │     │     │    │  └─ LRC3 (no data)
│  │    │     │     │    └──── LRC2
│  │    │     │     └───────── LEN = 0
│  │    │     └─────────────── STATUS = 0x0000
│  │    └───────────────────── CMD = 1000 (0x03E8)
│  └────────────────────────── LRC1 = 0xEF
└───────────────────────────── SOF = 0x11

Response:

11 EF 03 E8 00 00 00 02 16 01 00 FE
│  │  └─┬─┘ └─┬─┘ └─┬─┘ │  └┬┘ │
│  │    │     │     │    │   │  └─ LRC3
│  │    │     │     │    │   └──── DATA (2 bytes: major.minor)
│  │    │     │     │    └──────── LRC2
│  │    │     │     └───────────── LEN = 2
│  │    │     └─────────────────── STATUS = 0x0000 (success)
│  │    └───────────────────────── CMD = 1000
│  └────────────────────────────── LRC1
└───────────────────────────────── SOF

Set Active Slot (CMD 1003)

Request to set slot 3:

11 EF 03 EB 00 00 00 01 15 03 FC
│  │  └─┬─┘ └─┬─┘ └─┬─┘ │  │  │
│  │    │     │     │    │  │  └─ LRC3
│  │    │     │     │    │  └──── DATA = 0x03 (slot 3)
│  │    │     │     │    └──────── LRC2
│  │    │     │     └───────────── LEN = 1
│  │    │     └─────────────────── STATUS = 0x0000
│  │    └───────────────────────── CMD = 1003 (0x03EB)
│  └────────────────────────────── LRC1
└───────────────────────────────── SOF

Set Slot Nickname (CMD 1007)

Request to name slot 0 "MyCard":

11 EF 03 EF 00 00 00 07 11 00 4D 79 43 61 72 64 8B
│  │  └─┬─┘ └─┬─┘ └─┬─┘ │  │  └──────┬──────┘ │
│  │    │     │     │    │  │         │        └─ LRC3
│  │    │     │     │    │  │         └────────── "MyCard"
│  │    │     │     │    │  └───────────────────── Slot 0
│  │    │     │     │    └──────────────────────── LRC2
│  │    │     │     └───────────────────────────── LEN = 7 (1 + 6)
│  │    │     └─────────────────────────────────── STATUS = 0x0000
│  │    └───────────────────────────────────────── CMD = 1007
│  └────────────────────────────────────────────── LRC1
└───────────────────────────────────────────────── SOF

Implementation Notes

Byte Order

  • All multi-byte values use Big Endian (network byte order)

String Encoding

  • UTF-8 encoding, no null terminator
  • Maximum 32 bytes for slot nicknames

Key Formats

  • Mifare keys: 6 bytes
  • Key type: 0x60 (Key A) or 0x61 (Key B)

Best Practices

  1. Always validate SOF and LRC1 before parsing
  2. Check LRC2 before processing header
  3. Verify LRC3 after receiving data
  4. Check STATUS code before using response data
  5. Respect maximum DATA length (512 bytes)

References