public static void WriteFDS(FamicomDumperConnection dumper, string fileName, bool needCheck = false) { if (dumper.ProtocolVersion < 3) { throw new NotSupportedException("Dumper firmware version is too old, update it to read/write FDS cards"); } var oldTimeout = dumper.Timeout; try { dumper.Timeout = 30000; CheckRAMAdapter(dumper); var rom = new FdsFile(fileName); for (int sideNumber = 0; sideNumber < rom.Sides.Count; sideNumber++) { var driveStatus = dumper.ReadCpu(0x4032); if ((driveStatus & 1) != 0) { Console.Write($"Please set disk card, side #{sideNumber + 1}... "); while ((driveStatus & 1) != 0) { Thread.Sleep(100); driveStatus = dumper.ReadCpu(0x4032); } Console.WriteLine("OK"); } PrintDiskHeaderInfo(rom.Sides[sideNumber].DiskInfoBlock); Console.WriteLine($"Number of non-hidden files: {rom.Sides[sideNumber].FileAmount}"); Console.WriteLine($"Number of hidden files: {rom.Sides[sideNumber].Files.Count - rom.Sides[sideNumber].FileAmount}"); var blocks = rom.Sides[sideNumber].GetBlocks().ToArray(); Console.WriteLine($"Total blocks to write: {blocks.Length}"); byte blocksWrited = 0; while (blocksWrited < blocks.Length) { uint totalSize = 1; var blockIDs = new List <byte>(); var blocksToWrite = new List <IFdsBlock>(); for (byte i = blocksWrited; i < blocks.Count(); i++) { if (totalSize + blocks[i].Length + 3 <= dumper.MaxWritePacketSize) { blocksToWrite.Add(blocks[i]); blockIDs.Add(i); totalSize += blocks[i].Length + 3; } else { break; } } if (!blocksToWrite.Any()) { throw new OutOfMemoryException("Dumper has not enoght memory to write such big block"); } Console.Write($"Writing block(s): {string.Join(", ", blockIDs)}... "); dumper.WriteFdsBlocks(blockIDs.ToArray(), blocksToWrite.ToArray()); Console.WriteLine("OK"); blocksWrited += (byte)blocksToWrite.Count; } if (needCheck) { Console.WriteLine("Starting verification process"); var hiddenFiles = rom.Sides[sideNumber].Files.Count > rom.Sides[sideNumber].FileAmount; var sideImage = DumpFDSSide(dumper, dumpHiddenFiles: hiddenFiles, printDiskInfo: false); if (!sideImage.DiskInfoBlock.Equals(rom.Sides[sideNumber].DiskInfoBlock)) { throw new IOException("Disk info block verification failed"); } if (!sideImage.FileAmount.Equals(rom.Sides[sideNumber].FileAmount)) { throw new IOException("File amount block verification failed"); } if (sideImage.Files.Count < rom.Sides[sideNumber].Files.Count) { throw new IOException($"Invalid file count: {sideImage.Files.Count} < {rom.Sides[sideNumber].Files.Count}"); } for (int f = 0; f < rom.Sides[sideNumber].Files.Count; f++) { if (!sideImage.Files[f].HeaderBlock.Equals(rom.Sides[sideNumber].Files[f].HeaderBlock)) { throw new IOException($"File #{f} header block verification failed"); } if (!sideImage.Files[f].DataBlock.Equals(rom.Sides[sideNumber].Files[f].DataBlock)) { throw new IOException($"File #{f} data block verification failed"); } } Console.WriteLine("Verification successful."); } if (sideNumber + 1 < rom.Sides.Count) { driveStatus = dumper.ReadCpu(0x4032); if ((driveStatus & 1) == 0) { Console.Write($"Please remove disk card... "); while ((driveStatus & 1) == 0) { Thread.Sleep(100); driveStatus = dumper.ReadCpu(0x4032); } Console.WriteLine("OK"); } } } } finally { dumper.Timeout = oldTimeout; } }