{"id":6485,"library":"xmodem","title":"XMODEM protocol implementation","description":"The `xmodem` library provides an implementation of the XMODEM, YMODEM, and ZMODEM protocols for Python. It focuses on a minimalistic implementation while adhering to protocol specifications. All modem classes require `getc` and `putc` callback functions to handle character data for communication. The current version is 0.5.0, with releases occurring periodically to address bugs and introduce enhancements.","status":"active","version":"0.5.0","language":"en","source_language":"en","source_url":"https://github.com/tehmaze/xmodem","tags":["xmodem","ymodem","zmodem","serial","protocol","file-transfer","embedded"],"install":[{"cmd":"pip install xmodem","lang":"bash","label":"Install latest version"}],"dependencies":[],"imports":[{"note":"The `modem` package refers to an older or different library; the correct import path for this specific library (tehmaze/xmodem) is `from xmodem import XMODEM`.","wrong":"from modem import XMODEM","symbol":"XMODEM","correct":"from xmodem import XMODEM"}],"quickstart":{"code":"import serial\nfrom xmodem import XMODEM\n\n# Configure your serial port here\n# For example, using a dummy serial port for demonstration\n# In a real application, replace with an actual serial port like '/dev/ttyUSB0'\nclass DummySerial:\n    def __init__(self, timeout=0):\n        self.buffer = b''\n\n    def read(self, size):\n        if not self.buffer:\n            return b''\n        data = self.buffer[:size]\n        self.buffer = self.buffer[size:]\n        return data\n\n    def write(self, data):\n        # In a real scenario, this would send data over serial\n        # For this dummy example, we just 'receive' it instantly\n        # Or, you could print it to simulate output.\n        # print(f\"DummySerial sent: {data!r}\")\n        self.buffer += data # Simulate loopback or immediate reception\n        return len(data)\n\n# Replace DummySerial() with serial.Serial('/dev/ttyUSB0', timeout=0) for actual use\nser = DummySerial(timeout=0)\n\ndef getc(size, timeout=1):\n    return ser.read(size) or None\n\ndef putc(data, timeout=1):\n    return ser.write(data)\n\nmodem = XMODEM(getc, putc)\n\n# --- Example: Sending a file ---\nprint(\"Attempting to send data...\")\n# Create a dummy stream for demonstration\nimport io\nstream_to_send = io.BytesIO(b\"Hello, XMODEM world! This is a test file.\\n\")\n\n# In a real scenario, this would be `open('/path/to/file', 'rb')`\n# status = modem.send(stream_to_send)\n# print(f\"Send status: {status}\")\n\n# Due to the complexity of XMODEM handshakes in a simple script \n# without a cooperating receiver, the send/recv calls are commented out.\n# A successful transfer requires a matching XMODEM receiver on the other end.\nprint(\"To send a file: modem.send(file_stream_object)\")\nprint(\"To receive a file: modem.recv(file_stream_object)\")\nprint(\"Note: A full XMODEM transfer requires a corresponding receiver/sender.\")\n\n# --- Example: Receiving a file ---\n# stream_to_receive = io.BytesIO()\n# received_bytes = modem.recv(stream_to_receive)\n# if received_bytes is not None:\n#     print(f\"Received {received_bytes} bytes: {stream_to_receive.getvalue()!r}\")\n# else:\n#     print(\"Failed to receive data.\")","lang":"python","description":"This quickstart demonstrates how to initialize the `XMODEM` class by providing `getc` and `putc` callback functions, which handle reading from and writing to a communication channel (e.g., a serial port). It shows the basic structure for sending and receiving data streams using the `send()` and `recv()` methods. Note that a full XMODEM transfer requires a cooperating sender and receiver, and a dummy serial port is used here for illustrative purposes."},"warnings":[{"fix":"Upgrade to `xmodem` version 0.4.5 or newer (`pip install --upgrade xmodem`).","message":"Version 0.4.0 introduced a critical bug that caused `recv()` to raise an `AssertionError` due to a bogus `assert False` statement. This was fixed in version 0.4.5.","severity":"breaking","affected_versions":"0.4.0 - 0.4.4"},{"fix":"Upgrade to `xmodem` version 0.4.4 or newer to ensure correct `retry` behavior (`pip install --upgrade xmodem`).","message":"The `retry` parameter in `send()` and `recv()` methods was incorrectly implemented in versions prior to 0.4.4. For `send()`, it was treated as total failures instead of failures per block, and `retry=n` would only retry `n-1` times instead of `n` times. This could lead to premature transfer failures, especially for large files or when `retry=1` was used.","severity":"gotcha","affected_versions":"< 0.4.4"},{"fix":"Upgrade to `xmodem` version 0.4.7 or newer to resolve stalling issues in `recv()` (`pip install --upgrade xmodem`).","message":"Prior to version 0.4.7, `recv()` could stall under certain error conditions or when receiving empty files. This could cause programs to hang indefinitely.","severity":"gotcha","affected_versions":"< 0.4.7"},{"fix":"Upgrade to `xmodem` version 0.4.3 or newer. The fix ensures all three data blocks are sent by a single `putc()` call, improving compatibility.","message":"In versions prior to 0.4.3, the `putc()` callback was invoked multiple times for each part of an XMODEM block's header, data, and checksum. This behavior could cause issues when integrating with microcontrollers or hardware sensitive to timing at stream boundaries.","severity":"gotcha","affected_versions":"< 0.4.3"},{"fix":"Ensure you are using `xmodem` version 0.5.0 or newer to benefit from the corrected `retry_limit` logic (`pip install --upgrade xmodem`).","message":"In version 0.5.0, a bug was fixed where `retry_limit` was not correctly triggered during the data transfer phase because errors were not properly accumulated. This means retry mechanisms might not have functioned as expected in versions where this issue was present.","severity":"gotcha","affected_versions":"Likely < 0.5.0 (fixed in 0.5.0)"}],"env_vars":null,"last_verified":"2026-04-15T00:00:00.000Z","next_check":"2026-07-14T00:00:00.000Z"}