import sys
import datetime
import threading
import json
import RXTools # Trimble receiver communication tools (in GPSTools/pythonTools)
import argparse
import time

# Script to flash multiple receivers in parallel. It requires a JSON file that
# defines all the receivers. Note this same JSON file is used for other scripts
# in this directory, not all information is required to flash the devices.

# An example JSON file is given in the comments below:
#
#[
#  {"long":"CS1-BD940-1",  "user":"admin", "pw":"password", "short":"BD940-1(C1)",  "addr":"192.168.1.2",  "fw":"argon.timg", "clone":"DHS940B.xml", "isReference":"1"}, 
#  {"long":"CS1-BD940-2",  "user":"admin", "pw":"password", "short":"BD940-2(C1)",  "addr":"192.168.1.8",  "fw":"argon.timg", "clone":"DHS940RX.xml"}
#]

# Thread to perform the upgrade - we'll run N threads in parallel. One for each receiver
# we are going to flash
def workerUpgrade(num):
  print("Starting Flash RX = %s" % ( stations[num].get("long") ) )
  try:
    RXTools.upgradeFW( stations[num].get("addr"), stations[num].get("user"), stations[num].get("pw"), stations[num].get("fw"),False)
  except:
    print("!!!! Problem with flashing receiver Name = %s IP = %s File = %s !!!!" % 
           ( stations[num].get("long"), stations[num].get("addr"), stations[num].get("fw") ) )
    return

  # Normal exit
  nowStr = datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")
  print("%s - Completed Flash RX = %s IP = %s" % 
         (nowStr, stations[num].get("long"),stations[num].get("addr")) )
  return

if __name__ == "__main__":

  ######################################################################
  # Parse arguments
  parser = argparse.ArgumentParser(description='Flash receivers')
  parser.add_argument('-s','--stations', help='Filename of the station JSON e.g. --stations global.json')
  args = parser.parse_args()
  ######################################################################

  # Load the list of stations
  if(args.stations):
    with open(args.stations,'r') as f: 
      data = json.load(f)

    stations = []
    gotStations = False
    # New JSON format
    for i in range(len(data)):
      if('RX' in data[i]):
        stations = data[i]['RX']
        gotStations = True
    
    # Old format
    if(gotStations == False):
      stations = data
  else:
    print('require a station JSON file')
    sys.exit(1)
 
  nowStr = datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")
  print("\n%s - Starting Parallel quick flash (not a failsafe!!) of receivers found in %s\n" % (nowStr, args.stations) )

  # Now install a set of threads, one for each receiver. Each thread
  # will install firmware for a single receiver
  threadHandle = []
  for num in range(len(stations)):
    t = threading.Thread(target=workerUpgrade, args=(num,))
    threadHandle.append(t)
    t.start()
    # 50ms sleep - gives the task time to start before we start the next
    # one. This simply reduces the chance of the debug getting mangled
    # on stdout.
    time.sleep(0.05) 

  # Give the threads a couple of seconds to connect to the receiver and
  # complete outputing any status to stdout (otherwise the output in normal
  # operation can get mixed up with what follows). This is to simply
  # make the debug neater on stdout. There are cases, e.g. a problem
  # with a receiver, that can result in debug cluttering stdout.
  # However, for most normal cases this will work.
  time.sleep(2) 

  nowStr = datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")
  print("\n%s - Waiting for flash to complete on all receivers" % nowStr)
  # Now wait for the upgrades to finish, the following code will block
  # until all of the threads have returned
  for i in range(len(threadHandle)):
    threadHandle[i].join()
 
  nowStr = datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")
  print("%s - Flash completed" % nowStr)


