#
#  Copyright (C) 2020-2021 Aloysius Indrayanto
#
#  This file is part of the eCxx library, see LICENSE file for the license details.
#


# Import modules from the system-wide Python installation
import os
import struct
import sys
import termios
import time
import traceback

# Import the embedded pySerial module
thisDirName = os.path.dirname( ( os.path.abspath(__file__) ) )
libsDirName = os.path.abspath( os.path.join(thisDirName, "../3rd_party/tools/EspDevelopment") )

sys.path.insert(0, libsDirName)

from pyserial import serial

# The lowest possible baudrate that would still be supported on most platforms
# which is not the magic baudrate of 1200 bps
LOWEST_BAUDRATE = 2400

# Reset pulse time
RESET_PULSE_TIME = 0.25

# Check the arguments
if( len(sys.argv) != 2 ) :
    print("\n")
    print("Usage: ResetMCUFromUSB <device>")
    print("\n")
    sys.exit(1)

# Get the serial device names
device0 = sys.argv[1]
device1 = device0[:-1] + str( int( device0[-1:] ) + 1 );

# Some termios constants
TIOCMBIS      = getattr(termios, 'TIOCMBIS',  0x5416)
TIOCMBIC      = getattr(termios, 'TIOCMBIC',  0x5417)

TIOCM_DTR     = getattr(termios, 'TIOCM_DTR', 0x0002)
TIOCM_RTS     = getattr(termios, 'TIOCM_RTS', 0x0004)

TIOCM_RTS_str = struct.pack('I', TIOCM_RTS)
TIOCM_DTR_str = struct.pack('I', TIOCM_DTR)

# Get the available baudrates from pySerial
keys   = list( serial.Serial.BAUDRATE_CONSTANTS.keys  () )
values = list( serial.Serial.BAUDRATE_CONSTANTS.values() )

# Get and check the current baudrate of port #0
baud0 = None
fd0   = None

fd0    = os.open(device0, os.O_RDONLY | os.O_NOCTTY | os.O_NONBLOCK)
ospeed = termios.tcgetattr(fd0)[5]
baud0  = keys[ values.index(ospeed) ]
if(baud0 == 1200) : baud0 = 9600 # Ensure the baudrate is not the same with the magic baudrate of 1200 bps

# Get and check the current baudrate of port #1
baud1 = None
fd1   = None

try :
    fd1    = os.open(device1, os.O_RDONLY | os.O_NOCTTY | os.O_NONBLOCK)
    ospeed = termios.tcgetattr(fd1)[5]
    baud1  = keys[ values.index(ospeed) ]
    if(baud1 == 1200) : baud1 = 9600 # Ensure the baudrate is not the same with the magic baudrate of 1200 bps
except :
    pass

# Try reset the attached MCU
try :
    # Open port #0 using the lowest possible baudrate which is not the magic baudrate
    ser = serial.Serial(port=device0, baudrate=LOWEST_BAUDRATE)

    # RTS high and DTR LOW
    #     It needs a try-except block because some USB drivers may immediately reset the MCU
    #     when the host PC open the serial port (without further waiting for RTS and DTR)
    try :
        ser.setRTS(True)
        ser.setDTR(False)
        time.sleep(RESET_PULSE_TIME)
        ser.setDTR(True)
    except :
        pass

    # Close port #0
    ser.close()

    # Close the file descriptors
    if(fd0 != None) : os.close(fd0)
    if(fd1 != None) : os.close(fd1)

    # Delay for a while
    time.sleep(RESET_PULSE_TIME * 2)

    # Restore the baudrate of port #0
    ser0 = serial.Serial(port=device0, baudrate=LOWEST_BAUDRATE)
    ser0.baudrate = baud0
    ser0.close()

    # Restore the baudrate of port #1 (if it exist)
    if(baud1 != None) :
        ser1 = serial.Serial(port=device1, baudrate=LOWEST_BAUDRATE)
        ser1.baudrate = baud1
        ser1.close()

except :
    traceback.print_exc()
