Below is a Python example demonstrating how to control ETH Digital Input/Output (DIO) using the lower-level protocol. The code will: Establish a TCP/IP connection to the device. Construct and send packets according to the specified protocol. Perform basic DIO operations like reading and writing DIO data. Python Example: Controlling DIO Using the Lower-Level Protocol import socket import struct def connect_to_device(ip_address, port=5000): """ Establish a TCP/IP connection to the device. """ sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) sock.connect((ip_address, port)) return sock def send_packet(sock, packet_type, payload=b''): """ Construct and send a packet to the device. """ body = packet_type.encode('ascii') + payload length = len(body) if length < 4 or length > 255: raise ValueError("Packet body length must be between 4 and 255 bytes.") packet = struct.pack('B', length) + body sock.sendall(packet) return receive_response(sock) def receive_response(sock): """ Receive and parse the response from the device. """ # Read the length byte length_byte = sock.recv(1) if not length_byte: raise ConnectionError("No response from device.") length = struct.unpack('B', length_byte)[0] # Read the rest of the packet data = sock.recv(length) if len(data) < 4: raise ValueError("Incomplete response from device.") # Parse the response response_type = data[:4].decode('ascii') payload = data[4:] return response_type, payload def read_all_dio(sock): """ Read all DIO data using the RADI command. """ response_type, payload = send_packet(sock, 'RADI') if response_type == 'R_OK': # The first byte of payload is the length of DIO data dio_length = payload[0] dio_data = payload[1:1+dio_length] print(f"DIO Data (hex): {dio_data.hex()}") return dio_data else: raise Exception(f"Error reading DIO: {response_type}") def write_all_dio(sock, dio_data): """ Write all DIO data using the WADO command. """ dio_length = len(dio_data) if dio_length > 255: raise ValueError("DIO data too long.") payload = struct.pack('B', dio_length) + dio_data response_type, _ = send_packet(sock, 'WADO', payload) if response_type == 'W_OK': print("DIO data written successfully.") else: raise Exception(f"Error writing DIO: {response_type}") def main(): ip_address = '192.168.1.100' # Replace with your device's IP address port = 5000 # Replace with your device's port if different try: sock = connect_to_device(ip_address, port) print("Connected to device.") # Example: Read all DIO data dio_data = read_all_dio(sock) # Example: Toggle the first DIO bit dio_list = list(dio_data) dio_list[0] ^= 0x01 # Toggle bit 0 new_dio_data = bytes(dio_list) # Write the modified DIO data back to the device write_all_dio(sock, new_dio_data) # Verify the change by reading back the DIO data dio_data = read_all_dio(sock) except Exception as e: print(f"An error occurred: {e}") finally: sock.close() print("Connection closed.") if __name__ == '__main__': main() Explanation: Connecting to the Device: The connect_to_device function establishes a TCP/IP connection to the device using its IP address and port. Sending Packets: The send_packet function constructs a packet according to the protocol: Length Byte: Total length of the body (4 to 255 bytes). Command Type: 4-byte ASCII string (e.g., 'RADI' for reading all DIO data). Payload: Optional, varies per command. The function then sends the packet and waits for a response. Receiving Responses: The receive_response function reads the response from the device, which includes: Length Byte: Indicates how many bytes to read. Response Type: 4-byte ASCII string (e.g., 'R_OK' or 'W_OK'). Payload: Contains data or error codes. Reading All DIO Data: The read_all_dio function sends the 'RADI' command to read all DIO data. The device responds with an 'R_OK' packet containing the DIO data. Writing All DIO Data: The write_all_dio function sends the 'WADO' command to write DIO data. The payload includes the length of the DIO data and the actual data bytes. The device should respond with a 'W_OK' packet upon success. Example Usage: The main function demonstrates how to read the current DIO data, toggle the first bit, write the modified data back to the device, and then read back the data to verify the change. Notes: Byte Order and Endianness: The protocol specifies big-endian format for multi-byte values. Ensure that you handle byte order correctly when constructing payloads. Error Handling: The code includes basic error handling to catch exceptions and print error messages. Adjustments: Replace '192.168.1.100' and 5000 with your device's actual IP address and port. The number of DIO bytes (dio_length) may vary depending on your device model. Adjust the code if necessary. Extending the Code: You can add more functions to handle other commands like ChIO (configure DIO direction) or WRPD (write partial DIO data and read back the state). Understanding the Packet Structure: Packet: scss +-----------+--------------------+ | Length(1) | Body (Length bytes)| +-----------+--------------------+ Body: scss +----------------+-------------------+ | Command Type(4)| Payload (optional)| +----------------+-------------------+ Example 'RADI' Command Packet: Length Byte: 0x04 (since the body is 4 bytes long) Command Type: 'RADI' (ASCII encoded to bytes) Example 'WADO' Command Packet: Length Byte: Varies based on payload length. Command Type: 'WADO' Payload: DIO Length Byte: Number of DIO data bytes. DIO Data: The actual DIO bytes to write. Additional Tips: Device Responses: Always check the response type ('R_OK', 'W_OK', or '_Err') to determine if the command was successful. If you receive an error ('_Err'), the payload contains a 4-byte little-endian Windows error code. Data Formats: When dealing with IP addresses, subnet masks, and MAC addresses, ensure you're formatting them correctly (big-endian byte order). Testing: Before running the script, ensure your device is reachable and that no firewalls are blocking the connection.