public static ModePage_05?DecodeModePage_05(byte[] pageResponse) { if ((pageResponse?[0] &0x40) == 0x40) { return(null); } if ((pageResponse?[0] &0x3F) != 0x05) { return(null); } if (pageResponse[1] + 2 != pageResponse.Length) { return(null); } if (pageResponse.Length < 32) { return(null); } ModePage_05 decoded = new ModePage_05(); decoded.PS |= (pageResponse[0] & 0x80) == 0x80; decoded.TransferRate = (ushort)((pageResponse[2] << 8) + pageResponse[3]); decoded.Heads = pageResponse[4]; decoded.SectorsPerTrack = pageResponse[5]; decoded.BytesPerSector = (ushort)((pageResponse[6] << 8) + pageResponse[7]); decoded.Cylinders = (ushort)((pageResponse[8] << 8) + pageResponse[9]); decoded.WritePrecompCylinder = (ushort)((pageResponse[10] << 8) + pageResponse[11]); decoded.WriteReduceCylinder = (ushort)((pageResponse[12] << 8) + pageResponse[13]); decoded.DriveStepRate = (ushort)((pageResponse[14] << 8) + pageResponse[15]); decoded.DriveStepPulse = pageResponse[16]; decoded.HeadSettleDelay = (ushort)((pageResponse[17] << 8) + pageResponse[18]); decoded.MotorOnDelay = pageResponse[19]; decoded.MotorOffDelay = pageResponse[20]; decoded.TRDY |= (pageResponse[21] & 0x80) == 0x80; decoded.SSN |= (pageResponse[21] & 0x40) == 0x40; decoded.MO |= (pageResponse[21] & 0x20) == 0x20; decoded.SPC = (byte)(pageResponse[22] & 0x0F); decoded.WriteCompensation = pageResponse[23]; decoded.HeadLoadDelay = pageResponse[24]; decoded.HeadUnloadDelay = pageResponse[25]; decoded.Pin34 = (byte)((pageResponse[26] & 0xF0) >> 4); decoded.Pin2 = (byte)(pageResponse[26] & 0x0F); decoded.Pin4 = (byte)((pageResponse[27] & 0xF0) >> 4); decoded.Pin1 = (byte)(pageResponse[27] & 0x0F); decoded.MediumRotationRate = (ushort)((pageResponse[28] << 8) + pageResponse[29]); return(decoded); }
public static string PrettifyModePage_05(ModePage_05?modePage) { if (!modePage.HasValue) { return(null); } ModePage_05 page = modePage.Value; StringBuilder sb = new StringBuilder(); sb.AppendLine("SCSI Flexible disk page:"); if (page.PS) { sb.AppendLine("\tParameters can be saved"); } sb.AppendFormat("\tTransfer rate: {0} kbit/s", page.TransferRate).AppendLine(); sb.AppendFormat("\t{0} heads", page.Heads).AppendLine(); sb.AppendFormat("\t{0} cylinders", page.Cylinders).AppendLine(); sb.AppendFormat("\t{0} sectors per track", page.SectorsPerTrack).AppendLine(); sb.AppendFormat("\t{0} bytes per sector", page.BytesPerSector).AppendLine(); if (page.WritePrecompCylinder < page.Cylinders) { sb.AppendFormat("\tWrite pre-compensation starts at cylinder {0}", page.WritePrecompCylinder) .AppendLine(); } if (page.WriteReduceCylinder < page.Cylinders) { sb.AppendFormat("\tWrite current reduction starts at cylinder {0}", page.WriteReduceCylinder) .AppendLine(); } if (page.DriveStepRate > 0) { sb.AppendFormat("\tDrive steps in {0} μs", (uint)page.DriveStepRate * 100).AppendLine(); } if (page.DriveStepPulse > 0) { sb.AppendFormat("\tEach step pulse is {0} ms", page.DriveStepPulse).AppendLine(); } if (page.HeadSettleDelay > 0) { sb.AppendFormat("\tHeads settles in {0} μs", (uint)page.HeadSettleDelay * 100).AppendLine(); } if (!page.TRDY) { sb .AppendFormat("\tTarget shall wait {0} seconds before attempting to access the medium after motor on is asserted", (double)page.MotorOnDelay * 10).AppendLine(); } else { sb .AppendFormat("\tTarget shall wait {0} seconds after drive is ready before aborting medium access attemps", (double)page.MotorOnDelay * 10).AppendLine(); } if (page.MotorOffDelay != 0xFF) { sb .AppendFormat("\tTarget shall wait {0} seconds before releasing the motor on signal after becoming idle", (double)page.MotorOffDelay * 10).AppendLine(); } else { sb.AppendLine("\tTarget shall never release the motor on signal"); } if (page.TRDY) { sb.AppendLine("\tThere is a drive ready signal"); } if (page.SSN) { sb.AppendLine("\tSectors start at 1"); } if (page.MO) { sb.AppendLine("\tThe motor on signal shall remain released"); } sb.AppendFormat("\tDrive needs to do {0} step pulses per cylinder", page.SPC + 1).AppendLine(); if (page.WriteCompensation > 0) { sb.AppendFormat("\tWrite pre-compensation is {0}", page.WriteCompensation).AppendLine(); } if (page.HeadLoadDelay > 0) { sb.AppendFormat("\tHead takes {0} ms to load", page.HeadLoadDelay).AppendLine(); } if (page.HeadUnloadDelay > 0) { sb.AppendFormat("\tHead takes {0} ms to unload", page.HeadUnloadDelay).AppendLine(); } if (page.MediumRotationRate > 0) { sb.AppendFormat("\tMedium rotates at {0} rpm", page.MediumRotationRate).AppendLine(); } switch (page.Pin34 & 0x07) { case 0: sb.AppendLine("\tPin 34 is unconnected"); break; case 1: sb.Append("\tPin 34 indicates drive is ready when active "); sb.Append((page.Pin34 & 0x08) == 0x08 ? "high" : "low"); break; case 2: sb.Append("\tPin 34 indicates disk has changed when active "); sb.Append((page.Pin34 & 0x08) == 0x08 ? "high" : "low"); break; default: sb.AppendFormat("\tPin 34 indicates unknown function {0} when active ", page.Pin34 & 0x07); sb.Append((page.Pin34 & 0x08) == 0x08 ? "high" : "low"); break; } switch (page.Pin4 & 0x07) { case 0: sb.AppendLine("\tPin 4 is unconnected"); break; case 1: sb.Append("\tPin 4 indicates drive is in use when active "); sb.Append((page.Pin4 & 0x08) == 0x08 ? "high" : "low"); break; case 2: sb.Append("\tPin 4 indicates eject when active "); sb.Append((page.Pin4 & 0x08) == 0x08 ? "high" : "low"); break; case 3: sb.Append("\tPin 4 indicates head load when active "); sb.Append((page.Pin4 & 0x08) == 0x08 ? "high" : "low"); break; default: sb.AppendFormat("\tPin 4 indicates unknown function {0} when active ", page.Pin4 & 0x07); sb.Append((page.Pin4 & 0x08) == 0x08 ? "high" : "low"); break; } switch (page.Pin2 & 0x07) { case 0: sb.AppendLine("\tPin 2 is unconnected"); break; default: sb.AppendFormat("\tPin 2 indicates unknown function {0} when active ", page.Pin2 & 0x07); sb.Append((page.Pin2 & 0x08) == 0x08 ? "high" : "low"); break; } switch (page.Pin1 & 0x07) { case 0: sb.AppendLine("\tPin 1 is unconnected"); break; case 1: sb.Append("\tPin 1 indicates disk change reset when active "); sb.Append((page.Pin1 & 0x08) == 0x08 ? "high" : "low"); break; default: sb.AppendFormat("\tPin 1 indicates unknown function {0} when active ", page.Pin1 & 0x07); sb.Append((page.Pin1 & 0x08) == 0x08 ? "high" : "low"); break; } return(sb.ToString()); }