MD Al Amin Ashik
Published © GPL3+

Capturing UART using Saleae Logic Analyzer

Reverse engineering a UART capacitive touch sensor module and writing Python to control - SEN0542

IntermediateFull instructions provided30 minutes27
Capturing UART using Saleae Logic Analyzer

Things used in this project

Hardware components

1 x UART Capacitive Fingerprint Sensor
×1
3.3V USB-to-TTL Module
×1
USB Saleae logic analyzer
×1
Bread Board
×1

Software apps and online services

Python
Saleae logic

Hand tools and fabrication machines

Breadboard, 170 Pin
Breadboard, 170 Pin
10 Pc. Jumper Wire Kit, 5 cm Long
10 Pc. Jumper Wire Kit, 5 cm Long

Story

Read more

Code

EnrollNewFinger.py

Python
import serial
import time

# ================= CONFIG =================
PORT = 'COM3'
BAUD = 115200
DID  = 0x00
# =========================================

ser = serial.Serial(PORT, BAUD, timeout=2)
time.sleep(0.5)

def cmd(cmd_id, data=b''):
    pkt = bytearray(26)
    pkt[0:4] = b'\x55\xAA\x00' + DID.to_bytes(1, 'little')
    pkt[4:6] = cmd_id.to_bytes(2, 'little')
    pkt[6:8] = len(data).to_bytes(2, 'little')
    pkt[8:8+len(data)] = data
    pkt[24:26] = (sum(pkt[:24]) & 0xFFFF).to_bytes(2, 'little')

    ser.write(pkt)
    resp = ser.read(26)

    if len(resp) != 26 or resp[0:2] != b'\xAA\x55':
        return 0xFFFF, b''

    ret = int.from_bytes(resp[8:10], 'little')
    ln  = int.from_bytes(resp[6:8], 'little') - 2
    return ret, resp[10:10+ln] if ln > 0 else b''


def wait_finger_present():
    while True:
        if cmd(0x0020)[0] == 0x0000:
            return
        time.sleep(0.2)


def wait_finger_removed():
    while True:
        if cmd(0x0021)[0] == 0x0000:
            break
        time.sleep(0.2)

    while cmd(0x0020)[0] == 0x0000:
        time.sleep(0.2)

    time.sleep(0.6)


# ================= ENROLL =================
fid = int(input("Enter fingerprint ID (180): "))
print(f"\nEnrolling ID {fid}")

# Start enrollment
cmd(0x0046, fid.to_bytes(2, 'little'))

# -------- First finger --------
print("Place finger (1/3)...")
wait_finger_present()

if cmd(0x0060, b'\x00\x00')[0] != 0x0000:
    print("First template failed")
    exit()

print("Lift finger")
wait_finger_removed()

# -------- Second finger --------
print("Place same finger (2/3)...")
wait_finger_present()

if cmd(0x0060, b'\x01\x00')[0] != 0x0000:
    print("Second template failed")
    exit()

print("Lift finger")
wait_finger_removed()

# -------- Third finger --------
print("Place same finger (3/3)...")
wait_finger_present()

if cmd(0x0060, b'\x02\x00')[0] != 0x0000:
    print("Third template failed")
    exit()

print("Lift finger")
wait_finger_removed()

# -------- Merge (3 templates) --------
if cmd(0x0061, b'\x00\x00\x03\x00')[0] != 0x0000:
    print("Template merge failed")
    exit()

# -------- Store --------
if cmd(0x0040, fid.to_bytes(2, 'little') + b'\x00\x00')[0] != 0x0000:
    print("Store failed")
    exit()

# -------- End --------
cmd(0x0024, b'\x00\x00')

print("Enrollment successful (3-scan)")
ser.close()

getDeviceID.py

Python
import serial
import time

PORT = 'COM3'
BAUD = 115200
DID  = 0x00

ser = serial.Serial(PORT, BAUD, timeout=1)
time.sleep(0.5)

def cmd(cmd_id, data=b''):
    pkt = bytearray(26)
    pkt[0:4] = b'\x55\xAA\x00' + DID.to_bytes(1, 'little')
    pkt[4:6] = cmd_id.to_bytes(2, 'little')
    pkt[6:8] = len(data).to_bytes(2, 'little')
    pkt[8:8+len(data)] = data
    pkt[24:26] = (sum(pkt[:24]) & 0xFFFF).to_bytes(2, 'little')

    ser.write(pkt)
    resp = ser.read(26)

    if len(resp) != 26 or resp[0:2] != b'\xAA\x55':
        return None

    return resp

print("Device Information\n")

# ---- Device ID ----
resp = cmd(0x0024)
if resp:
    print(f"Device ID Success           ID : {resp[8]}")
else:
    print("Device ID Failed")

ser.close()

IsFingerPressed.py

Python
import serial
import time

# ========== CONFIG ==========
PORT = 'COM3'        # Change if needed
BAUD = 115200
DID  = 0x00          # MUST be 0x00 (vendor default)
# ============================

ser = serial.Serial(PORT, BAUD, timeout=1)
time.sleep(0.5)

def cmd(cmd_id, data=b''):
    pkt = bytearray(26)
    pkt[0:4] = b'\x55\xAA\x00' + DID.to_bytes(1, 'little')
    pkt[4:6] = cmd_id.to_bytes(2, 'little')
    pkt[6:8] = len(data).to_bytes(2, 'little')
    pkt[8:8+len(data)] = data
    pkt[24:26] = (sum(pkt[:24]) & 0xFFFF).to_bytes(2, 'little')

    ser.write(pkt)

    resp = ser.read(26)
    if len(resp) != 26 or resp[0:2] != b'\xAA\x55':
        return 0xFFFF

    return int.from_bytes(resp[8:10], 'little')


print("Please place your finger on the sensor...")

# Vendor-style polling: GET_IMAGE until success
while True:
    ret = cmd(0x0020)     # CMD_GET_IMAGE
    if ret == 0x0000:
        print("Finger detected.")
        break
    time.sleep(0.25)

ser.close()

getStoredFingers.py

Python
import serial
import time

SERIAL_PORT = 'COM3'
BAUD_RATE = 115200
DID = 0x01

ser = serial.Serial(SERIAL_PORT, BAUD_RATE, timeout=1)
time.sleep(0.3)

def checksum(buf):
    return sum(buf) & 0xFFFF

def cmd(cmd_id):
    pkt = bytearray(26)
    pkt[0:2] = b'\x55\xAA'
    pkt[2] = DID
    pkt[3] = 0x00
    pkt[4:6] = cmd_id.to_bytes(2, 'little')
    pkt[6:8] = (0).to_bytes(2, 'little')
    pkt[24:26] = checksum(pkt[:24]).to_bytes(2, 'little')

    ser.write(pkt)

    # ACK frame
    ack = ser.read(26)
    if len(ack) != 26 or ack[0:2] != b'\xAA\x55':
        return None

    if int.from_bytes(ack[8:10], 'little') != 0:
        return None

    # DATA frame
    time.sleep(0.07)
    hdr = ser.read(8)
    if len(hdr) != 8 or hdr[0:2] != b'\xA5\x5A':
        return None

    data_len = int.from_bytes(hdr[6:8], 'little')
    data = ser.read(data_len + 2)

    return data[:data_len]

# ---- Execute ----
payload = cmd(0x0049)

if payload is None or len(payload) < 4:
    print("Failed to get ID list")
else:
    enroll_count = int.from_bytes(payload[0:2], 'little')
    bitmap = payload[2:]

    enrolled_ids = []
    for byte_index, b in enumerate(bitmap):
        for bit in range(8):
            if b & (1 << bit):
                enrolled_ids.append(byte_index * 8 + bit)

    print(f"Enroll Count = {enroll_count}")
    print("ID =")
    for i in enrolled_ids:
        print(i)

ser.close()

DeleteAllID.py

Python
import serial
import time

SERIAL_PORT = 'COM3'      # Change to your USB-TTL port
BAUD_RATE = 115200
DID = 0x01                # Try 0x00 if no response

ser = serial.Serial(SERIAL_PORT, BAUD_RATE, timeout=2)
time.sleep(0.3)

def cmd(cmd_id, data=b''):
    packet = bytearray(26)
    packet[0:4] = b'\x55\xAA\x00' + DID.to_bytes(1, 'little')
    packet[4:6] = cmd_id.to_bytes(2, 'little')
    packet[6:8] = len(data).to_bytes(2, 'little')
    packet[8:8+len(data)] = data
    packet[24:26] = (sum(packet[:24]) & 0xFFFF).to_bytes(2, 'little')
    ser.write(packet)
    resp = ser.read(26)
    if len(resp) < 26 or resp[0:2] != b'\xAA\x55':
        return 0xFF, b''
    ret = int.from_bytes(resp[8:10], 'little')
    return ret, b''

print("Deleting ALL stored fingerprints from the module...")

# Correct data for delete all: startID=1 (0x01 0x00), endID=80 (0x50 0x00)
del_all_data = b'\x01\x00\x50\x00'

