pepper_c1
Python driver for the Eccel Pepper C1 RFID reader made by Eccel Technology Ltd.
Supports communication over UART and TCP, and covers MIFARE Classic, MIFARE Ultralight, MIFARE DESFire, and ICODE tag families.
Compatibility
| Module | UART | TCP | MIFARE Classic | MIFARE Ultralight | MIFARE DESFire | ICODE |
|---|---|---|---|---|---|---|
| Pepper C1 | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
| Pepper C2 | ✓ | — | ✓ | ✓ | — | ✓ |
Pepper C2 modules communicate over UART only and do not support the MIFARE DESFire command set (
mfdf_*methods). All other commands work identically to the C1.
Installation
pip install pepper_c1
Quick start
from pepper_c1 import PepperC1, UARTTransport
with PepperC1(UARTTransport('/dev/ttyUSB0', baudrate=115200)) as reader:
print(reader.get_version())
count = reader.get_tag_count()
if count:
uid_info = reader.get_uid() # returns [type, param, uid_bytes...]
print(f"Tag UID: {uid_info[2:].hex()}")
MIFARE Classic example
from pepper_c1 import PepperC1, UARTTransport
from pepper_c1.commands import KEY_TYPE_MIFARE
with PepperC1(UARTTransport('/dev/ttyUSB0')) as reader:
reader.get_tag_count()
reader.activate_tag()
reader.set_key(0, KEY_TYPE_MIFARE, bytes([0xFF] * 12)) # key A + key B
original = reader.mf_read_block(5)
print(f"Block 5: {original.hex()}")
reader.mf_write_block(5, b'\x01' * 16)
print(f"Readback: {reader.mf_read_block(5).hex()}")
reader.mf_write_block(5, original) # restore
MIFARE Ultralight example
from pepper_c1 import PepperC1, UARTTransport
with PepperC1(UARTTransport('/dev/ttyUSB0')) as reader:
reader.get_tag_count()
reader.activate_tag()
original = reader.mfu_read_page(4)
print(f"Page 4: {original.hex()}")
reader.mfu_write_page(4, b'\x01\x02\x03\x04')
print(f"Readback: {reader.mfu_read_page(4).hex()}")
reader.mfu_write_page(4, original) # restore
MIFARE DESFire example
from pepper_c1 import PepperC1, UARTTransport
from pepper_c1.commands import KEY_TYPE_AES128
with PepperC1(UARTTransport('/dev/ttyUSB0')) as reader:
# DESFire does not need activate_tag
reader.get_tag_count()
reader.mfdf_select_app(bytes([0x00, 0x00, 0x00])) # select PICC master app
reader.set_key(0, KEY_TYPE_AES128, bytes(16)) # all-zero = factory default
reader.mfdf_auth_aes(key_no=0, key_slot=0)
app_ids = reader.mfdf_get_app_ids()
for aid in app_ids:
print(f"AID: {aid.hex()}")
ICODE example
from pepper_c1 import PepperC1, UARTTransport
with PepperC1(UARTTransport('/dev/ttyUSB0')) as reader:
# ICODE (ISO 15693) does not need activate_tag
reader.get_tag_count()
reader.get_uid()
original = reader.icode_read_block(5)
print(f"Block 5: {original.hex()}")
reader.icode_write_block(5, b'\x01\x02\x03\x04')
print(f"Readback: {reader.icode_read_block(5).hex()}")
reader.icode_write_block(5, original) # restore
Antenna multiplexer example
For readers with multiple antennas, use set_active_antenna() to switch between them (1–8):
import time
from pepper_c1 import PepperC1, UARTTransport
with PepperC1(UARTTransport('/dev/ttyUSB0')) as reader:
while True:
for antenna in range(1, 9):
reader.set_active_antenna(antenna)
count = reader.get_tag_count()
if count:
uid_info = reader.get_uid()
tag_type = uid_info[0]
uid = uid_info[2:].hex().upper()
print(f"Antenna {antenna}: type=0x{tag_type:02X} UID={uid}")
else:
print(f"Antenna {antenna}: --")
See tools/mux_example.py for the full CLI script with transport selection and configurable dwell time.
Firmware update (OTA)
import math
from pepper_c1 import PepperC1, TCPTransport
from pepper_c1.commands import Command
fw_data = open("Pepper_C1_2.56.2249.bin", "rb").read()
chunk_size = 1024
num_frames = math.ceil(len(fw_data) / chunk_size)
with PepperC1(TCPTransport('192.168.100.1', 1234), response_timeout=2.0) as reader:
reader._timeout = 5.0
reader.send_command(Command.OTA_BEGIN)
reader._timeout = 2.0
for i in range(num_frames):
chunk = fw_data[i * chunk_size : (i + 1) * chunk_size]
reader.send_command(Command.OTA_FRAME, chunk)
print(f"\r {(i + 1) * 100 // num_frames}% frame {i + 1}/{num_frames}", end="")
print()
reader._timeout = 5.0
reader.send_command(Command.OTA_FINISH)
reader.reboot()
See tools/firmware_update.py for the full script with progress bar and CLI options.
TCP transport
from pepper_c1 import PepperC1, TCPTransport
# Connect via TCP before opening UART — closing UART may reset the device
with PepperC1(TCPTransport('192.168.100.1', 1234)) as reader:
print(reader.get_version())
count = reader.get_tag_count()
if count:
uid_info = reader.get_uid()
print(f"Tag UID: {uid_info[2:].hex()}")
Error handling
from pepper_c1 import PepperC1, UARTTransport, CommandError, TransportError
try:
with PepperC1(UARTTransport('/dev/ttyUSB0')) as reader:
reader.get_tag_count()
reader.get_uid()
except TransportError as e:
print(f"Connection failed: {e}")
except CommandError as e:
print(f"Device error: {e}")
Protocol
The Pepper C1 uses a binary framing protocol over serial or TCP:
[0xF5] [LEN_L] [LEN_H] [LEN_L^0xFF] [LEN_H^0xFF] [PAYLOAD...] [CRC_L] [CRC_H]
CRC is CCITT-16 computed over the payload only.
Low-level access is available via PepperC1.send_command(cmd, data).
Metadata
Release files for pepper-c1 0.2.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| pepper_c1-0.2.0.tar.gz | 21.8 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| pepper_c1-0.2.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 40.2 kB
Release files / pepper_c1-0.2.0.tar.gz
| Download URL | pepper_c1-0.2.0.tar.gz |
|---|---|
| Size | 21.8 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
3c48fad4ab82c5e88571cecae3d1963a812b8e6496b00e5b1756ba80b1467c4c
|
|
BLAKE2b-256 checksum How to use checksums |
247633ec060dd06990331e09fb13e127fa2f8d578519dfe31ff93e1f35703530
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.1.0 CPython/3.8.3
|
Release files / pepper_c1-0.2.0-py3-none-any.whl
| Download URL | pepper_c1-0.2.0-py3-none-any.whl |
|---|---|
| Size | 18.3 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
acc1143661b11398f27d23b480638a8263e2ff8960d102f841791439531e9769
|
|
BLAKE2b-256 checksum How to use checksums |
2c8f6bf7a9fae71c5aefeed678e0024bcf3fc865afc9f67666ebec35fa92953e
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.1.0 CPython/3.8.3
|