import os import hid import time import sys import struct from UploadImg import HidCommunicationConfig from HidCommunication import HidCommunication # Constants VENDOR_ID = 0x2C7C PRODUCT_ID = 0x0901 MAX_HID_PACKET_SIZE = 64 MAX_DATA_SIZE = 63 # One byte reserved for report ID FILE_CHUNK_SIZE = 4 * 1024 # 4KB chunks for file transfer def compute_checksum(packet_bytes): """Calculate XOR checksum of packet bytes""" checksum = 0 for b in packet_bytes: checksum ^= b return checksum def build_background_command(seq=1, command_type=1, color=None): """Build a background command packet""" header = 0x02 type_code = 0x01 # LCD command if command_type == 4: # Fail payment op_code = 0x05 data_length = bytearray([0x00, 0x00]) elif command_type == 2: # Success payment op_code = 0x04 data_length = bytearray([0x00, 0x00]) elif command_type == 3: # pending payment op_code = 0x06 data_length = bytearray([0x00, 0x00]) elif command_type == 1: # Home Background op_code = 0x07 data_length = bytearray([0x00, 0x00]) else: print("Invalid command type.") return None packet = bytearray([header, seq, type_code, op_code]) packet.extend(data_length) if command_type == 5 and color: packet.extend(color) # Calculate checksum and append it checksum = compute_checksum(packet) packet.append(checksum) return packet def build_background_volume(seq=1, command_type=1, color=None): """Build a background command packet""" header = 0x02 type_code = 0x03 # LCD command if command_type == 12: # GET_VOLUME op_code = 0x25 data_length = bytearray([0x00, 0x00]) elif command_type == 13: # INCREASE_VOLUME op_code = 0x27 data_length = bytearray([0x00, 0x00]) elif command_type == 14: # DECREASE_VOLUME op_code = 0x28 data_length = bytearray([0x00, 0x00]) else: print("Invalid command type.") return None packet = bytearray([header, seq, type_code, op_code]) packet.extend(data_length) if command_type == 5 and color: packet.extend(color) # Calculate checksum and append it checksum = compute_checksum(packet) packet.append(checksum) return packet def build_qr_code_command(x, y, data): """Build QR code command packet(s) with optimized packetization for HID""" header = 0x02 type_code = 0x01 # LCD command op_code = 0x01 # Convert data to ASCII bytes qr_data = data.encode('ascii') # Prepare coordinates in correct byte order x_pos = struct.pack('>H', x) # Big endian ('>') unsigned short ('H') y_pos = struct.pack('>H', y) qr_data_length = struct.pack('>H', len(qr_data)) # Packet overhead (everything except the actual QR data) first_packet_overhead = 13 # header(1) + seq(1) + type(1) + op(1) + length(2) + x(2) + y(2) + data_len(2) continuation_packet_overhead = 7 # header(1) + seq(1) + type(1) + op(1) + length(2) + checksum(1) # Max QR data we can fit into the packet max_data_first_packet = MAX_DATA_SIZE - first_packet_overhead # First packet max_data_continuation_packet = MAX_DATA_SIZE - continuation_packet_overhead # Continuation packets packets = [] # If data fits in a single packet if len(qr_data) <= max_data_first_packet: seq = 0x01 total_data_length = struct.pack('>H', len(x_pos) + len(y_pos) + len(qr_data_length) + len(qr_data)) packet = bytearray([header, seq, type_code, op_code]) packet.extend(total_data_length) packet.extend(x_pos) packet.extend(y_pos) packet.extend(qr_data_length) packet.extend(qr_data) # Calculate checksum and append it checksum = compute_checksum(packet) packet.append(checksum) packets.append(packet) print(f"Single QR packet created: {len(packet)} bytes") else: # Need to split into multiple packets seq = 0x01 total_data_length = struct.pack('>H', len(x_pos) + len(y_pos) + len(qr_data_length) + len(qr_data)) first_packet = bytearray([header, seq, type_code, op_code]) first_packet.extend(total_data_length) first_packet.extend(x_pos) first_packet.extend(y_pos) first_packet.extend(qr_data_length) # Add as much QR data as possible to first packet first_packet_data = qr_data[:max_data_first_packet] first_packet.extend(first_packet_data) # Calculate checksum and append it checksum = compute_checksum(first_packet) first_packet.append(checksum) packets.append(first_packet) print(f"First QR packet created: {len(first_packet)} bytes with {len(first_packet_data)} bytes of QR data") # Handle remaining data in continuation packets remaining_data = qr_data[max_data_first_packet:] chunk_num = 2 # Start from 2 since 1 was the first packet while remaining_data: chunk = remaining_data[:max_data_continuation_packet] remaining_data = remaining_data[max_data_continuation_packet:] packet = bytearray([header, chunk_num, type_code, op_code]) # The length is just the chunk length for continuation packets chunk_length = struct.pack('>H', len(chunk)) packet.extend(chunk_length) packet.extend(chunk) # Calculate checksum and append it checksum = compute_checksum(packet) packet.append(checksum) packets.append(packet) print(f"Continuation packet {chunk_num-1}: {len(packet)} bytes with {len(chunk)} bytes of QR data") chunk_num += 1 if chunk_num > 255: # Ensure seq stays in byte range print("Warning: Sequence number overflow, wrapping to 1") chunk_num = 1 return packets def build_optimized_qr_packets(x, y, data): """Build optimized QR packets that utilize full 63 bytes per HID packet""" # Convert QR data to ASCII bytes qr_data = data.encode('ascii') # Create initial command (first packet) header = 0x02 type_code = 0x01 # LCD command op_code = 0x01 seq = 0x01 # Prepare coordinates x_pos = struct.pack('>H', x) y_pos = struct.pack('>H', y) qr_data_length = struct.pack('>H', len(qr_data)) # Calculate total data length total_data_length = struct.pack('>H', len(x_pos) + len(y_pos) + len(qr_data_length) + len(qr_data)) # Create initial packet structure first_packet = bytearray([header, seq, type_code, op_code]) first_packet.extend(total_data_length) first_packet.extend(x_pos) first_packet.extend(y_pos) first_packet.extend(qr_data_length) # First packet overhead: 13 bytes (header+seq+type+op+length(2)+x(2)+y(2)+data_len(2)+checksum) first_packet_overhead = 13 # Maximum data we can fit in first packet max_data_first_packet = MAX_DATA_SIZE - first_packet_overhead # Continuation packet overhead: 7 bytes (header+seq+type+op+length(2)+checksum) continuation_packet_overhead = 7 # Maximum data per continuation packet max_data_continuation_packet = MAX_DATA_SIZE - continuation_packet_overhead # Prepare packets list hid_packets = [] # Handle first packet first_chunk = qr_data[:max_data_first_packet] first_packet.extend(first_chunk) checksum = compute_checksum(first_packet) first_packet.append(checksum) hid_packets.append(first_packet) # Handle remaining data remaining_data = qr_data[max_data_first_packet:] packet_num = 2 while remaining_data: chunk = remaining_data[:max_data_continuation_packet] remaining_data = remaining_data[max_data_continuation_packet:] packet = bytearray([header, packet_num, type_code, op_code]) chunk_length = struct.pack('>H', len(chunk)) packet.extend(chunk_length) packet.extend(chunk) checksum = compute_checksum(packet) packet.append(checksum) hid_packets.append(packet) packet_num += 1 # Handle sequence number overflow if packet_num > 255: packet_num = 1 # Debug information print(f"Created {len(hid_packets)} HID packets for QR data of length {len(qr_data)}") for i, packet in enumerate(hid_packets): print(f"Packet {i+1}: {len(packet)} bytes") return hid_packets def build_text_command(font, font_size, color,bg_color, x, y, data): """Build a text command packet with adjusted font size and position""" header = 0x02 type_code = 0x01 # LCD command op_code = 0x02 seq = 0x01 # Convert data to ASCII bytes text_data = data.encode('ascii') # Use struct to ensure proper byte order for positions x_pos = struct.pack('>H', x) # Big endian ('>') unsigned short ('H') y_pos = struct.pack('>H', y) text_data_length = struct.pack('>H', len(text_data)) # Calculate total data length (1 for font + 1 for size + 3 for RGB + positions + text) total_data_length = struct.pack('>H', 1 + 1 + 3 + 3 + len(x_pos) + len(y_pos) + len(text_data_length) + len(text_data)) # Build packet packet = bytearray([header, seq, type_code, op_code]) packet.extend(total_data_length) packet.append(font) packet.append(font_size) packet.extend(color) packet.extend(bg_color) packet.extend(x_pos) packet.extend(y_pos) packet.extend(text_data_length) packet.extend(text_data) # Calculate checksum and append it checksum = compute_checksum(packet) packet.append(checksum) # Debug info print(f"Text Packet length: {len(packet)} bytes") print(f"Text Data length: {len(text_data)} bytes") print(f"Font: {font}, Size: {font_size}") print(f"Position: ({x}, {y})") print(f"Color: RGB({color[0]}, {color[1]}, {color[2]})") return packet def create_hid_report(packet): """Create an HID report with the packet data""" total_size = len(packet) + 2 # 2 bytes for report ID and length byte if total_size > MAX_HID_PACKET_SIZE: print(f"Error: The packet exceeds the maximum allowed size. Packet length: {total_size}") return None report_data = bytearray(MAX_HID_PACKET_SIZE) report_data[0] = 0x00 # Report ID report_data[1] = len(packet) # Length of the packet (excluding the report ID byte) for i in range(len(packet)): report_data[i + 2] = packet[i] return report_data # def send_command_to_hid(packet): # """Send command packet to HID device""" # try: # device = hid.device() # device.open(VENDOR_ID, PRODUCT_ID) # device.set_nonblocking(1) # report_data = create_hid_report(packet) # print(f"report_data {report_data.hex()} bytes") # if not report_data: # print("Packet too large. Aborting send.") # return False # # Send packet data # bytes_written = device.write(report_data) # print(f"Sent {bytes_written} bytes") # # Wait for response (optional) # time.sleep(1) # device.close() # return True # except Exception as e: # print(f"Error sending command to HID device: {e}") # return False def send_command_to_hid(packet): """Send command packet to HID device and read response""" try: device = hid.device() device.open(VENDOR_ID, PRODUCT_ID) device.set_nonblocking(1) report_data = create_hid_report(packet) if not report_data: print("Packet too large. Aborting send.") return False print(f"report_data {report_data.hex()} bytes") bytes_written = device.write(report_data) print(f"Sent {bytes_written} bytes") # Wait for device to process and respond time.sleep(0.5) response = device.read(64, timeout_ms=1000) # Try to read response if response: print(f"Response from device: {bytes(response).hex()}") else: print("No response received from device.") device.close() return True except Exception as e: print(f"Error sending command to HID device: {e}") return False def send_multiple_commands(commands_list): """Send multiple commands with proper sequencing and delays""" for i, cmd_packet in enumerate(commands_list): print(f"\nSending command {i+1} of {len(commands_list)}...") success = send_command_to_hid(cmd_packet) if not success: print(f"Failed at command {i+1}") return False time.sleep(0.1) # Wait between commands return True def clear_screen(): """Clear the screen first with a home background""" return build_background_command(1, 4) # Home Background def format_packet_bytes(packet): """Format packet bytes for display""" return ' '.join(f'{b:02X}' for b in packet) def build_play_sound_command(op): header = 0x02 seq = 0x02 # Sequence number type_code = 0x02 # Command type for sound play op_code = op # Operation code for play sound # Build packet packet = bytearray([header, seq, type_code, op_code]) # Ensure the packet doesn't exceed the maximum allowed size if len(packet) > MAX_HID_PACKET_SIZE: print(f"Error: The packet exceeds the maximum allowed size. Packet length: {len(packet)}") return None # Calculate checksum and append it checksum = compute_checksum(packet) packet.append(checksum) return packet def build_success_with_amount_command(amount): """Build a success command followed by a text command displaying the amount""" commands = [] # First, add the success background command commands.append(build_background_command(1, 2)) # Success payment background # Then, add the text command to display the amount text_message = f"Rs. {amount}" commands.append(build_text_command( font=1, # Normal font font_size=200, color=[0, 0, 0], bg_color=[255, 255, 255], x=0, # X position y=600, # Y position data=text_message )) return commands def build_play_tts_num_command(num): header = 0x02 seq = 0x01 # Sequence number type_code = 0x02 # Command type for sound play op_code = 8 # Operation code for play sound num_data_length = struct.pack('>H', 4) num_data = struct.pack('>I', num) # 4 Byte big endian # Build packet packet = bytearray([header, seq, type_code, op_code]) packet.extend(num_data_length) packet.extend(num_data) # Ensure the packet doesn't exceed the maximum allowed size if len(packet) > MAX_HID_PACKET_SIZE: print(f"Error: The packet exceeds the maximum allowed size. Packet length: {len(packet)}") return None # Calculate checksum and append it checksum = compute_checksum(packet) packet.append(checksum) return packet def main(): """Main function to run the HID tool""" print("HID Background Command Tool") print("==========================") while True: print("\nSelect a command to send:") print("1: Home Background") print("2: Success payment Background") print("3: Pending payment Background") print("4: Fail payment Background") print("5: Send Optimized QR Code (for long & short data)") print("0: Exit") try: user_choice = int(input()) if user_choice < 0 or user_choice > 6: print("Invalid input! Enter a number between 0 and 5.") return except ValueError: print("Invalid input! Enter a number between 0 and 5.") continue if user_choice == 0: print("Exiting program.") break elif user_choice == 1: # welcome Background with sound cmd_packet = build_background_command(1, 1) # welcome background sound_packet = build_play_sound_command(1) # welcome sound (op_code 1) send_multiple_commands([cmd_packet, sound_packet]) elif user_choice == 2: # Success with Amount try: amount = int(input("Enter the payment amount: ")) commands = build_success_with_amount_command(amount) # Display/Text commands tts_command = build_play_tts_num_command(amount) # Audio command all_commands = [] all_commands.extend(commands) # Display commands first if tts_command: all_commands.append(tts_command) # Then play audio send_multiple_commands(all_commands) except ValueError: print("Invalid amount input.") continue elif user_choice == 3: # pending Background with sound cmd_packet = build_background_command(1, 3) # pending background sound_packet = build_play_sound_command(6) # pending sound (op_code 6) send_multiple_commands([cmd_packet, sound_packet]) elif user_choice == 4: # Fail Background with sound cmd_packet = build_background_command(1, 4) # Fail background sound_packet = build_play_sound_command(4) # Fail sound (op_code 4) send_multiple_commands([cmd_packet, sound_packet]) elif user_choice == 5: # Optimized QR Code and Text Amount try: print("Starting QR Code and Text Amount Display...") # Initialize HID communication hid_comm = HidCommunication() # Get user input for QR text with validation while True: qr_text = input("Enter QR code text: ").strip() if qr_text: break print("Error: QR text cannot be empty. Please try again.") # Get coordinates with validation while True: try: x_position = int(input("Enter X position for QR (180): ")) y_position = int(input("Enter Y position for QR (600): ")) if 0 <= x_position <= 800 and 0 <= y_position <= 1280: break print("Error: Coordinates out of range. X(0-800), Y(0-1280)") except ValueError: print("Invalid input. Please enter numbers only.") # Get user input for the amount text (amount to be displayed on the HID device) while True: amount_text = input("Enter amount text to display: ").strip() if amount_text: break print("Error: Amount text cannot be empty. Please try again.") amount_text = f"Rs. {amount_text}" text_x_position = 0 text_y_position = 450 # Define text parameters (font, size, and color) font = 1 # Example font font_size = 200 # Example font size color = (0, 0, 0) # White color for text # Play the QR display sound (dqr) before displaying the QR code sound_command = build_play_sound_command(2) # Audio command for dqr (QR code display sound) # Initialize all commands all_commands = [sound_command] # Execute QR display hid_comm.OnLcdDqrClicked(qr_text, x_position, y_position) print("QR code display initiated. Processing...") # Wait for the QR code display process to finish time.sleep(1) # Build and send text command text_packet = build_text_command(font, font_size, color,[255,255,255], text_x_position, text_y_position, amount_text) # Send text data packet # hid_comm.SendData(text_packet) send_command_to_hid(text_packet) print(f"Text packet sent: {format_packet_bytes(text_packet)}") print("Amount text display initiated. Processing...") # Wait for the text display process to finish time.sleep(1) # Send all commands (audio + text display) send_multiple_commands(all_commands) except Exception as e: print(f"An error occurred: {str(e)}") continue else: # Other background commands cmd_packet = build_background_command(1, user_choice) send_command_to_hid(cmd_packet) if __name__ == "__main__": main()