ret, _ = cmd(0x0044, del_all_data)

if ret == 0x0000:
    print("All fingerprints deleted successfully!")
elif ret == 0x0012:
    print("No fingerprints were stored (module already empty)")
else:
    print(f"Delete all failed (error code: 0x{ret:04X})")

ser.close()

verifyStoredFinger.py

Python
import serial
import time

SERIAL_PORT = 'COM3'      # Change to your USB-TTL port, e.g. '/dev/ttyUSB0'
BAUD_RATE = 115200
DID = 0x01                # Usually 0x01, try 0x00 if no response

ser = serial.Serial(SERIAL_PORT, BAUD_RATE, timeout=1)
time.sleep(0.3)

def cmd(cmd_id, data=b''):
    packet = bytearray(26)
    packet[0:4] = b'\x55\xAA\x00' + DID.to_bytes(1, 'little')
    packet[4:6] = cmd_id.to_bytes(2, 'little')
    packet[6:8] = len(data).to_bytes(2, 'little')
    packet[8:8+len(data)] = data
    packet[24:26] = (sum(packet[:24]) & 0xFFFF).to_bytes(2, 'little')
    ser.write(packet)
    resp = ser.read(26)
    if len(resp) < 26 or resp[0:2] != b'\xAA\x55':
        return 0xFF, b''
    ret = int.from_bytes(resp[8:10], 'little')
    data_len = int.from_bytes(resp[6:8], 'little') - 2
    return ret, resp[10:10+data_len] if data_len > 0 else b''

print("Press the finger")
while True:
    ret, _ = cmd(0x0021)            # Finger detect
    if ret == 0x0000:
        ret, _ = cmd(0x0020)        # Get image
        if ret == 0x0000:
            ret, _ = cmd(0x0060, b'\x00\x00')  # Generate template in buffer 0
            if ret == 0x0000:
                ret, data = cmd(0x0063, b'\x00\x00\x01\x00\x50\x00')  # Search ID 1-80
                if ret == 0x0000 and len(data) >= 2:
                    id_match = int.from_bytes(data[:2], 'little')
                    print(f"Finger matches stored ID: {id_match}")
                else:
                    print("No match")
            else:
                print("No match")
        #print("Press the finger")
    time.sleep(0.1)

ser.close()

DeleteID.py

Python
import serial
import time

SERIAL_PORT = 'COM3'      # Change to your USB-TTL port
BAUD_RATE = 115200
DID = 0x01                # Try 0x00 if no response

ser = serial.Serial(SERIAL_PORT, BAUD_RATE, timeout=2)
time.sleep(0.3)

def cmd(cmd_id, data=b''):
    packet = bytearray(26)
    packet[0:4] = b'\x55\xAA\x00' + DID.to_bytes(1, 'little')
    packet[4:6] = cmd_id.to_bytes(2, 'little')
    packet[6:8] = len(data).to_bytes(2, 'little')
    packet[8:8+len(data)] = data
    packet[24:26] = (sum(packet[:24]) & 0xFFFF).to_bytes(2, 'little')
    ser.write(packet)
    resp = ser.read(26)
    if len(resp) < 26 or resp[0:2] != b'\xAA\x55':
        return 0xFF, b''
    ret = int.from_bytes(resp[8:10], 'little')
    data_len = int.from_bytes(resp[6:8], 'little') - 2
    return ret, resp[10:10+data_len] if data_len > 0 else b''

# Prompt for ID to delete
try:
    fid = int(input("Enter the fingerprint ID to delete (1-80): "))
    if not 1 <= fid <= 80:
        print("ID must be between 1 and 80")
        ser.close()
        exit()
except:
    print("Invalid input")
    ser.close()
    exit()

print(f"Attempting to delete single fingerprint ID: {fid}")

# Correct way to delete a single specific ID
del_data = fid.to_bytes(2, 'little') + fid.to_bytes(2, 'little')  # startID = fid, endID = fid

ret, _ = cmd(0x0044, del_data)

if ret == 0x0000:
    print(f"Successfully deleted ID {fid}")
elif ret == 0x0012:
    print(f"Delete returned 0x0012: No fingerprint stored at ID {fid} (template empty)")
else:
    print(f"Delete failed (error code: 0x{ret:04X})")

ser.close()

GitHub Link

Find all the codes and resources related to this project

Credits

MD Al Amin Ashik
2 projects • 0 followers
I am a embedded systems engineer who likes to work with different electronic devices that ease our daily life, especially automation!

Comments