From 1139f3993dfe2810c3374af707931f871cfff49b Mon Sep 17 00:00:00 2001 From: vinay-dev95 Date: Fri, 11 Jul 2025 14:40:44 +0530 Subject: [PATCH] update bootmode --- example/01_commands.py | 22 ++- example/02_blackframes.py | 2 +- model2450lib/__init__.py | 1 + model2450lib/model.py | 55 ------- model2450lib/model2450.py | 196 ++++++++++++++++--------- model2450lib/packetutils.py | 83 +++++++++++ model2450lib/searchmodel.py | 74 +++++----- model2450lib/serial/__init__.py | 1 + model2450lib/serial/models.py | 60 ++++++++ model2450lib/serial/models2450.py | 33 +++++ model2450lib/serial/searchmodelboot.py | 70 +++++++++ model2450lib/serial/serialmodels.py | 59 ++++++++ model2450lib/serialmodel.py | 194 +++++++++++++++--------- setup.py | 2 +- 14 files changed, 619 insertions(+), 233 deletions(-) delete mode 100644 model2450lib/model.py create mode 100644 model2450lib/packetutils.py create mode 100644 model2450lib/serial/__init__.py create mode 100644 model2450lib/serial/models.py create mode 100644 model2450lib/serial/models2450.py create mode 100644 model2450lib/serial/searchmodelboot.py create mode 100644 model2450lib/serial/serialmodels.py diff --git a/example/01_commands.py b/example/01_commands.py index 5eef775..c5eab80 100644 --- a/example/01_commands.py +++ b/example/01_commands.py @@ -13,7 +13,7 @@ print(dev_list) # Replace 'COMX' with the appropriate COM port for Model2450 -sw1 = model2450.Model2450('COM10') +sw1 = model2450.Model2450('COM6') # print("switch 2450 connected:", sw1) # Connect the USB Switch sw1.connect() @@ -26,6 +26,26 @@ gread = sw1.get_read() # cmd for read the ambient light sensor print(gread) +time.sleep(1) +gread = sw1.get_read() # cmd for read the ambient light sensor +print(gread) + +time.sleep(1) +gread = sw1.get_read() # cmd for read the ambient light sensor +print(gread) + +time.sleep(1) +gcolor = sw1.get_color() # display the color reading +print(gcolor) + +time.sleep(1) +gcolor = sw1.get_color() # display the color reading +print(gcolor) + +time.sleep(1) +gcolor = sw1.get_color() # display the color reading +print(gcolor) + time.sleep(1) glevel = sw1.get_level() # cmd for read the light level for detecting blank frames print(glevel) diff --git a/example/02_blackframes.py b/example/02_blackframes.py index 52efa60..490ba46 100644 --- a/example/02_blackframes.py +++ b/example/02_blackframes.py @@ -12,7 +12,7 @@ print(dev_list) # Replace 'COMX' with the appropriate COM port for Model2450 -sw1 = model2450.Model2450('COM10') +sw1 = model2450.Model2450('COM6') # print("switch 2450 connected:", sw1) # Connect the USB Switch sw1.connect() diff --git a/model2450lib/__init__.py b/model2450lib/__init__.py index e69de29..203562b 100644 --- a/model2450lib/__init__.py +++ b/model2450lib/__init__.py @@ -0,0 +1 @@ +# __init__.py \ No newline at end of file diff --git a/model2450lib/model.py b/model2450lib/model.py deleted file mode 100644 index df55f74..0000000 --- a/model2450lib/model.py +++ /dev/null @@ -1,55 +0,0 @@ -############################################################################## -# -# Module: model.py -# -# Description: -# API to send commands -# -# Released under the MCCI Corporation. -# -# Author: -# Vinay N, MCCI Corporation August 2024 -# -# Revision history: -# V1.0.0 Wed Aug 2024 12:05:00 Vinay N -# Module created -############################################################################## - -from model2450lib import serialmodel - -class Model(serialmodel.SerialDev): - def __init__(self, cport, baud): - self.sport = serialmodel.SerialDev(cport, baud) - - def connect(self): - return self.sport.open() - - def disconnect(self): - return self.sport.close() - - def get_version(self): - cmd = 'version\r\n' - return self.send_cmd(cmd) - - def send_cmd(self, cmd): - # self.clear_buffer() # Clear buffer before sending command - res = self.sport.write(cmd) - if res > 0: - res, rstr = self.sport.read() - else: - rstr = "Comm Error\n" - return res, rstr - - def send_blinkcommand(self, cmd): - re = self.sport.write(cmd) - lines = self.sport.read_multiple_lines() - return re, "\n".join(lines) - - def send_command(self, cmd): - # self.write(cmd.encode('utf-8') + b'\r\n') - # self.sport.write(cmd.encode('utf-8') + b'\r\n') - re = self.sport.write(cmd) - response1 = self.sport.readcolor() - response2 = self.sport.readcolor() - - return re, response1 diff --git a/model2450lib/model2450.py b/model2450lib/model2450.py index 9042234..6a058f0 100644 --- a/model2450lib/model2450.py +++ b/model2450lib/model2450.py @@ -1,3 +1,4 @@ + ############################################################################## # # Module: model2450.py @@ -8,90 +9,149 @@ # Released under the MCCI Corporation. # # Author: -# Vinay N, MCCI Corporation August 2024 +# Vinay N, MCCI Corporation May 2025 # # Revision history: -# V1.0.0 Wed Aug 2024 12:05:00 Vinay N +# V1.0.1 Wed May 2025 12:05:00 Vinay N # Module created ############################################################################## -from model2450lib import model +from model2450lib.serialmodel import SerialDevice +from model2450lib.packetutils import decode_packet, read_packet_from_serial, read_block_frames +import time -class Model2450(model.Model): - def __init__(self, cport): - model.Model.__init__(self, cport, 115200) - - def read_sn(self): - cmd = 'sn\r\n' - rc, rstr = self.send_cmd(cmd) - # print(rc,rstr) - return (rstr) +class Model2450(SerialDevice): + def __init__(self, port): + super().__init__(port) + self.r_data = [] + self.g_data = [] + self.b_data = [] + self.light_data = [] + self.time_data = [] + self.keep_running = True + + def read_sn(self): + return self.send_cmd('sn\r\n') + def read_sn(self): + return self.send_cmd('sn\r\n') + def get_version(self): - cmd = 'version\r\n' - rc, rstr = self.send_cmd(cmd) - # print("rstr-version:", rstr) - return (rc, rstr) - - def do_reset(self): - cmd = 'reset\r\n' - rc, rstr = self.send_cmd(cmd) - # print("rstr-version:", rstr) - return (rc, rstr) + return self.send_cmd('version\r\n') + + def get_color(self): + return self.send_cmd('color\r\n') - def get_read(self): - cmd = 'read\r\n' - rc, rstr = self.send_cmd(cmd) - # print("read->:",rstr) - return (rstr) + return self.send_cmd('read\r\n') - def get_level(self): - cmd = 'level\r\n' - rc, rstr = self.send_cmd(cmd) - # print("level->", rstr) - return rstr + return self.send_cmd('level\r\n') - def set_level(self, value): - cmd = self.set_level_cmd(value) - return self.send_cmd(cmd) - - def set_level_cmd(self, value): - return 'level '+str(value)+'\r\n' - - - def get_color(self): - cmd = 'color\r\n' - rc, rstr = self.send_command(cmd) - # print("color->", rstr) - return rstr - def set_red(self): - cmd = 'set red\r\n' - rc, rstr = self.send_cmd(cmd) - return rstr + return self.send_cmd('set red\r\n') def set_blue(self): - cmd = 'set blue\r\n' - rc, rstr = self.send_cmd(cmd) - return rstr - + return self.send_cmd('set blue\r\n') + def set_green(self): - cmd = 'set green\r\n' - rc, rstr = self.send_cmd(cmd) - return rstr + return self.send_cmd('set green\r\n') - # def set_th_light(self): - # cmd = "level" - def set_run(self): - cmd = 'run\r\n' - rc, rstr = self.send_blinkcommand(cmd) - # print(f"run command output:\n{rstr}") - return rstr - + return self.send_text_command('run\r\n') + def set_stop(self): - cmd = 'stop\r\n' - rc, rstr = self.send_blinkcommand(cmd) - # print(f"stop command output:\n{rstr}") - return rstr + return self.send_text_command('stop\r\n') + + def do_reset(self): + try: + self.send_command('reset -b\r\n') + time.sleep(0.1) # Give time for device to reset + self.disconnect() # Close serial port cleanly + except Exception as e: + print(f"Ignoring expected error during reset: {e}") + + def reset_mode(self): + try: + self.send_command('reset\r\n') + time.sleep(0.1) # Give time for device to reset + self.disconnect() # Close serial port cleanly + except Exception as e: + print(f"Ignoring expected error during reset: {e}") + + def set_level(self, value): + cmd = f'level {value}\r\n' + return self.send_cmd(cmd) + + def get_stream3(self, callback=None): + """ + Continuously stream data from the device and call the callback with each piece of data. + """ + self.send_stream_cmd("stream 3\r\n") # or whatever command starts the stream + + while self.ser and self.ser.is_open: + packet = read_packet_from_serial(self.ser) + if packet: + try: + decoded = decode_packet(packet) + payload = decoded.get("payload", b"") + ascii_payload = payload.decode("ascii", errors="ignore").strip() + + if ascii_payload: + print(f"[get_stream3] Received: {ascii_payload}") + if callback: + callback(ascii_payload) + + except Exception as e: + print(f"[get_stream3] Decode error: {e}") + + + def run_blank_frame_sequence(self, duration=10): + """ + Sends 'run' command to start blank frames, and automatically sends 'stop' after a specified duration. + """ + self.ser.write(b"run\r\n") # Use self.ser instead of ser + + start_time = time.time() # Track the start time + buffered_payload = b"" + blank_frame_count = 0 # Initialize a counter for blank frames + + while self.ser and self.ser.is_open: + # Check if the elapsed time has passed the duration + if time.time() - start_time >= duration: + self.stop_blank_frame_sequence() # Stop the sequence after the specified duration + break + + packet = read_block_frames(self.ser) + if packet: + try: + decoded = decode_packet(packet) + payload = decoded.get("payload", b"") + start_bit = decoded["start_bit"] + end_bit = decoded["end_bit"] + if start_bit: + buffered_payload = payload + else: + buffered_payload += payload + + if end_bit or len(payload) < decoded["length"] - 2: + try: + ascii_payload = buffered_payload.decode("ascii").strip() + if not ascii_payload: # Consider empty payload as blank frame + blank_frame_count += 1 + except UnicodeDecodeError: + print(f"payload: {buffered_payload.hex()} (non-ascii)") + buffered_payload = b"" + + except Exception as decode_err: + print("Decode error:", decode_err) + + time.sleep(0.0006) + + return blank_frame_count # Return the count of blank frames detected + + def stop_blank_frame_sequence(self): + """ + Sends 'stop' command to stop the blank frame sequence. + """ + self.ser.write(b"stop\r\n") # Use self.ser instead of ser + print("Sent: stop") diff --git a/model2450lib/packetutils.py b/model2450lib/packetutils.py new file mode 100644 index 0000000..b985b10 --- /dev/null +++ b/model2450lib/packetutils.py @@ -0,0 +1,83 @@ +# packetutils.py +############################################################################## +# +# Module: packetutils.py +# +# Description: +# this is decoding and encoding the commands when command is enable +# under packetaization format. +# +# Released under the MCCI Corporation. +# +# Author: +# Vinay N, MCCI Corporation May 2025 +# +# Revision history: +# V1.0.1 Wed May 2025 12:05:00 Vinay N +# Module created +############################################################################## +import time + +def decode_packet(packet_bytes): + # print("packet_bytes:", packet_bytes) + + if len(packet_bytes) < 2: + raise ValueError("Packet too short to decode header.") + + header_byte_0 = packet_bytes[0] + header_byte_1 = packet_bytes[1] + + start_bit = (header_byte_0 >> 7) & 0x01 + end_bit = (header_byte_0 >> 6) & 0x01 + reserved = (header_byte_0 >> 5) & 0x01 + command = header_byte_0 & 0x1F + + sequence = (header_byte_1 >> 5) & 0x07 + length = header_byte_1 & 0x1F + + if len(packet_bytes) < length: + raise ValueError(f"Packet length mismatch. Expected {length}, got {len(packet_bytes)}") + + payload = packet_bytes[2:length] + + return { + "start_bit": start_bit, + "end_bit": end_bit, + "reserved": reserved, + "command": command, + "sequence": sequence, + "length": length, + "payload": payload + } + +def read_packet_from_serial(ser): + header = ser.read(2) + if len(header) < 2: + return None + + length = header[1] & 0x1F + remaining = length - 2 + + # Read the remaining payload robustly + payload = b"" + while len(payload) < remaining: + more = ser.read(remaining - len(payload)) + if not more: + return None + payload += more + + return header + payload + +def read_block_frames(ser): + header = ser.read(2) + # print("......header:", header) + if len(header) < 2: + return None + + length = header[1] & 0x1F + remaining = length - 2 + payload = ser.read(remaining) + if len(payload) < remaining: + return None + + return header + payload diff --git a/model2450lib/searchmodel.py b/model2450lib/searchmodel.py index 4171ec6..5b043f9 100644 --- a/model2450lib/searchmodel.py +++ b/model2450lib/searchmodel.py @@ -8,10 +8,10 @@ # Released under the MCCI Corporation. # # Author: -# Vinay N, MCCI Corporation August 2024 +# Vinay N, MCCI Corporation May 2025 # # Revision history: -# V1.0.0 Wed Aug 2024 12:05:00 Vinay N +# V1.0.1 Wed May 2025 12:05:00 Vinay N # Module created ############################################################################## import serial @@ -20,6 +20,8 @@ import sys import usb.util from usb.backend import libusb1 +# from packetutils import read_packet_from_serial, decode_packet +from .packetutils import read_packet_from_serial, decode_packet def version(): @@ -49,50 +51,43 @@ def filter_port(): def check_status(myport): try: - # Attempt to open the serial port ser = serial.Serial(myport, baudrate=115200, bytesize=serial.EIGHTBITS, parity=serial.PARITY_NONE, timeout=1, stopbits=serial.STOPBITS_ONE) time.sleep(1) - # Send command to check version - version_cmd = 'version\r\n' - ser.write(version_cmd.encode()) - - # Read the initial response for the version - response = ser.readline().decode('utf-8') - - # Wait for the complete response - start_time = time.time() - while (time.time() - start_time) < 2: - line = ser.readline().decode('utf-8') - response += line - - # Check if version is '3:1' - if '3:1' in response: - ser.close() - return '2450' - - # Send command to check status - status_cmd = 'status\r\n' - ser.write(status_cmd.encode()) - - # Read the initial response for the status - response = ser.readline().decode('utf-8') - - # Wait for the complete response - start_time = time.time() - while (time.time() - start_time) < 2: - line = ser.readline().decode('utf-8') - response += line + # Send version command and try to decode the response + ser.write(b'version\r\n') + time.sleep(0.1) + raw_packet = read_packet_from_serial(ser) + + if raw_packet: + try: + decoded = decode_packet(raw_packet) + payload_str = bytes(decoded["payload"]).decode('ascii', errors='ignore') + if '3:1' in payload_str or '8:1' in payload_str or '9:1' in payload_str: + ser.close() + return '2450' + except Exception as e: + print(f"Packet decoding failed: {e}") + + # If version didn't return valid result, try status + ser.write(b'status\r\n') + time.sleep(0.1) + raw_packet = read_packet_from_serial(ser) + + if raw_packet: + try: + decoded = decode_packet(raw_packet) + payload_str = bytes(decoded["payload"]).decode('ascii', errors='ignore') + if 'Brightness And Color Kit' in payload_str: + ser.close() + return '2450' + except Exception as e: + print(f"Packet decoding failed: {e}") ser.close() - - # Check if status contains 'Brightness And Color Kit' - if 'Brightness And Color Kit' in response: - return '2450' - return None except serial.SerialException as e: @@ -103,6 +98,7 @@ def check_status(myport): print(f"Unexpected error: {e}") return None + def search_models(): port_name = filter_port() rev_list = [] @@ -124,4 +120,4 @@ def search_models(): devlist.append(tempdict) rdict["models"] = devlist - return rdict + return rdict \ No newline at end of file diff --git a/model2450lib/serial/__init__.py b/model2450lib/serial/__init__.py new file mode 100644 index 0000000..203562b --- /dev/null +++ b/model2450lib/serial/__init__.py @@ -0,0 +1 @@ +# __init__.py \ No newline at end of file diff --git a/model2450lib/serial/models.py b/model2450lib/serial/models.py new file mode 100644 index 0000000..59a95fa --- /dev/null +++ b/model2450lib/serial/models.py @@ -0,0 +1,60 @@ +############################################################################## +# +# Module: models.py +# +# Description: +# API to send commands +# +# Released under the MCCI Corporation. +# +# Author: +# Vinay N, MCCI Corporation May 2025 +# +# Revision history: +# V1.0.1 Wed May 2025 12:05:00 Vinay N +# Module created +############################################################################## + +from model2450lib.serial import serialmodels + +class Switch(serialmodels.SerialDev): + def __init__(self, cport, baud): + self.sport = serialmodels.SerialDev(cport, baud) + + def connect(self): + return self.sport.open() + + def disconnect(self): + return self.sport.close() + + def get_version(self): + cmd = 'version\r\n' + return self.send_cmd(cmd) + + def send_cmd(self, cmd): + res = self.sport.write(cmd) + if res > 0: + res, rstr = self.sport.read() + else: + rstr = "Comm Error\n" + return res, rstr + + def send_reset(self, cmd): + res = self.sport.write(cmd) + if res > 0: + rstr = "success\n" + else: + rstr = "Comm Error\n" + return res, rstr + + def send_status_cmd(self, cmd): + outstr = "" + res = self.sport.write(cmd) + if res > 0: + for i in range(25): + res, rstr = self.sport.read() + if res == 0: + outstr = outstr + rstr + elif res == 0: + outstr = "Comm Error\n" + return res, outstr \ No newline at end of file diff --git a/model2450lib/serial/models2450.py b/model2450lib/serial/models2450.py new file mode 100644 index 0000000..136ed43 --- /dev/null +++ b/model2450lib/serial/models2450.py @@ -0,0 +1,33 @@ +############################################################################## +# +# Module: models2450.py +# +# Description: +# Top level API to manage Model 2450 +# +# Released under the MCCI Corporation. +# +# Author: +# Vinay N, MCCI Corporation May 2025 +# +# Revision history: +# V1.0.1 Wed May 2025 12:05:00 Vinay N +# Module created +############################################################################## + +from model2450lib.serial import models + +class Models2450(models.Switch): + def __init__(self, cport): + models.Switch.__init__(self, cport, 115200) + + def get_status(self): + cmd = 'status\r\n' + rc, rstr = self.send_status_cmd(cmd) + return(rc, rstr) + + def do_reset(self): + cmd = 'reset -b\r\n' + rc, rstr = self.send_reset(cmd) + return(rc, rstr) + \ No newline at end of file diff --git a/model2450lib/serial/searchmodelboot.py b/model2450lib/serial/searchmodelboot.py new file mode 100644 index 0000000..014301a --- /dev/null +++ b/model2450lib/serial/searchmodelboot.py @@ -0,0 +1,70 @@ +############################################################################## +# +# Module: searchmodelboot.py +# +# Description: +# API to show list of available COMX with Normal and boot mode. +# +# Released under the MCCI Corporation. +# +# Author: +# Vinay N, MCCI Corporation May 2025 +# +# Revision history: +# V1.0.1 Wed May 2024 12:05:00 Vinay N +# Module created +############################################################################## +import serial +import serial.tools.list_ports +import time + +TARGET_VID_PID = "VID:PID=045E:0646" # Target USB device VID:PID +STATUS_CMD = "status\r\n" + +def check_status(myport): + """Check the device model after sending a status command.""" + try: + ser = serial.Serial( + myport, baudrate=115200, bytesize=serial.EIGHTBITS, + parity=serial.PARITY_NONE, timeout=1, stopbits=serial.STOPBITS_ONE + ) + time.sleep(0.5) # Reduce sleep time to allow faster scanning + + ser.write(STATUS_CMD.encode()) # Send the status command + response = ser.readlines() # Read all available lines + + ser.close() # Ensure port is closed + + # Check if response contains "Model 3141" + for line in response: + decoded_line = line.decode('utf-8').strip() + if "Brightness And Color Kit" in decoded_line: + return "2450" # Detected Model 3141 + + return None # No valid response found + except serial.SerialException as e: + print(f"Error opening {myport}: {e}") + return None # Handle cases where the port cannot be opened + except Exception as e: + print(f"Unexpected error on {myport}: {e}") + return None # Handle any other unexpected errors + +def find_switch(): + """Search for connected COM ports and detect all Model 3141 devices.""" + comlist = serial.tools.list_ports.comports() + detected_ports = [] + + for port, desc, hwid in sorted(comlist): + + if TARGET_VID_PID in hwid: # Check if VID:PID matches + model = check_status(port) + print("model:", model) + if model == "2450": + result = f"{model}({port})" # Format as "3141(COMx)" + detected_ports.append(result) + + else: + print(f"No valid response from {port}") + detected_ports.append(port) # Append only COMx if not 3141 + + return detected_ports if detected_ports else None \ No newline at end of file diff --git a/model2450lib/serial/serialmodels.py b/model2450lib/serial/serialmodels.py new file mode 100644 index 0000000..0a514e6 --- /dev/null +++ b/model2450lib/serial/serialmodels.py @@ -0,0 +1,59 @@ +############################################################################## +# +# Module: searchmodels.py +# +# Description: +# API to show list of available MCCI Model 2450 BACK (Brightness and Color Kit) +# +# Released under the MCCI Corporation. +# +# Author: +# Vinay N, MCCI Corporation May 2025 +# +# Revision history: +# V1.0.1 Wed May 2024 12:05:00 Vinay N +# Module created +############################################################################## +import serial +import serial.tools.list_ports + +class SerialDev: + def __init__(self, port, baud): + self.handler = None + self.port = port + self.baud = baud + + def open(self): + self.handler = serial.Serial() + self.handler.port = self.port + self.handler.baudrate = self.baud + self.handler.bytesize = serial.EIGHTBITS + self.handler.parity = serial.PARITY_NONE + self.handler.timeout = 1 + self.handler.stopbits =serial. STOPBITS_ONE + + try: + res = self.handler.open() + return True + except serial.SerialException as e: + return False + + def close(self): + try: + self.handler.close() + return True + except: + return False + + def write(self, cmd): + try: + cnt = self.handler.write(cmd.encode()) + return cnt + except: + return -1 + + def read(self): + try: + return 0, self.handler.readline().decode('utf-8') + except: + return -1 \ No newline at end of file diff --git a/model2450lib/serialmodel.py b/model2450lib/serialmodel.py index 895dd85..ce87fd6 100644 --- a/model2450lib/serialmodel.py +++ b/model2450lib/serialmodel.py @@ -1,93 +1,151 @@ +# serial_com.py ############################################################################## # -# Module: serialmodel.py +# Module: searchmodel.py # # Description: -# serialmodel is shows serial port devices +# API to show list of available MCCI Model 2450 BACK (Brightness and Color Kit) # # Released under the MCCI Corporation. # # Author: -# Vinay N, MCCI Corporation August 2024 +# Vinay N, MCCI Corporation May 2025 # # Revision history: -# V1.0.0 Wed Aug 2024 12:05:00 Vinay N +# V1.0.1 Wed May 2024 12:05:00 Vinay N # Module created ############################################################################## +import time import serial import serial.tools.list_ports +from model2450lib.packetutils import decode_packet, read_packet_from_serial -class SerialDev: - def __init__(self, port, baud): - self.handler = None +class SerialDevice: + def __init__(self, port): self.port = port - self.baud = baud - - def open(self): - self.handler = serial.Serial() - self.handler.port = self.port - self.handler.baudrate = self.baud - self.handler.bytesize = serial.EIGHTBITS - self.handler.parity = serial.PARITY_NONE - self.handler.timeout = 1 - self.handler.stopbits =serial. STOPBITS_ONE - - try: - res = self.handler.open() - return True - except serial.SerialException as e: - return False - - def close(self): - try: - self.handler.close() - return True - except: - return False - - def write(self, cmd): - try: - cnt = self.handler.write(cmd.encode()) - return cnt - except: - return -1 + self.baudrate = 115200 + self.ser = None + self.keep_running = False - def read(self): - try: - return 0, self.handler.readline().decode('utf-8') - except: - return -1 - - # def read_line(self): - # try: - # return self.handler.readline().decode('utf-8').strip() - # except: - # return "" - - def read_multiple_lines(self): - lines = [] + def connect(self): try: - while True: - line = self.handler.readline().decode('utf-8').strip() - if line: - lines.append(line) - else: - break # Exit loop when no more data is received + self.ser = serial.Serial(self.port, baudrate=self.baudrate, timeout=1) except Exception as e: - print(f"Error reading multiple lines: {e}") - return lines - + print(f"Failed to connect: {e}") + self.ser = None - def readcolor(self): - try: - self.res1 = self.handler.readline().decode('utf-8').strip() - self.res2 = self.handler.readline().decode('utf-8').strip() + def disconnect(self): + if self.ser and self.ser.is_open: + self.ser.close() + def send_command(self, command): + if self.ser and self.ser.is_open: + self.ser.write(command.encode()) + time.sleep(0.001) + + def read_and_process(self): + if not self.ser: + return + + buffered_payload = b"" + + while True: + packet = read_packet_from_serial(self.ser) + if packet: + try: + # Decode the packet + decoded = decode_packet(packet) + payload = decoded.get("payload", b"") + start_bit = decoded["start_bit"] + end_bit = decoded["end_bit"] + reserved_bit = decoded["reserved"] + command = decoded["command"] + sequence = decoded["sequence"] + length = decoded["length"] + + if start_bit: + buffered_payload = payload + else: + buffered_payload += payload - # return self.res2 Actual return + if end_bit or len(payload) < decoded["length"] - 2: + try: + ascii_payload = buffered_payload.decode("ascii").strip() + + # Optional filtering logic + if ascii_payload and ascii_payload[0].isalpha(): + pass + elif ':' in ascii_payload: + pass - return self.res2 + buffered_payload = b"" # Reset after processing - except: - return " " + return ascii_payload # = + + except UnicodeDecodeError: + print("Non-ASCII Payload:", buffered_payload.hex()) + buffered_payload = b"" # Also reset here in error case + return buffered_payload.hex() + + except Exception as decode_err: + print("Decode error:", decode_err) + time.sleep(0.0006) + + def read_serial_data(self): + if not self.ser: + print("Serial not connected.") + return + + buffer = b"" + + while True: + packet = read_packet_from_serial(self.ser) + try: + if packet: + decoded = decode_packet(packet) + payload = decoded["payload"] + + buffer += payload + + # Check if a complete message (ending with \r\n) is received + while b'\r\n' in buffer: + line, buffer = buffer.split(b'\r\n', 1) + # print(f"Actual payload: {line + b'\r\n'}") + full_line = line + b'\r\n' + print(f"Actual payload: {full_line}") + + # return full_line + + except Exception as e: + print(f"Error reading data: {e}") + + def send_cmd(self, cmd): + """ + A utility function to send commands and get the response from the device. + """ + self.send_command(cmd) + return self.read_and_process() + + def send_stream_cmd(self, cmd): + self.send_command(cmd) + return self.read_serial_data() + def send_text_command(self, command, wait=2): + if not self.ser or not self.ser.is_open: + return "Serial port not connected.\n" + + self.ser.write(command.encode()) + output = f"[Sent TEXT command]: {command.strip()}\n" + + start_time = time.time() + while time.time() - start_time < wait: + if self.ser.in_waiting: + try: + response = self.ser.readline().decode('utf-8', errors='ignore').strip() + if response: + output += f"{response}\n" + except UnicodeDecodeError: + pass + time.sleep(0.1) + return output + \ No newline at end of file diff --git a/setup.py b/setup.py index 28d1918..5828c7c 100644 --- a/setup.py +++ b/setup.py @@ -18,7 +18,7 @@ setup( name='model2450lib', - version='1.0.1', + version='2.0.0', description='API for MCCI Model2450', author='Vinay N MCCI Corporation', author_email='',