public void Save(string fileName)
        {
            StringBuilder builder = new StringBuilder();

            builder.AppendLine("#Created by PcJolt");
            builder.AppendLine("#" + DateTime.Now.ToString("d") + " " + DateTime.Now.ToString("T"));
            builder.AppendLine("mapBins=" + BuildOutputString(LoadBins));
            builder.AppendLine("rpmBins=" + BuildOutputString(RpmBins));
            for (byte loadIndex = 0; loadIndex < 10; loadIndex++)
            {
                byte[] bytes = new byte[10];
                Array.Copy(AdvanceMap, loadIndex * 10, bytes, 0, 10);
                builder.AppendLine("advance" + loadIndex + "=" + string.Join(",", bytes.Select(b => b.ToString()).ToArray()));
            }
            builder.AppendLine("correctionBins=" + BuildOutputString(AdvanceCorrection.Bins));
            builder.AppendLine("correctionValues=" + BuildOutputString(AdvanceCorrection.Values));
            builder.AppendLine("correctionPeakHold=" + AdvanceCorrection.PeakHoldCount);
            builder.AppendLine(BuildOutputString(UserOutput1, 0));
            builder.AppendLine(BuildOutputString(UserOutput2, 1));
            builder.AppendLine(BuildOutputString(UserOutput3, 2));
            builder.AppendLine(BuildOutputString(UserOutput4, 3));
            builder.AppendLine("shiftLight=" + ShiftLightThreshold / 100);
            builder.AppendLine("revLimit=" + RevLimitThreshold / 100);

            PersistedStorage.Write(fileName, builder.ToString());
            SavedState = SavedState ^ SavedStates.SavedToFile;
        }
        public void Load(string fileName)
        {
            LoadInProgress = true;

            try
            {
                byte[]     advance0 = new byte[10];
                byte[]     advance1 = new byte[10];
                byte[]     advance2 = new byte[10];
                byte[]     advance3 = new byte[10];
                byte[]     advance4 = new byte[10];
                byte[]     advance5 = new byte[10];
                byte[]     advance6 = new byte[10];
                byte[]     advance7 = new byte[10];
                byte[]     advance8 = new byte[10];
                byte[]     advance9 = new byte[10];
                byte[]     advanceCorrectionBins   = null;
                sbyte[]    advanceCorrectionValues = null;
                ushort     peakHoldCount           = 0;
                UserOutput userOutput1             = new UserOutput(Controller);
                UserOutput userOutput2             = new UserOutput(Controller);
                UserOutput userOutput3             = new UserOutput(Controller);
                UserOutput userOutput4             = new UserOutput(Controller);

                IEnumerable <string> fileContents = PersistedStorage.ReadAll(fileName);
                foreach (string line in fileContents)
                {
                    //Load Bins
                    if (line.StartsWith("mapBins", StringComparison.OrdinalIgnoreCase))
                    {
                        PopulateLoadBins(GetByteArrayFromLine(line));
                    }

                    //RPM Bins
                    else if (line.StartsWith("rpmBins", StringComparison.OrdinalIgnoreCase))
                    {
                        PopulateRpmBins(GetByteArrayFromLine(line).Select(item => (ushort)(item * 100)).ToArray());
                    }

                    //Advance Correction
                    else if (line.StartsWith("correctionBins", StringComparison.OrdinalIgnoreCase))
                    {
                        advanceCorrectionBins = GetByteArrayFromLine(line);
                    }
                    else if (line.StartsWith("correctionValues", StringComparison.OrdinalIgnoreCase))
                    {
                        advanceCorrectionValues = GetSByteArrayFromLine(line);
                    }
                    else if (line.StartsWith("correctionPeakHold", StringComparison.OrdinalIgnoreCase))
                    {
                        peakHoldCount = GetUShortFromLine(line);
                    }

                    //Ignition Advance
                    else if (line.StartsWith("advance0", StringComparison.OrdinalIgnoreCase))
                    {
                        advance0 = GetByteArrayFromLine(line);
                    }
                    else if (line.StartsWith("advance1", StringComparison.OrdinalIgnoreCase))
                    {
                        advance1 = GetByteArrayFromLine(line);
                    }
                    else if (line.StartsWith("advance2", StringComparison.OrdinalIgnoreCase))
                    {
                        advance2 = GetByteArrayFromLine(line);
                    }
                    else if (line.StartsWith("advance3", StringComparison.OrdinalIgnoreCase))
                    {
                        advance3 = GetByteArrayFromLine(line);
                    }
                    else if (line.StartsWith("advance4", StringComparison.OrdinalIgnoreCase))
                    {
                        advance4 = GetByteArrayFromLine(line);
                    }
                    else if (line.StartsWith("advance5", StringComparison.OrdinalIgnoreCase))
                    {
                        advance5 = GetByteArrayFromLine(line);
                    }
                    else if (line.StartsWith("advance6", StringComparison.OrdinalIgnoreCase))
                    {
                        advance6 = GetByteArrayFromLine(line);
                    }
                    else if (line.StartsWith("advance7", StringComparison.OrdinalIgnoreCase))
                    {
                        advance7 = GetByteArrayFromLine(line);
                    }
                    else if (line.StartsWith("advance8", StringComparison.OrdinalIgnoreCase))
                    {
                        advance8 = GetByteArrayFromLine(line);
                    }
                    else if (line.StartsWith("advance9", StringComparison.OrdinalIgnoreCase))
                    {
                        advance9 = GetByteArrayFromLine(line);
                    }

                    //User Output1
                    else if (line.StartsWith("userOutType0", StringComparison.OrdinalIgnoreCase))
                    {
                        userOutput1.OutputType = (UserOutputType)(2 - GetByteFromLine(line));
                    }
                    else if (line.StartsWith("userOutMode0", StringComparison.OrdinalIgnoreCase))
                    {
                        userOutput1.OutputMode = GetUserOutputModeFromLine(line);
                    }
                    else if (line.StartsWith("userOutValue0", StringComparison.OrdinalIgnoreCase))
                    {
                        userOutput1.Threshold = (ushort)(GetUShortFromLine(line) * (userOutput1.OutputType == UserOutputType.Rpm ? 100 : 1));
                    }

                    //User Output2
                    else if (line.StartsWith("userOutType1", StringComparison.OrdinalIgnoreCase))
                    {
                        userOutput2.OutputType = (UserOutputType)(2 - GetByteFromLine(line));
                    }
                    else if (line.StartsWith("userOutMode1", StringComparison.OrdinalIgnoreCase))
                    {
                        userOutput2.OutputMode = GetUserOutputModeFromLine(line);
                    }
                    else if (line.StartsWith("userOutValue1", StringComparison.OrdinalIgnoreCase))
                    {
                        userOutput2.Threshold = (ushort)(GetUShortFromLine(line) * (userOutput2.OutputType == UserOutputType.Rpm ? 100 : 1));
                    }

                    //User Output3
                    else if (line.StartsWith("userOutType2", StringComparison.OrdinalIgnoreCase))
                    {
                        userOutput3.OutputType = (UserOutputType)(2 - GetByteFromLine(line));
                    }
                    else if (line.StartsWith("userOutMode2", StringComparison.OrdinalIgnoreCase))
                    {
                        userOutput3.OutputMode = GetUserOutputModeFromLine(line);
                    }
                    else if (line.StartsWith("userOutValue2", StringComparison.OrdinalIgnoreCase))
                    {
                        userOutput3.Threshold = (ushort)(GetUShortFromLine(line) * (userOutput3.OutputType == UserOutputType.Rpm ? 100 : 1));
                    }

                    //User Output4
                    else if (line.StartsWith("userOutType3", StringComparison.OrdinalIgnoreCase))
                    {
                        userOutput4.OutputType = (UserOutputType)(2 - GetByteFromLine(line));
                    }
                    else if (line.StartsWith("userOutMode3", StringComparison.OrdinalIgnoreCase))
                    {
                        userOutput4.OutputMode = GetUserOutputModeFromLine(line);
                    }
                    else if (line.StartsWith("userOutValue3", StringComparison.OrdinalIgnoreCase))
                    {
                        userOutput4.Threshold = (ushort)(GetUShortFromLine(line) * (userOutput4.OutputType == UserOutputType.Rpm ? 100 : 1));
                    }

                    else if (line.StartsWith("shiftLight", StringComparison.OrdinalIgnoreCase))
                    {
                        ShiftLightThreshold = (ushort)(GetUShortFromLine(line) * 100);
                    }
                    else if (line.StartsWith("revLimit", StringComparison.OrdinalIgnoreCase))
                    {
                        RevLimitThreshold = (ushort)(GetUShortFromLine(line) * 100);
                    }
                }


                List <byte> ignitionMap = new List <byte>(100);
                ignitionMap.AddRange(advance0);
                ignitionMap.AddRange(advance1);
                ignitionMap.AddRange(advance2);
                ignitionMap.AddRange(advance3);
                ignitionMap.AddRange(advance4);
                ignitionMap.AddRange(advance5);
                ignitionMap.AddRange(advance6);
                ignitionMap.AddRange(advance7);
                ignitionMap.AddRange(advance8);
                ignitionMap.AddRange(advance9);

                PopulateIgnitionMap(ignitionMap.ToArray());
                UserOutput1.Populate(userOutput1);
                UserOutput2.Populate(userOutput2);
                UserOutput3.Populate(userOutput3);
                UserOutput4.Populate(userOutput4);
                if (advanceCorrectionBins != null && advanceCorrectionValues != null)
                {
                    AdvanceCorrection.Populate(advanceCorrectionBins, advanceCorrectionValues, peakHoldCount);
                }

                LoadInProgress = false;
                SavedState     = SavedStates.SavedToFile;
            }
            finally
            {
                LoadInProgress = false;
            }
        }