Skip to content

Instantly share code, notes, and snippets.

@hsiboy
Created September 26, 2024 15:11
Show Gist options
  • Save hsiboy/d179e105668135ec3bff61f8e79b4ae7 to your computer and use it in GitHub Desktop.
Save hsiboy/d179e105668135ec3bff61f8e79b4ae7 to your computer and use it in GitHub Desktop.
Python script for FDX-B 15-digit, ISO-compliant Pet microchips

The script processes a raw HEX string input (representing an FDX-B transponder) and extracts relevant fields, such as the header, identification code, country code, data block status, animal application indicator, CRC checksum, and extended data block.

Key Features:

  1. Dynamic Imports: It dynamically imports required libraries (binascii, argparse, termcolor), displaying errors if any library is missing.
  2. HEX Processing: It converts the input HEX string into binary and extracts the fields following the FDX-B protocol structure.
  3. Manufacturer Lookup: Based on the country code, it enriches the output by displaying the manufacturer's name (if available).
  4. Colorful Output: Uses the termcolor library to colorize the output fields for better readability.
  5. Error Handling:
    • If no HEX string is passed, it displays a usage guide and prompts the user to provide valid input.
    • If an invalid HEX string is passed, it catches the error and prints a helpful message.

The script is run via the command line, and the user must provide the HEX string as an argument for it to process the data.

The Python Script:

import sys

# Dynamically import required libraries
libnames = ['binascii', 'argparse', 'termcolor']
for libname in libnames:
    try:
        lib = __import__(libname)
    except:
        print(f"Failed to import {libname}: ", sys.exc_info())
    else:
        globals()[libname] = lib

# List of known manufacturers and their ISO codes
manufacturers = {
    985: "Destron",
    982: "Allflex",
    981: "Datamars",
    978: "Ordicam",
    977: "Avid",
    975: "Sokymat",
    972: "Planet ID",
    968: "AEG",
    967: "Rfdynamics",
    966: "PetCode",
    965: "4D Technology Co. Ltd.",
    963: "Korth Eletro Mecanica LTDA",
    961: "Mannings I.A.I.D.",
    959: "Global ID Technologies",
    958: "Pet ID",
    956: "Trovan Ltd.",
    955: "Reseaumatique",
    953: "Cromasa Identificacion electronica S.A.",
    952: "JECTA"
}

# Function to process the HEX input
def process_hex(hex_string):
    try:
        # Remove spaces and convert hex string to binary
        hex_clean = hex_string.replace(" ", "")
        binary_data = bin(int(hex_clean, 16))[2:].zfill(len(hex_clean) * 4)

        # Extract fields from the binary data
        header = binary_data[:11]  # 11-bit header
        identification_data = binary_data[11:49]  # 38-bit identification code
        country_code_binary = binary_data[49:59]  # 10-bit country code
        data_block_status = binary_data[59]  # 1-bit data block status
        animal_indicator = binary_data[60]  # 1-bit animal indicator
        crc = binary_data[61:77]  # 16-bit CRC
        extended_data_block = binary_data[77:101]  # 24-bit extended data block

        # Convert fields to relevant formats
        country_code = int(country_code_binary, 2)
        identification_code = int(identification_data, 2)
        
        # Enrich manufacturer information
        manufacturer_name = manufacturers.get(country_code, "Unknown")

        # Print the fields with color
        print(termcolor.colored(f"Header: {header} (11-bit)", "yellow"))
        print(termcolor.colored(f"Identification Code: {identification_code} (12-digit code)", "cyan"))
        print(termcolor.colored(f"Country Code: {country_code} (Manufacturer: {manufacturer_name})", "green"))
        print(termcolor.colored(f"Data Block Status: {data_block_status} (1-bit)", "yellow"))
        print(termcolor.colored(f"Animal Application Indicator: {animal_indicator} (1-bit)", "cyan"))
        print(termcolor.colored(f"CRC Checksum: {crc} (16-bit)", "red"))
        print(termcolor.colored(f"Extended Data Block: {extended_data_block} (24-bit)", "green"))
    
    except ValueError:
        print(termcolor.colored("Error: Invalid HEX string. Please provide a valid HEX string.", "red"))

# Command-line argument parser with error handling
def main():
    parser = argparse.ArgumentParser(description="Process raw HEX input from an FDX-B transponder.")
    parser.add_argument("hex_string", nargs="?", help="The raw HEX string to process (e.g., 'C2 28 EE 12 E9 6F 00 01 00 00 00')")
    
    args = parser.parse_args()
    
    if not args.hex_string:
        print(termcolor.colored("Error: No HEX string provided. Please provide a valid HEX string as a command-line argument.", "red"))
        parser.print_help()
    else:
        process_hex(args.hex_string)

if __name__ == "__main__":
    main()

Error Handling:

  1. Error Handling for Missing Input:

    • If no string is passed, the script will display a usage message using argparse.print_help() along with an error message.
  2. Error Handling for Invalid HEX Strings:

    • If an invalid HEX string (i.e., a string that can't be converted to a valid hexadecimal number) is passed, it will catch the ValueError and print a user-friendly error message indicating the issue.
  3. argparse Settings:

    • nargs="?" is used to allow the HEX string argument to be optional, and the script can then handle the case where it’s missing.

How to Run the Script:

  • If you pass a valid HEX string:
python process_transponder.py "C2 28 EE 12 E9 6F 00 01 00 00 00"
  • If you pass an invalid HEX string:
python process_transponder.py "InvalidString"
  • If no string is passed:
python process_transponder.py

Example Output for Missing Input:

Error: No HEX string provided. Please provide a valid HEX string as a command-line argument.
usage: process_transponder.py [-h] [hex_string]
Process raw HEX input from an FDX-B transponder.

positional arguments:
  hex_string  The raw HEX string to process (e.g., 'C2 28 EE 12 E9 6F 00 01 00 00 00')

optional arguments:
  -h, --help  show this help message and exit

Example Output for Invalid HEX String:

Error: Invalid HEX string. Please provide a valid HEX string.

This ensures that the script is robust, handles errors gracefully, and gives clear feedback to the user when something is wrong.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment