private static void ReloadIOconf(SerialNumberMapper serial)
 {
     IOconfFile.Reload();
     foreach (var board in serial.McuBoards)
     {
         foreach (var ioconfMap in IOconfFile.GetMap())
         {
             if (ioconfMap.SetMCUboard(board))
             {
                 board.BoxName = ioconfMap.BoxName;
             }
         }
     }
 }
        static async Task MainAsync(string[] args)
        {
            try
            {
                CALog.LogInfoAndConsoleLn(LogID.A, RpiVersion.GetWelcomeMessage($"Upload temperature data to cloud"));
                Console.WriteLine("Initializing...");
                using (var serial = await SerialNumberMapper.DetectDevices())
                {
                    if (args.Length > 0 && args[0] == "-listdevices")
                    {
                        return; // SerialNumberMapper already lists devices, no need for further output.
                    }
                    // close all ports which are not Hub10
                    serial.McuBoards.Where(x => !x.productType.Contains("Temperature") && !x.productType.Contains("Hub10STM")).ToList().ForEach(x => x.SafeClose(System.Threading.CancellationToken.None).Wait());

                    var email = IOconfSetup.UpdateIOconf(serial);

                    using var cmd   = new CommandHandler(serial);
                    using var usb   = new ThermocoupleBox(cmd);
                    using var cloud = new ServerUploader(cmd.GetFullSystemVectorDescription(), cmd);
                    CALog.LogInfoAndConsoleLn(LogID.A, "Now connected to server...");
                    _ = Task.Run(() => cmd.RunSubsystems());

                    int i = 0;
                    var uploadThrottle = new TimeThrottle(100);
                    while (cmd.IsRunning)
                    {
                        var(sensorsSamples, vectorTime) = cmd.GetFullSystemVectorValues();
                        cloud.SendVector(sensorsSamples.Select(v => v.Value).ToList(), vectorTime);
                        Console.Write($"\r data points uploaded: {i++}"); // we don't want this in the log file.
                        uploadThrottle.Wait();
                        if (i == 20)
                        {
                            DULutil.OpenUrl(cloud.GetPlotUrl());
                        }
                    }
                }
                CALog.LogInfoAndConsoleLn(LogID.A, Environment.NewLine + "Bye..." + Environment.NewLine + "Press any key to exit");
            }
            catch (Exception ex)
            {
                ShowHumanErrorMessages(ex);
            }

            Console.ReadKey();
        }
        public async Task Scale()
        {
            //Set the scale in RS232 mode by holding MODE until display show Prt, then press TARA.
            //Then press MODE until you see 'Cont in', then press TARA. Then connect to COM port with 9600 baud.

            var mapper = await SerialNumberMapper.DetectDevices();

            var list = mapper.ByProductType("Scale");

            for (int i = 0; i < 50; i++)
            {
                string str = string.Empty;
                foreach (var scale in list)
                {
                    str += (await scale.SafeReadLine(CancellationToken.None)).Replace("\r", "      ");
                }

                Debug.Print(str);
            }
        }
        public static string UpdateIOconf(SerialNumberMapper serial)
        {
            var mcuList = serial.McuBoards.Where(x => !x.serialNumber.StartsWith("unknown"));

            if (!mcuList.Any())
            {
                throw new Exception($"Could not find any devices connected to USB.");
            }

            if (!File.Exists("IO.conf"))
            {
                throw new Exception($"Could not find the file {Directory.GetCurrentDirectory()}\\IO.conf");
            }

            var lines = File.ReadAllLines("IO.conf").ToList();

            if (lines.Any(x => x.StartsWith("LoopName")) && lines.Any(x => x.StartsWith("Account")) && lines.Any(x => x.StartsWith("Map")) && lines.Count(x => x.StartsWith("TypeK")) > 1)
            {
                Console.WriteLine("Do you want to skip IO.conf setup? (yes, no)");
                var answer = Console.ReadLine();
                if (answer.ToLower().StartsWith("y"))
                {
                    if (lines.Any(x => x.StartsWith("Account")))
                    {
                        var user = lines.First(x => x.StartsWith("Account")).Split(";".ToCharArray(), StringSplitOptions.RemoveEmptyEntries).ToList();
                        return(user[2].Trim()); // return the email address.
                    }

                    return("");
                }
            }

            // comment out all the existing Map lines
            foreach (var mapLine in lines.Where(x => x.StartsWith("Map")).ToList())
            {
                int j = lines.IndexOf(mapLine);
                lines[j] = "// " + lines[j];
            }

            // add new Map lines
            int i = 1;

            foreach (var mcu in mcuList)
            {
                lines.Insert(4, $"Map;{mcu.serialNumber};ThermalBox{i++}");
            }

            if (lines.Any(x => x.StartsWith("LoopName")))
            {
                lines.Remove(lines.First(x => x.StartsWith("LoopName")));
            }

            Console.Write("Please enter a name for the webchart (It must be a new name you have not used before): ");
            var plotname = Console.ReadLine();

            if (plotname.Length > 50)
            {
                plotname = plotname.Substring(0, 50);
            }

            lines.Insert(0, $"LoopName;{plotname};Normal;https://www.theng.dk");

            if (lines.Any(x => x.StartsWith("Account")))
            {
                lines.Remove(lines.First(x => x.StartsWith("Account")));
            }

            Console.Write("Please enter your full name: ");
            var fullname = Console.ReadLine();

            if (fullname.Length > 100)
            {
                fullname = fullname.Substring(0, 100);
            }

            string email;

            Console.Write("Please enter your email address: ");
            do
            {
                email = Console.ReadLine();
            }while (!IsValidEmail(email));

            string pwd;

            Console.Write("Please enter a password for the webchart: ");
            do
            {
                pwd = Console.ReadLine();
            }while (!IsValidPassword(pwd));

            lines.Insert(1, $"Account; {fullname}; {email}; {pwd}");

            File.Delete("IO.conf");
            File.WriteAllLines("IO.conf", lines);
            ReloadIOconf(serial);

            if (mcuList.Count() > 1)
            {
                Console.ForegroundColor = ConsoleColor.Yellow;
                Console.WriteLine("You need to manually edit the IO.conf file and add more 'TypeK' lines..");
                Console.ForegroundColor = ConsoleColor.DarkGray;
                DULutil.OpenUrl("https://github.com/copenhagenatomics/CA_DataUploader/wiki/IO.conf-documentation");
            }

            return(email);
        }