示例#1
0
文件: FrmMain.cs 项目: littleking/DJK
        private void CalculateTxtData()
        {
            System.Data.DataTable dtInfo   = new System.Data.DataTable();
            System.Data.DataTable dtMatrix = new System.Data.DataTable();
            ipList = new List <InfoParser>();
            mpList = new List <MatrixParser>();
            if (File.Exists(infoFile) && File.Exists(matrixFile))
            {
                splashScreenManager1.ShowWaitForm();
                splashScreenManager1.SetWaitFormCaption("正在加载数据");
                splashScreenManager1.SetWaitFormDescription(" 请等待。。。");

                dtInfo   = OpenCSV(infoFile, 0, 0, 0, 0, true);
                dtMatrix = OpenCSV(matrixFile, 0, 0, 0, 0, true);
                foreach (DataRow dr in dtInfo.Rows)
                {
                    if (dr[0].ToString() == "0")
                    {
                        continue;
                    }
                    else
                    {
                        InfoParser ip = new InfoParser();
                        ip.No    = dr[0].ToString();
                        ip.Value = dr[1].ToString();
                        ip.Name  = dr[2].ToString();
                        ipList.Add(ip);
                    }
                }
                foreach (DataRow dr in dtMatrix.Rows)
                {
                    MatrixParser mp = new MatrixParser();
                    mp.No       = dr[0].ToString();
                    mp.Value    = dr[1].ToString();
                    mp.Name     = dr[2].ToString();
                    mp.OldValue = dr[3].ToString();
                    mpList.Add(mp);
                }

                splashScreenManager1.SetWaitFormCaption("正在计算");
                FrmCalculation frmCal = new FrmCalculation(mpList, ipList);
                splashScreenManager1.CloseWaitForm();
                frmCal.Show();
            }
            else
            {
                MessageBox.Show("CSV文件不存在");
            }
        }
示例#2
0
        private int SaveFileToDB(bool hasTitle, string fileName, string password)
        {
            Microsoft.Office.Interop.Excel.Application app = new Microsoft.Office.Interop.Excel.Application();
            Sheets   sheets;
            object   oMissiong = System.Reflection.Missing.Value;
            Workbook workbook  = null;

            System.Data.DataTable dt = new System.Data.DataTable();

            try
            {
                if (app == null)
                {
                    return(0);
                }
                workbook = app.Workbooks.Open(fileName, oMissiong, oMissiong, oMissiong, password, oMissiong,
                                              oMissiong, oMissiong, oMissiong, oMissiong, oMissiong, oMissiong, oMissiong, oMissiong, oMissiong);
                sheets = workbook.Worksheets;



                //将数据读入

                //worksheet 1
                Excel.Worksheet ws = (Worksheet)sheets.get_Item(1);
                if (ws == null)
                {
                    return(0);
                }

                string machineSourceCode = ((Excel.Range)ws.Cells[1, 1]).Text.ToString();
                string machineCode       = "";
                if (machineSourceCode.IndexOf("=") > 0)
                {
                    string[] machineCodes = machineSourceCode.Split('=');
                    if (machineCodes.Length == 2)
                    {
                        machineCode = machineCodes[1];
                    }
                }

                ws = (Worksheet)sheets.get_Item(2);
                string serialCode = ((Excel.Range)ws.Cells[3, 3]).Text.ToString();
                if (serialCode.IndexOf("_") > 0)
                {
                    string[] serialCodes = serialCode.Split('_');
                    if (serialCodes.Length == 2)
                    {
                        serialCode = serialCodes[1];
                    }
                }

                string sex = ((Excel.Range)ws.Cells[11, 3]).Text.ToString().ToLower();

                int iRowCount = ws.UsedRange.Rows.Count;
                int iColCount = ws.UsedRange.Columns.Count;

                //生成行数据 info
                List <InfoParser> ipList = new List <InfoParser>();
                Range             range;
                int rowIdx = hasTitle ? 2 : 1;
                for (int iRow = rowIdx; iRow <= iRowCount; iRow++)
                {
                    InfoParser ip = new InfoParser();
                    range    = (Range)ws.Cells[iRow, 1];
                    ip.No    = (range.Value2 == null) ? "" : range.Text.ToString();
                    range    = (Range)ws.Cells[iRow, 2];
                    ip.Value = (range.Value2 == null) ? "" : range.Text.ToString();
                    range    = (Range)ws.Cells[iRow, 3];
                    ip.Name  = (range.Value2 == null) ? "" : range.Text.ToString();
                    ipList.Add(ip);
                }

                //生成行数据 matrix
                ws        = (Worksheet)sheets.get_Item(3);
                iRowCount = ws.UsedRange.Rows.Count;
                iColCount = ws.UsedRange.Columns.Count;

                List <MatrixParser> mpList = new List <MatrixParser>();
                for (int iRow = rowIdx; iRow <= iRowCount; iRow++)
                {
                    MatrixParser mp = new MatrixParser();
                    range       = (Range)ws.Cells[iRow, 1];
                    mp.No       = (range.Value2 == null) ? "" : range.Text.ToString();
                    range       = (Range)ws.Cells[iRow, 2];
                    mp.Value    = (range.Value2 == null) ? "" : range.Text.ToString();
                    range       = (Range)ws.Cells[iRow, 3];
                    mp.Name     = (range.Value2 == null) ? "" : range.Text.ToString();
                    range       = (Range)ws.Cells[iRow, 4];
                    mp.OldValue = (range.Value2 == null) ? "" : range.Text.ToString();
                    mpList.Add(mp);
                }

                string info   = JsonConvert.SerializeObject(ipList);
                string matrix = JsonConvert.SerializeObject(mpList);

                modelSourceData.infoData    = info;
                modelSourceData.matrixData  = matrix;
                modelSourceData.serialCode  = serialCode;
                modelSourceData.machineCode = machineCode;
                modelSourceData.sex         = sex;
                int ret = dalSourceData.Add(modelSourceData);

                return(ret);
            }
            catch { return(0); }
            finally
            {
                workbook.Close(false, oMissiong, oMissiong);
                System.Runtime.InteropServices.Marshal.ReleaseComObject(workbook);
                workbook = null;
                app.Workbooks.Close();
                app.Quit();
                System.Runtime.InteropServices.Marshal.ReleaseComObject(app);
            }
        }
示例#3
0
        static async Task Main()
        {
            //Directory.SetCurrentDirectory(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location) ?? throw new InvalidOperationException());

            Log.Logger = new LoggerConfiguration()
                         .WriteTo.Console()
                         .Enrich.FromLogContext()
                         .MinimumLevel.Information()
                         .CreateLogger();
            var c = await JsonReader.ReadConfigAsync();

            foreach (var cfg in c)
            {
                Log.Logger.Information("Loading version configration: {0}", cfg.Version);
                //初始化parser
                var parser = new InfoParser(cfg.Configuration, cfg.CustomConfigurations);

                if (cfg.Configuration is not null)
                {
                    var dict = await JsonReader.ReadIntroAsync(cfg.Configuration.Version, cfg.Version);

                    var root = Directory.CreateDirectory(
                        $"{Directory.GetCurrentDirectory()}\\projects\\{cfg.Version}\\assets");

                    var names = root.GetDirectories().Select(_ => _.Name).ToList();

                    if (cfg.CustomConfigurations is not null)
                    {
                        foreach (var configuration in cfg.CustomConfigurations)
                        {
                            if (!names.Contains(configuration.ProjectName))
                            {
                                names.Add(configuration.ProjectName);
                            }
                        }
                    }

                    if (cfg.Count is not null)
                    {
                        var allMods = await UrlLib.GetModInfoAsync(cfg.Count.Value, cfg.Configuration.Version);

                        foreach (var modInfo in allMods)
                        {
                            if (dict.ContainsKey(modInfo.Slug) || dict.ContainsValue(modInfo.Id))
                            {
                                continue;
                            }
                            dict.Add(modInfo.Slug, modInfo.Id);
                        }

                        if (names.Count > cfg.Count)
                        {
                            var bin = allMods.Where(_ => !names.Contains(_.Slug));
                            var l   = allMods.ToList();
                            foreach (var info in bin)
                            {
                                l.Remove(info);
                            }

                            allMods = l.ToArray();
                        }
                        var allNames = allMods.ToList().Select(_ => _.Slug).Distinct().ToList();
                        var l1       = parser.SerializeAll(allMods).Distinct().ToList();

                        var pending = new List <string>();
                        foreach (var str in names)
                        {
                            if (!allNames.Contains(str))
                            {
                                pending.Add(str);
                            }
                        }

                        Log.Logger.Information($"该版本[assets]文件夹下含有 {names.Count} 个mod,有 {pending.Count} 要单独处理");
                        var semaphore = new SemaphoreSlim(16, 16);

                        var tasks = l1.Select(async mod =>
                        {
                            try
                            {
                                await semaphore.WaitAsync();
                                await Utils.ParseModsAsync(mod, cfg);
                            }
                            catch (Exception e)
                            {
                                Log.Logger.Error(e.Message);
                            }
                            finally
                            {
                                semaphore.Release();
                            }
                        });

                        await Task.WhenAll(tasks);

                        if (!Directory.Exists(@$ "{Directory.GetCurrentDirectory()}\config\spider\{cfg.Configuration.Version}"))
                        {
                            Directory.CreateDirectory(
                                @$ "{Directory.GetCurrentDirectory()}\config\spider\{cfg.Configuration.Version}");
                        }

                        var inf = new List <ModIntro>();
                        foreach (var(key, value) in dict)
                        {
                            inf.Add(new ModIntro()
                            {
                                Name = key, Id = value
                            });
                        }
                        await File.WriteAllTextAsync(@$ "{Directory.GetCurrentDirectory()}\config\spider\{cfg.Version}\intro.json",
                                                     JsonSerializer.Serialize(inf, new JsonSerializerOptions()
                        {
                            WriteIndented = true
                        }));

                        var ids = pending.Where(name => dict.ContainsKey(name)).Select(name => dict[name].ToString());

                        var infos = await UrlLib.GetModInfosAsync(ids);

                        var cfgs = parser.SerializeAll(infos);

                        var semaphore2 = new SemaphoreSlim(16, 16);
                        var postTask   = cfgs.Select(async _ =>
                        {
                            try
                            {
                                await semaphore2.WaitAsync();
                                await Utils.ParseModsAsync(_, cfg);
                            }
                            catch (Exception e)
                            {
                                Log.Logger.Error(e.Message);
                            }
                            finally
                            {
                                semaphore2.Release();
                            }
                        });

                        await Task.WhenAll(postTask);
                    }
示例#4
0
 /// <summary>
 /// Retrieves file information from the given filename
 /// </summary>
 /// <returns>File info</returns>
 public override Task <ParsedFileInfo> Execute() => InfoParser.Parse(FileName);
示例#5
0
        static async Task Main(string[] args)
        {
            //Directory.SetCurrentDirectory(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location) ?? throw new InvalidOperationException());

            Log.Logger = new LoggerConfiguration()
                         .WriteTo.Console()
                         .CreateLogger();
            var c = await JsonReader.ReadConfigAsync();

            foreach (var cfg in c)
            {
                var parser = new InfoParser(cfg.Configuration, cfg.CustomConfigurations);
                var root   = Directory.CreateDirectory(
                    $"{Directory.GetCurrentDirectory()}\\projects\\{cfg.Version}\\assets");

                var names = root.GetDirectories().Select(_ => _.Name).ToList();

                foreach (var configuration in cfg.CustomConfigurations)
                {
                    if (!names.Contains(configuration.ProjectName))
                    {
                        names.Add(configuration.ProjectName);
                    }
                }

                var allM = await UrlLib.GetModInfoAsync(cfg.Count, cfg.Version);

                var allN    = allM.ToList().Select(_ => _.ShortWebsiteUrl).ToList();
                var pending = new List <string>();
                foreach (var info in names)
                {
                    if (!allN.Contains(info))
                    {
                        pending.Add(info);
                    }
                }

                Log.Logger.Information($"该版本[assets]文件夹下含有 {names.Count} 个mod,{pending.Count} 个mod需要单独处理");

                var dict = await JsonReader.ReadIntroAsync(cfg.Version);

                if (names.Count > cfg.Count)
                {
                    var bin = allM.Where(_ => !names.Contains(_.ShortWebsiteUrl));
                    var l   = allM.ToList();
                    foreach (var info in bin)
                    {
                        l.Remove(info);
                    }

                    allM = l.ToArray();
                }
                parser.Infos = allM.ToList();
                var l1 = parser.SerializeAll();

                var semaphore = new Semaphore(32, 40);
                foreach (var l in l1)
                {
                    try {
                        semaphore.WaitOne();
                        await Utils.ParseModsAsync(l);
                    }
                    catch (Exception e) {
                        Log.Logger.Error(e.Message);
                    }
                    finally {
                        semaphore.Release();
                    }
                }

                foreach (var name in pending)
                {
                    if (dict.ContainsKey(name))
                    {
                        var m = await UrlLib.GetModInfoAsync(dict[name]);

                        var i = parser.Serialize(m);
                        try {
                            await Utils.ParseModsAsync(i);
                        }
                        catch (Exception e) {
                            Log.Logger.Error(e.Message);
                        }
                        Thread.Sleep(5000);
                    }
                }
            }
        }
示例#6
0
        /// <summary>
        /// Process an M-code that should be interpreted by the control server
        /// </summary>
        /// <param name="code">Code to process</param>
        /// <returns>Result of the code if the code completed, else null</returns>
        public static async Task <CodeResult> Process(Commands.Code code)
        {
            if (code.Channel == CodeChannel.File && FileExecution.Job.IsSimulating)
            {
                // Ignore M-codes from files in simulation mode...
                return(null);
            }

            switch (code.MajorNumber)
            {
            // Stop or Unconditional stop
            // Sleep or Conditional stop
            case 0:
            case 1:
                if (await SPI.Interface.Flush(code))
                {
                    using (await FileExecution.Job.LockAsync())
                    {
                        if (FileExecution.Job.IsFileSelected)
                        {
                            // M0/M1 may be used in a print file to terminate it
                            if (code.Channel != CodeChannel.File && !FileExecution.Job.IsPaused)
                            {
                                return(new CodeResult(MessageType.Error, "Pause the print before attempting to cancel it"));
                            }
                            code.CancellingPrint = true;
                        }
                    }
                    break;
                }
                throw new OperationCanceledException();

            // List SD card
            case 20:
                if (await SPI.Interface.Flush(code))
                {
                    // Resolve the directory
                    string virtualDirectory = code.Parameter('P');
                    if (virtualDirectory == null)
                    {
                        using (await Model.Provider.AccessReadOnlyAsync())
                        {
                            virtualDirectory = Model.Provider.Get.Directories.GCodes;
                        }
                    }
                    string physicalDirectory = await FilePath.ToPhysicalAsync(virtualDirectory);

                    // Make sure to stay within limits if it is a request from the firmware
                    int maxSize = -1;
                    if (code.Flags.HasFlag(CodeFlags.IsFromFirmware))
                    {
                        maxSize = SPI.Communication.Consts.MaxMessageLength;
                    }

                    // Check if JSON file lists were requested
                    int           startAt = Math.Max(code.Parameter('R') ?? 0, 0);
                    CodeParameter sParam  = code.Parameter('S', 0);
                    if (sParam == 2)
                    {
                        string json = FileLists.GetFiles(virtualDirectory, physicalDirectory, startAt, true, maxSize);
                        return(new CodeResult(MessageType.Success, json));
                    }
                    if (sParam == 3)
                    {
                        string json = FileLists.GetFileList(virtualDirectory, physicalDirectory, startAt, maxSize);
                        return(new CodeResult(MessageType.Success, json));
                    }

                    // Print standard G-code response
                    Compatibility compatibility;
                    using (await Model.Provider.AccessReadOnlyAsync())
                    {
                        compatibility = Model.Provider.Get.Inputs[code.Channel].Compatibility;
                    }

                    StringBuilder result = new StringBuilder();
                    if (compatibility == Compatibility.Default || compatibility == Compatibility.RepRapFirmware)
                    {
                        result.AppendLine("GCode files:");
                    }
                    else if (compatibility == Compatibility.Marlin || compatibility == Compatibility.NanoDLP)
                    {
                        result.AppendLine("Begin file list:");
                    }

                    int  numItems  = 0;
                    bool itemFound = false;
                    foreach (string file in Directory.EnumerateFileSystemEntries(physicalDirectory))
                    {
                        if (numItems++ >= startAt)
                        {
                            string filename = Path.GetFileName(file);
                            if (compatibility == Compatibility.Marlin || compatibility == Compatibility.NanoDLP)
                            {
                                result.AppendLine(filename);
                            }
                            else
                            {
                                if (itemFound)
                                {
                                    result.Append(',');
                                }
                                result.Append($"\"{filename}\"");
                            }
                            itemFound = true;
                        }
                    }

                    if (compatibility == Compatibility.Marlin || compatibility == Compatibility.NanoDLP)
                    {
                        if (!itemFound)
                        {
                            result.AppendLine("NONE");
                        }
                        result.Append("End file list");
                    }

                    return(new CodeResult(MessageType.Success, result.ToString()));
                }
                throw new OperationCanceledException();

            // Initialize SD card
            case 21:
                throw new NotSupportedException();

            // Release SD card
            case 22:
                throw new NotSupportedException();

            // Select a file to print
            case 23:
            case 32:
                if (await SPI.Interface.Flush(code))
                {
                    string file = code.GetUnprecedentedString();
                    if (string.IsNullOrWhiteSpace(file))
                    {
                        return(new CodeResult(MessageType.Error, "Filename expected"));
                    }

                    string physicalFile = await FilePath.ToPhysicalAsync(file, FileDirectory.GCodes);

                    if (!File.Exists(physicalFile))
                    {
                        return(new CodeResult(MessageType.Error, $"Could not find file {file}"));
                    }

                    using (await FileExecution.Job.LockAsync())
                    {
                        if (code.Channel != CodeChannel.File && FileExecution.Job.IsProcessing)
                        {
                            return(new CodeResult(MessageType.Error, "Cannot set file to print, because a file is already being printed"));
                        }
                        await FileExecution.Job.SelectFile(physicalFile);
                    }

                    if (await code.EmulatingMarlin())
                    {
                        return(new CodeResult(MessageType.Success, "File opened\nFile selected"));
                    }
                    return(new CodeResult(MessageType.Success, $"File {file} selected for printing"));
                }
                throw new OperationCanceledException();


            // Resume a file print
            case 24:
                if (await SPI.Interface.Flush(code))
                {
                    using (await FileExecution.Job.LockAsync())
                    {
                        if (!FileExecution.Job.IsFileSelected)
                        {
                            return(new CodeResult(MessageType.Error, "Cannot print, because no file is selected!"));
                        }
                    }

                    // Let RepRapFirmware process this request so it can invoke resume.g. When M24 completes, the file is resumed
                    break;
                }
                throw new OperationCanceledException();

            // Set SD position
            case 26:
                if (await SPI.Interface.Flush(code))
                {
                    using (await FileExecution.Job.LockAsync())
                    {
                        if (!FileExecution.Job.IsFileSelected)
                        {
                            return(new CodeResult(MessageType.Error, "Not printing a file"));
                        }

                        CodeParameter sParam = code.Parameter('S');
                        if (sParam != null)
                        {
                            if (sParam < 0L || sParam > FileExecution.Job.FileLength)
                            {
                                return(new CodeResult(MessageType.Error, "Position is out of range"));
                            }
                            await FileExecution.Job.SetFilePosition(sParam);
                        }
                    }

                    // P is not supported yet

                    return(new CodeResult());
                }
                throw new OperationCanceledException();

            // Report SD print status
            case 27:
                if (await SPI.Interface.Flush(code))
                {
                    using (await FileExecution.Job.LockAsync())
                    {
                        if (FileExecution.Job.IsFileSelected)
                        {
                            long filePosition = await FileExecution.Job.GetFilePosition();

                            return(new CodeResult(MessageType.Success, $"SD printing byte {filePosition}/{FileExecution.Job.FileLength}"));
                        }
                        return(new CodeResult(MessageType.Success, "Not SD printing."));
                    }
                }
                throw new OperationCanceledException();

            // Begin write to SD card
            case 28:
                if (await SPI.Interface.Flush(code))
                {
                    int numChannel = (int)code.Channel;
                    using (await Commands.Code.FileLocks[numChannel].LockAsync(code.CancellationToken))
                    {
                        if (Commands.Code.FilesBeingWritten[numChannel] != null)
                        {
                            return(new CodeResult(MessageType.Error, "Another file is already being written to"));
                        }

                        string file = code.GetUnprecedentedString();
                        if (string.IsNullOrWhiteSpace(file))
                        {
                            return(new CodeResult(MessageType.Error, "Filename expected"));
                        }

                        string prefix       = (await code.EmulatingMarlin()) ? "ok\n" : string.Empty;
                        string physicalFile = await FilePath.ToPhysicalAsync(file, FileDirectory.GCodes);

                        try
                        {
                            FileStream   fileStream = new FileStream(physicalFile, FileMode.Create, FileAccess.Write);
                            StreamWriter writer     = new StreamWriter(fileStream);
                            Commands.Code.FilesBeingWritten[numChannel] = writer;
                            return(new CodeResult(MessageType.Success, prefix + $"Writing to file: {file}"));
                        }
                        catch (Exception e)
                        {
                            _logger.Debug(e, "Failed to open file for writing");
                            return(new CodeResult(MessageType.Error, prefix + $"Can't open file {file} for writing."));
                        }
                    }
                }
                throw new OperationCanceledException();

            // End write to SD card
            case 29:
                if (await SPI.Interface.Flush(code))
                {
                    int numChannel = (int)code.Channel;
                    using (await Commands.Code.FileLocks[numChannel].LockAsync(code.CancellationToken))
                    {
                        if (Commands.Code.FilesBeingWritten[numChannel] != null)
                        {
                            Stream stream = Commands.Code.FilesBeingWritten[numChannel].BaseStream;
                            Commands.Code.FilesBeingWritten[numChannel].Dispose();
                            Commands.Code.FilesBeingWritten[numChannel] = null;
                            stream.Dispose();

                            if (await code.EmulatingMarlin())
                            {
                                return(new CodeResult(MessageType.Success, "Done saving file."));
                            }
                            return(new CodeResult());
                        }
                        break;
                    }
                }
                throw new OperationCanceledException();

            // Delete a file on the SD card
            case 30:
                if (await SPI.Interface.Flush(code))
                {
                    string file         = code.GetUnprecedentedString();
                    string physicalFile = await FilePath.ToPhysicalAsync(file);

                    try
                    {
                        File.Delete(physicalFile);
                    }
                    catch (Exception e)
                    {
                        _logger.Debug(e, "Failed to delete file");
                        return(new CodeResult(MessageType.Error, $"Failed to delete file {file}: {e.Message}"));
                    }
                }
                throw new OperationCanceledException();

            // For case 32, see case 23

            // Return file information
            case 36:
                if (code.Parameters.Count > 0)
                {
                    if (await SPI.Interface.Flush(code))
                    {
                        string file = await FilePath.ToPhysicalAsync(code.GetUnprecedentedString(), FileDirectory.GCodes);

                        try
                        {
                            ParsedFileInfo info = await InfoParser.Parse(file);

                            string json = JsonSerializer.Serialize(info, JsonHelper.DefaultJsonOptions);
                            return(new CodeResult(MessageType.Success, "{\"err\":0," + json.Substring(1)));
                        }
                        catch (Exception e)
                        {
                            _logger.Debug(e, "Failed to return file information");
                            return(new CodeResult(MessageType.Success, "{\"err\":1}"));
                        }
                    }
                    throw new OperationCanceledException();
                }
                break;

            // Simulate file
            case 37:
                if (await SPI.Interface.Flush(code))
                {
                    CodeParameter pParam = code.Parameter('P');
                    if (pParam != null)
                    {
                        string file = pParam;
                        if (string.IsNullOrWhiteSpace(file))
                        {
                            return(new CodeResult(MessageType.Error, "Filename expected"));
                        }

                        string physicalFile = await FilePath.ToPhysicalAsync(file, FileDirectory.GCodes);

                        if (!File.Exists(physicalFile))
                        {
                            return(new CodeResult(MessageType.Error, $"GCode file \"{file}\" not found\n"));
                        }

                        using (await FileExecution.Job.LockAsync())
                        {
                            if (code.Channel != CodeChannel.File && FileExecution.Job.IsProcessing)
                            {
                                return(new CodeResult(MessageType.Error, "Cannot set file to simulate, because a file is already being printed"));
                            }

                            await FileExecution.Job.SelectFile(physicalFile, true);

                            // Simulation is started when M37 has been processed by the firmware
                        }
                    }
                    break;
                }
                throw new OperationCanceledException();

            // Compute SHA1 hash of target file
            case 38:
                if (await SPI.Interface.Flush(code))
                {
                    string file         = code.GetUnprecedentedString();
                    string physicalFile = await FilePath.ToPhysicalAsync(file);

                    try
                    {
                        using FileStream stream = new FileStream(file, FileMode.Open, FileAccess.Read);

                        byte[] hash;
                        using System.Security.Cryptography.SHA1 sha1 = System.Security.Cryptography.SHA1.Create();
                        hash = await Task.Run(() => sha1.ComputeHash(stream), code.CancellationToken);

                        return(new CodeResult(MessageType.Success, BitConverter.ToString(hash).Replace("-", string.Empty)));
                    }
                    catch (Exception e)
                    {
                        _logger.Debug(e, "Failed to compute SHA1 checksum");
                        if (e is AggregateException ae)
                        {
                            e = ae.InnerException;
                        }
                        return(new CodeResult(MessageType.Error, $"Could not compute SHA1 checksum for file {file}: {e.Message}"));
                    }
                }
                throw new OperationCanceledException();

            // Report SD card information
            case 39:
                if (await SPI.Interface.Flush(code))
                {
                    using (await Model.Provider.AccessReadOnlyAsync())
                    {
                        int index = code.Parameter('P', 0);
                        if (code.Parameter('S', 0) == 2)
                        {
                            if (index < 0 || index >= Model.Provider.Get.Volumes.Count)
                            {
                                return(new CodeResult(MessageType.Success, $"{{\"SDinfo\":{{\"slot\":{index},present:0}}}}"));
                            }

                            Volume storage = Model.Provider.Get.Volumes[index];
                            var    output  = new
                            {
                                SDinfo = new
                                {
                                    slot     = index,
                                    present  = 1,
                                    capacity = storage.Capacity,
                                    free     = storage.FreeSpace,
                                    speed    = storage.Speed
                                }
                            };
                            return(new CodeResult(MessageType.Success, JsonSerializer.Serialize(output, JsonHelper.DefaultJsonOptions)));
                        }
                        else
                        {
                            if (index < 0 || index >= Model.Provider.Get.Volumes.Count)
                            {
                                return(new CodeResult(MessageType.Error, $"Bad SD slot number: {index}"));
                            }

                            Volume storage = Model.Provider.Get.Volumes[index];
                            return(new CodeResult(MessageType.Success, $"SD card in slot {index}: capacity {storage.Capacity / (1000 * 1000 * 1000):F2}Gb, free space {storage.FreeSpace / (1000 * 1000 * 1000):F2}Gb, speed {storage.Speed / (1000 * 1000):F2}MBytes/sec"));
                        }
                    }
                }
                throw new OperationCanceledException();

            // Emergency Stop - unconditional and interpreteted immediately when read
            case 112:
                await SPI.Interface.EmergencyStop();

                using (await Model.Provider.AccessReadWriteAsync())
                {
                    Model.Provider.Get.State.Status = MachineStatus.Halted;
                }
                return(new CodeResult());

            // Immediate DSF diagnostics
            case 122:
                if (code.Parameter('B', 0) == 0 && code.GetUnprecedentedString() == "DSF")
                {
                    CodeResult result = new CodeResult();
                    await Diagnostics(result);

                    return(result);
                }
                break;

            // Save heightmap
            case 374:
                if (await SPI.Interface.Flush(code))
                {
                    string file         = code.Parameter('P', FilePath.DefaultHeightmapFile);
                    string physicalFile = await FilePath.ToPhysicalAsync(file, FileDirectory.System);

                    try
                    {
                        if (await SPI.Interface.LockMovementAndWaitForStandstill(code.Channel))
                        {
                            Heightmap map;
                            try
                            {
                                map = await SPI.Interface.GetHeightmap();
                            }
                            finally
                            {
                                await SPI.Interface.UnlockAll(code.Channel);
                            }

                            if (map.NumX * map.NumY > 0)
                            {
                                await map.Save(physicalFile);

                                string virtualFile = await FilePath.ToVirtualAsync(physicalFile);

                                using (await Model.Provider.AccessReadWriteAsync())
                                {
                                    Model.Provider.Get.Move.Compensation.File = virtualFile;
                                }
                                return(new CodeResult(MessageType.Success, $"Height map saved to file {file}"));
                            }
                            return(new CodeResult());
                        }
                    }
                    catch (Exception e)
                    {
                        _logger.Debug(e, "Failed to save height map");
                        if (e is AggregateException ae)
                        {
                            e = ae.InnerException;
                        }
                        return(new CodeResult(MessageType.Error, $"Failed to save height map to file {file}: {e.Message}"));
                    }
                }
                throw new OperationCanceledException();

            // Load heightmap
            case 375:
                if (await SPI.Interface.Flush(code))
                {
                    string file         = code.Parameter('P', FilePath.DefaultHeightmapFile);
                    string physicalFile = await FilePath.ToPhysicalAsync(file, FileDirectory.System);

                    try
                    {
                        Heightmap map = new Heightmap();
                        await map.Load(physicalFile);

                        if (await SPI.Interface.LockMovementAndWaitForStandstill(code.Channel))
                        {
                            try
                            {
                                await SPI.Interface.SetHeightmap(map);
                            }
                            finally
                            {
                                await SPI.Interface.UnlockAll(code.Channel);
                            }

                            string virtualFile = await FilePath.ToVirtualAsync(physicalFile);

                            using (await Model.Provider.AccessReadWriteAsync())
                            {
                                Model.Provider.Get.Move.Compensation.File = virtualFile;
                            }

                            CodeResult result = new CodeResult();
                            using (await Model.Provider.AccessReadOnlyAsync())
                            {
                                if (Model.Provider.Get.Move.Axes.Any(axis => axis.Letter == 'Z' && !axis.Homed))
                                {
                                    result.Add(MessageType.Warning, "The height map was loaded when the current Z=0 datum was not determined. This may result in a height offset.");
                                }
                            }
                            result.Add(MessageType.Success, $"Height map loaded from file {file}");
                            return(result);
                        }
                    }
                    catch (Exception e)
                    {
                        _logger.Debug(e, "Failed to load height map");
                        if (e is AggregateException ae)
                        {
                            e = ae.InnerException;
                        }
                        return(new CodeResult(MessageType.Error, $"Failed to load height map from file {file}: {e.Message}"));
                    }
                }
                throw new OperationCanceledException();

            // Create Directory on SD-Card
            case 470:
                if (await SPI.Interface.Flush(code))
                {
                    string path = code.Parameter('P');
                    if (path == null)
                    {
                        return(new CodeResult(MessageType.Error, "Missing directory name"));
                    }
                    string physicalPath = await FilePath.ToPhysicalAsync(path);

                    try
                    {
                        Directory.CreateDirectory(physicalPath);
                    }
                    catch (Exception e)
                    {
                        _logger.Debug(e, "Failed to create directory");
                        return(new CodeResult(MessageType.Error, $"Failed to create directory {path}: {e.Message}"));
                    }
                }
                throw new OperationCanceledException();

            // Rename File/Directory on SD-Card
            case 471:
                if (await SPI.Interface.Flush(code))
                {
                    string from = code.Parameter('S');
                    string to   = code.Parameter('T');

                    try
                    {
                        string source = await FilePath.ToPhysicalAsync(from);

                        string destination = await FilePath.ToPhysicalAsync(to);

                        if (File.Exists(source))
                        {
                            if (File.Exists(destination) && code.Parameter('D', false))
                            {
                                File.Delete(destination);
                            }
                            File.Move(source, destination);
                        }
                        else if (Directory.Exists(source))
                        {
                            if (Directory.Exists(destination) && code.Parameter('D', false))
                            {
                                // This could be recursive but at the moment we mimic RRF's behaviour
                                Directory.Delete(destination);
                            }
                            Directory.Move(source, destination);
                        }
                        throw new FileNotFoundException();
                    }
                    catch (Exception e)
                    {
                        _logger.Debug(e, "Failed to rename file or directory");
                        return(new CodeResult(MessageType.Error, $"Failed to rename file or directory {from} to {to}: {e.Message}"));
                    }
                }
                throw new OperationCanceledException();

            // Store parameters
            case 500:
                if (await SPI.Interface.Flush(code))
                {
                    await ConfigOverride.Save(code);

                    return(new CodeResult());
                }
                throw new OperationCanceledException();

            // Print settings
            case 503:
                if (await SPI.Interface.Flush(code))
                {
                    string configFile = await FilePath.ToPhysicalAsync(FilePath.ConfigFile, FileDirectory.System);

                    if (File.Exists(configFile))
                    {
                        string content = await File.ReadAllTextAsync(configFile);

                        return(new CodeResult(MessageType.Success, content));
                    }

                    string configFileFallback = await FilePath.ToPhysicalAsync(FilePath.ConfigFileFallback, FileDirectory.System);

                    if (File.Exists(configFileFallback))
                    {
                        string content = await File.ReadAllTextAsync(configFileFallback);

                        return(new CodeResult(MessageType.Success, content));
                    }
                    return(new CodeResult(MessageType.Error, "Configuration file not found"));
                }
                throw new OperationCanceledException();

            // Set configuration file folder
            case 505:
                if (await SPI.Interface.Flush(code))
                {
                    string directory = code.Parameter('P');
                    if (!string.IsNullOrEmpty(directory))
                    {
                        string physicalDirectory = await FilePath.ToPhysicalAsync(directory, "sys");

                        if (Directory.Exists(physicalDirectory))
                        {
                            string virtualDirectory = await FilePath.ToVirtualAsync(physicalDirectory);

                            using (await Model.Provider.AccessReadWriteAsync())
                            {
                                Model.Provider.Get.Directories.System = virtualDirectory;
                            }
                            return(new CodeResult());
                        }
                        return(new CodeResult(MessageType.Error, "Directory not found"));
                    }

                    using (await Model.Provider.AccessReadOnlyAsync())
                    {
                        return(new CodeResult(MessageType.Success, $"Sys file path is {Model.Provider.Get.Directories.System}"));
                    }
                }
                throw new OperationCanceledException();

            // Set Name
            case 550:
                if (await SPI.Interface.Flush(code))
                {
                    // Verify the P parameter
                    string pParam = code.Parameter('P');
                    if (!string.IsNullOrEmpty(pParam))
                    {
                        if (pParam.Length > 40)
                        {
                            return(new CodeResult(MessageType.Error, "Machine name is too long"));
                        }

                        // Strip letters and digits from the machine name
                        string machineName = string.Empty;
                        foreach (char c in Environment.MachineName)
                        {
                            if (char.IsLetterOrDigit(c))
                            {
                                machineName += c;
                            }
                        }

                        // Strip letters and digits from the desired name
                        string desiredName = string.Empty;
                        foreach (char c in pParam)
                        {
                            if (char.IsLetterOrDigit(c))
                            {
                                desiredName += c;
                            }
                        }

                        // Make sure the subset of letters and digits is equal
                        if (!machineName.Equals(desiredName, StringComparison.CurrentCultureIgnoreCase))
                        {
                            return(new CodeResult(MessageType.Error, "Machine name must consist of the same letters and digits as configured by the Linux hostname"));
                        }

                        // Hostname is legit - pretend we didn't see this code so RRF can interpret it
                    }
                    break;
                }
                throw new OperationCanceledException();

            // Configure filament
            case 703:
                if (await SPI.Interface.Flush(code))
                {
                    await Model.Updater.WaitForFullUpdate(Program.CancellationToken);

                    break;
                }
                throw new OperationCanceledException();

            // Set current RTC date and time
            case 905:
                if (await SPI.Interface.Flush(code))
                {
                    bool seen = false;

                    CodeParameter pParam = code.Parameter('P');
                    if (pParam != null)
                    {
                        if (DateTime.TryParseExact(pParam, "yyyy-MM-dd", CultureInfo.InvariantCulture, DateTimeStyles.None, out DateTime date))
                        {
                            System.Diagnostics.Process.Start("timedatectl", $"set-time {date:yyyy-MM-dd}").WaitForExit();
                            seen = true;
                        }
                        else
                        {
                            return(new CodeResult(MessageType.Error, "Invalid date format"));
                        }
                    }

                    CodeParameter sParam = code.Parameter('S');
                    if (sParam != null)
                    {
                        if (DateTime.TryParseExact(sParam, "HH:mm:ss", CultureInfo.InvariantCulture, DateTimeStyles.None, out DateTime time))
                        {
                            System.Diagnostics.Process.Start("timedatectl", $"set-time {time:HH:mm:ss}").WaitForExit();
                            seen = true;
                        }
                        else
                        {
                            return(new CodeResult(MessageType.Error, "Invalid time format"));
                        }
                    }

                    if (!seen)
                    {
                        return(new CodeResult(MessageType.Success, $"Current date and time: {DateTime.Now:yyyy-MM-dd HH:mm:ss}"));
                    }
                }
                throw new OperationCanceledException();

            // Start/stop event logging to SD card
            case 929:
                if (await SPI.Interface.Flush(code))
                {
                    CodeParameter sParam = code.Parameter('S');
                    if (sParam == null)
                    {
                        using (await Model.Provider.AccessReadOnlyAsync())
                        {
                            return(new CodeResult(MessageType.Success, $"Event logging is {(Model.Provider.Get.State.LogFile != null ? "enabled" : "disabled")}"));
                        }
                    }

                    if (sParam > 0)
                    {
                        string file = code.Parameter('P', Utility.Logger.DefaultLogFile);
                        if (string.IsNullOrWhiteSpace(file))
                        {
                            return(new CodeResult(MessageType.Error, "Missing filename in M929 command"));
                        }

                        string physicalFile = await FilePath.ToPhysicalAsync(file, FileDirectory.System);

                        await Utility.Logger.Start(physicalFile);
                    }
                    else
                    {
                        await Utility.Logger.Stop();
                    }

                    return(new CodeResult());
                }
                throw new OperationCanceledException();

            // Update the firmware
            case 997:
                if (((int[])code.Parameter('S', new int[] { 0 })).Contains(0) && code.Parameter('B', 0) == 0)
                {
                    if (await SPI.Interface.Flush(code))
                    {
                        string iapFile, firmwareFile;
                        using (await Model.Provider.AccessReadOnlyAsync())
                        {
                            if (Model.Provider.Get.Boards.Count == 0)
                            {
                                return(new CodeResult(MessageType.Error, "No boards have been detected"));
                            }

                            // There are now two different IAP binaries, check which one to use
                            iapFile      = Model.Provider.Get.Boards[0].IapFileNameSBC;
                            firmwareFile = Model.Provider.Get.Boards[0].FirmwareFileName;
                        }

                        iapFile = await FilePath.ToPhysicalAsync(iapFile, FileDirectory.Firmware);

                        if (!File.Exists(iapFile))
                        {
                            return(new CodeResult(MessageType.Error, $"Failed to find IAP file {iapFile}"));
                        }

                        firmwareFile = await FilePath.ToPhysicalAsync(firmwareFile, FileDirectory.Firmware);

                        if (!File.Exists(firmwareFile))
                        {
                            return(new CodeResult(MessageType.Error, $"Failed to find firmware file {firmwareFile}"));
                        }

                        using FileStream iapStream      = new FileStream(iapFile, FileMode.Open, FileAccess.Read);
                        using FileStream firmwareStream = new FileStream(firmwareFile, FileMode.Open, FileAccess.Read);
                        await SPI.Interface.UpdateFirmware(iapStream, firmwareStream);

                        return(new CodeResult());
                    }
                    throw new OperationCanceledException();
                }
                break;

            // Request resend of line
            case 998:
                throw new NotSupportedException();

            // Reset controller - unconditional and interpreteted immediately when read
            case 999:
                if (code.Parameters.Count == 0)
                {
                    await SPI.Interface.Reset();

                    return(new CodeResult());
                }
                break;
            }
            return(null);
        }
示例#7
0
        /// <summary>
        /// Process an M-code that should be interpreted by the control server
        /// </summary>
        /// <param name="code">Code to process</param>
        /// <returns>Result of the code if the code completed, else null</returns>
        public static async Task <CodeResult> Process(Commands.Code code)
        {
            if (code.Channel == CodeChannel.File && FileExecution.Job.IsSimulating)
            {
                // Ignore M-codes from files in simulation mode...
                return(null);
            }

            switch (code.MajorNumber)
            {
            // Stop or Unconditional stop
            // Sleep or Conditional stop
            case 0:
            case 1:
                if (await SPI.Interface.Flush(code))
                {
                    using (await FileExecution.Job.LockAsync())
                    {
                        if (FileExecution.Job.IsFileSelected)
                        {
                            // M0/M1 may be used in a print file to terminate it
                            if (code.Channel != CodeChannel.File && !FileExecution.Job.IsPaused)
                            {
                                return(new CodeResult(MessageType.Error, "Pause the print before attempting to cancel it"));
                            }
                        }
                    }
                    break;
                }
                throw new OperationCanceledException();

            // List SD card
            case 20:
                if (await SPI.Interface.Flush(code))
                {
                    // Resolve the directory
                    string virtualDirectory = code.Parameter('P');
                    if (virtualDirectory == null)
                    {
                        using (await Model.Provider.AccessReadOnlyAsync())
                        {
                            virtualDirectory = Model.Provider.Get.Directories.GCodes;
                        }
                    }
                    string physicalDirectory = await FilePath.ToPhysicalAsync(virtualDirectory);

                    // Make sure to stay within limits if it is a request from the firmware
                    int maxSize = -1;
                    if (code.Flags.HasFlag(CodeFlags.IsFromFirmware))
                    {
                        maxSize = Settings.MaxMessageLength;
                    }

                    // Check if JSON file lists were requested
                    int           startAt = Math.Max(code.Parameter('R') ?? 0, 0);
                    CodeParameter sParam  = code.Parameter('S', 0);
                    if (sParam == 2)
                    {
                        string json = FileLists.GetFiles(virtualDirectory, physicalDirectory, startAt, true, maxSize);
                        return(new CodeResult(MessageType.Success, json));
                    }
                    if (sParam == 3)
                    {
                        string json = FileLists.GetFileList(virtualDirectory, physicalDirectory, startAt, maxSize);
                        return(new CodeResult(MessageType.Success, json));
                    }

                    // Print standard G-code response
                    Compatibility compatibility;
                    using (await Model.Provider.AccessReadOnlyAsync())
                    {
                        compatibility = Model.Provider.Get.Inputs[code.Channel].Compatibility;
                    }

                    StringBuilder result = new StringBuilder();
                    if (compatibility == Compatibility.Default || compatibility == Compatibility.RepRapFirmware)
                    {
                        result.AppendLine("GCode files:");
                    }
                    else if (compatibility == Compatibility.Marlin || compatibility == Compatibility.NanoDLP)
                    {
                        result.AppendLine("Begin file list:");
                    }

                    int  numItems  = 0;
                    bool itemFound = false;
                    foreach (string file in Directory.EnumerateFileSystemEntries(physicalDirectory))
                    {
                        if (numItems++ >= startAt)
                        {
                            string filename = Path.GetFileName(file);
                            if (compatibility == Compatibility.Marlin || compatibility == Compatibility.NanoDLP)
                            {
                                result.AppendLine(filename);
                            }
                            else
                            {
                                if (itemFound)
                                {
                                    result.Append(',');
                                }
                                result.Append($"\"{filename}\"");
                            }
                            itemFound = true;
                        }
                    }

                    if (compatibility == Compatibility.Marlin || compatibility == Compatibility.NanoDLP)
                    {
                        if (!itemFound)
                        {
                            result.AppendLine("NONE");
                        }
                        result.Append("End file list");
                    }

                    return(new CodeResult(MessageType.Success, result.ToString()));
                }
                throw new OperationCanceledException();

            // Initialize SD card
            case 21:
                if (await SPI.Interface.Flush(code))
                {
                    if (code.Parameter('P', 0) == 0)
                    {
                        // M21 (P0) will always work because it's always mounted
                        return(new CodeResult());
                    }
                    throw new NotSupportedException();
                }
                throw new OperationCanceledException();

            // Release SD card
            case 22:
                throw new NotSupportedException();

            // Select a file to print
            case 23:
            case 32:
                if (await SPI.Interface.Flush(code))
                {
                    string file = code.GetUnprecedentedString();
                    if (string.IsNullOrWhiteSpace(file))
                    {
                        return(new CodeResult(MessageType.Error, "Filename expected"));
                    }

                    string physicalFile = await FilePath.ToPhysicalAsync(file, FileDirectory.GCodes);

                    if (!File.Exists(physicalFile))
                    {
                        return(new CodeResult(MessageType.Error, $"Could not find file {file}"));
                    }

                    using (await FileExecution.Job.LockAsync())
                    {
                        if (code.Channel != CodeChannel.File && FileExecution.Job.IsProcessing)
                        {
                            return(new CodeResult(MessageType.Error, "Cannot set file to print, because a file is already being printed"));
                        }
                        await FileExecution.Job.SelectFile(physicalFile);
                    }

                    if (await code.EmulatingMarlin())
                    {
                        return(new CodeResult(MessageType.Success, "File opened\nFile selected"));
                    }
                    return(new CodeResult(MessageType.Success, $"File {file} selected for printing"));
                }
                throw new OperationCanceledException();


            // Resume a file print
            case 24:
                if (await SPI.Interface.Flush(code))
                {
                    using (await FileExecution.Job.LockAsync())
                    {
                        if (!FileExecution.Job.IsFileSelected)
                        {
                            return(new CodeResult(MessageType.Error, "Cannot print, because no file is selected!"));
                        }
                    }

                    // Let RepRapFirmware process this request so it can invoke resume.g. When M24 completes, the file is resumed
                    break;
                }
                throw new OperationCanceledException();

            // Set SD position
            case 26:
                if (await SPI.Interface.Flush(code))
                {
                    using (await FileExecution.Job.LockAsync())
                    {
                        if (!FileExecution.Job.IsFileSelected)
                        {
                            return(new CodeResult(MessageType.Error, "Not printing a file"));
                        }

                        CodeParameter sParam = code.Parameter('S');
                        if (sParam != null)
                        {
                            if (sParam < 0L || sParam > FileExecution.Job.FileLength)
                            {
                                return(new CodeResult(MessageType.Error, "Position is out of range"));
                            }
                            await FileExecution.Job.SetFilePosition(sParam);
                        }
                    }

                    // P is not supported yet

                    return(new CodeResult());
                }
                throw new OperationCanceledException();

            // Report SD print status
            case 27:
                if (await SPI.Interface.Flush(code))
                {
                    using (await FileExecution.Job.LockAsync())
                    {
                        if (FileExecution.Job.IsFileSelected)
                        {
                            long filePosition = await FileExecution.Job.GetFilePosition();

                            return(new CodeResult(MessageType.Success, $"SD printing byte {filePosition}/{FileExecution.Job.FileLength}"));
                        }
                        return(new CodeResult(MessageType.Success, "Not SD printing."));
                    }
                }
                throw new OperationCanceledException();

            // Begin write to SD card
            case 28:
                if (await SPI.Interface.Flush(code))
                {
                    int numChannel = (int)code.Channel;
                    using (await Commands.Code.FileLocks[numChannel].LockAsync(Program.CancellationToken))
                    {
                        if (Commands.Code.FilesBeingWritten[numChannel] != null)
                        {
                            return(new CodeResult(MessageType.Error, "Another file is already being written to"));
                        }

                        string file = code.GetUnprecedentedString();
                        if (string.IsNullOrWhiteSpace(file))
                        {
                            return(new CodeResult(MessageType.Error, "Filename expected"));
                        }

                        string prefix       = (await code.EmulatingMarlin()) ? "ok\n" : string.Empty;
                        string physicalFile = await FilePath.ToPhysicalAsync(file, FileDirectory.GCodes);

                        try
                        {
                            FileStream   fileStream = new FileStream(physicalFile, FileMode.Create, FileAccess.Write);
                            StreamWriter writer     = new StreamWriter(fileStream);
                            Commands.Code.FilesBeingWritten[numChannel] = writer;
                            return(new CodeResult(MessageType.Success, prefix + $"Writing to file: {file}"));
                        }
                        catch (Exception e)
                        {
                            _logger.Debug(e, "Failed to open file for writing");
                            return(new CodeResult(MessageType.Error, prefix + $"Can't open file {file} for writing."));
                        }
                    }
                }
                throw new OperationCanceledException();

            // End write to SD card
            case 29:
                if (await SPI.Interface.Flush(code))
                {
                    int numChannel = (int)code.Channel;
                    using (await Commands.Code.FileLocks[numChannel].LockAsync(Program.CancellationToken))
                    {
                        if (Commands.Code.FilesBeingWritten[numChannel] != null)
                        {
                            Stream stream = Commands.Code.FilesBeingWritten[numChannel].BaseStream;
                            Commands.Code.FilesBeingWritten[numChannel].Dispose();
                            Commands.Code.FilesBeingWritten[numChannel] = null;
                            stream.Dispose();

                            if (await code.EmulatingMarlin())
                            {
                                return(new CodeResult(MessageType.Success, "Done saving file."));
                            }
                            return(new CodeResult());
                        }
                        break;
                    }
                }
                throw new OperationCanceledException();

            // Delete a file on the SD card
            case 30:
                if (await SPI.Interface.Flush(code))
                {
                    string file         = code.GetUnprecedentedString();
                    string physicalFile = await FilePath.ToPhysicalAsync(file);

                    try
                    {
                        File.Delete(physicalFile);
                    }
                    catch (Exception e)
                    {
                        _logger.Debug(e, "Failed to delete file");
                        return(new CodeResult(MessageType.Error, $"Failed to delete file {file}: {e.Message}"));
                    }
                }
                throw new OperationCanceledException();

            // For case 32, see case 23

            // Return file information
            case 36:
                if (code.Parameters.Count > 0)
                {
                    if (await SPI.Interface.Flush(code))
                    {
                        string file = await FilePath.ToPhysicalAsync(code.GetUnprecedentedString(), FileDirectory.GCodes);

                        try
                        {
                            ParsedFileInfo info = await InfoParser.Parse(file);

                            string json = JsonSerializer.Serialize(info, JsonHelper.DefaultJsonOptions);
                            return(new CodeResult(MessageType.Success, "{\"err\":0," + json[1..]));
        static async Task Main()
        {
            //Directory.SetCurrentDirectory(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location) ?? throw new InvalidOperationException());

            Log.Logger = new LoggerConfiguration()
                         .WriteTo.Console()
                         .Enrich.FromLogContext()
                         .MinimumLevel.Information()
                         .CreateLogger();
            var c = await JsonReader.ReadConfigAsync();

            foreach (var cfg in c)
            {
                var parser = new InfoParser(cfg.Configuration, cfg.CustomConfigurations);

                if (cfg.Configuration != null)
                {
                    var dict = await JsonReader.ReadIntroAsync(cfg.Configuration.Version, cfg.Version);

                    var pending = new List <string>();
                    var root    = Directory.CreateDirectory(
                        $"{Directory.GetCurrentDirectory()}\\projects\\{cfg.Version}\\assets");

                    var names = root.GetDirectories().Select(_ => _.Name).ToList();

                    if (cfg.CustomConfigurations != null)
                    {
                        foreach (var configuration in cfg.CustomConfigurations)
                        {
                            if (!names.Contains(configuration.ProjectName))
                            {
                                names.Add(configuration.ProjectName);
                            }
                        }
                    }

                    if (cfg.Count != null)
                    {
                        var allM = await UrlLib.GetModInfoAsync(cfg.Count.Value, cfg.Configuration.Version);


                        if (names.Count > cfg.Count)
                        {
                            var bin = allM.Where(_ => !names.Contains(_.Slug));
                            var l   = allM.ToList();
                            foreach (var info in bin)
                            {
                                l.Remove(info);
                            }

                            allM = l.ToArray();
                        }
                        var allN = allM.ToList().Select(_ => _.Slug).Distinct().ToList();
                        var l1   = parser.SerializeAll(allM).Distinct().ToList();

                        //var parallelOption = new ParallelOptions {
                        //    MaxDegreeOfParallelism = 16
                        //};

                        foreach (var str in names)
                        {
                            if (!allN.Contains(str))
                            {
                                pending.Add(str);
                            }
                        }

                        Log.Logger.Information($"该版本[assets]文件夹下含有 {names.Count} 个mod,有 {pending.Count} 要单独处理");
                        var semaphore = new SemaphoreSlim(16, 16);
                        //Parallel.ForEach(l1, parallelOption, (async tuple => {
                        //    try {
                        //        semaphore.WaitOne();
                        //        await Utils.ParseModsAsync(tuple, cfg);
                        //    }
                        //    catch (Exception e) {
                        //        Log.Logger.Error(e.Message);
                        //    }
                        //    finally {
                        //        semaphore.Release();
                        //    }
                        //}));

                        var tasks = l1.Select(async _ =>
                        {
                            try
                            {
                                await semaphore.WaitAsync();
                                await Utils.ParseModsAsync(_, cfg);
                            }
                            catch (Exception e)
                            {
                                Log.Logger.Error(e.Message);
                            }
                            finally
                            {
                                semaphore.Release();
                            }
                        });

                        await Task.WhenAll(tasks);
                    }


                    foreach (var name in pending)
                    {
                        if (dict.ContainsKey(name))
                        {
                            var m = await UrlLib.GetModInfoAsync(dict[name]);

                            var i = parser.Serialize(m);
                            try
                            {
                                var task = new Task(async() =>
                                {
                                    try
                                    {
                                        await Utils.ParseModsAsync(i, cfg);
                                    }
                                    catch (Exception e)
                                    {
                                        Log.Logger.Error(e.Message);
                                    }
                                });
                                task.Start();
                                //await Utils.ParseModsAsync(i,cfg);
                            }
                            catch (Exception e)
                            {
                                Log.Logger.Error(e.Message);
                            }
                            Thread.Sleep(5000);
                        }
                    }
                }

                //var semaphore = new Semaphore(32, 40);
                //foreach (var l in l1) {
                //    try {
                //        semaphore.WaitOne();
                //        await Utils.ParseModsAsync(l,cfg);
                //    }
                //    catch (Exception e) {
                //        Log.Logger.Error(e.Message);
                //    }
                //    finally {
                //        semaphore.Release();
                //    }
                //}
            }
        }