Merge pull request #529 from wybren1971/IMDwriter

Imd reader
This commit is contained in:
David Given
2022-06-13 15:46:54 +02:00
committed by GitHub
2 changed files with 248 additions and 86 deletions

View File

@@ -12,44 +12,44 @@
#include <iostream>
#include <fstream>
static unsigned getModulationandSpeed(uint8_t flags, bool *mfm)
static unsigned getModulationandSpeed(uint8_t flags, bool *fm)
{
switch (flags)
{
case 0: /* 500 kbps FM */
//clockRateKhz.setDefaultValue(250);
*mfm = false;
*fm = true;
return 500;
break;
case 1: /* 300 kbps FM */
*mfm = false;
*fm = true;
return 300;
break;
case 2: /* 250 kbps FM */
*mfm = false;
*fm = true;
return 250;
break;
case 3: /* 500 kbps MFM */
*mfm = true;
*fm = false;
return 500;
break;
case 4: /* 300 kbps MFM */
*mfm = true;
*fm = false;
return 300;
break;
case 5: /* 250 kbps MFM */
*mfm = true;
*fm = false;
return 250;
break;
default:
Error() << fmt::format("don't understand IMD disks with this modulation and speed {}", flags);
Error() << fmt::format("IMD: don't understand IMD disks with this modulation and speed {}", flags);
throw 0;
}
}
@@ -88,9 +88,7 @@ static unsigned getSectorSize(uint8_t flags)
class IMDImageReader : public ImageReader
{
public:
IMDImageReader(const ImageReaderProto& config):
ImageReader(config)
{}
IMDImageReader(const ImageReaderProto& config): ImageReader(config) {}
std::unique_ptr<Image> readImage()
/*
@@ -115,9 +113,9 @@ public:
//Read File
std::ifstream inputFile(_config.filename(), std::ios::in | std::ios::binary);
if (!inputFile.is_open())
Error() << "cannot open input file";
Error() << "IMD: cannot open input file";
//define some variables
bool mfm = false; //define coding just to show in comment for setting the right write parameters
bool fm = false; //define coding just to show in comment for setting the right write parameters
inputFile.seekg(0, inputFile.end);
int inputFileSize = inputFile.tellg(); // determine filesize
inputFile.seekg(0, inputFile.beg);
@@ -126,34 +124,41 @@ public:
ByteReader br(data);
std::unique_ptr<Image> image(new Image);
TrackHeader header = {0, 0, 0, 0, 0};
TrackHeader previousheader = {0, 0, 0, 0, 0};
unsigned n = 0;
unsigned headerPtr = 0;
unsigned Modulation_Speed = 0;
unsigned sectorSize = 0;
std::string sector_skew;
int b;
unsigned char comment[8192]; //i choose a fixed value. dont know how to make dynamic arrays in C++. This should be enough
// Read comment
while ((b = br.read_8()) != EOF && b != 0x1A)
{
comment[n++] = (unsigned char)b;
}
headerPtr = n; //set pointer to after comment
comment[n] = '\0'; // null-terminate the string
//write comment to screen
Logger() << fmt::format("IMD: comment: {}", comment);
std::string sector_skew;
int b;
std::string comment;
bool blnOptionalCylinderMap = false;
bool blnOptionalHeadMap = false;
int trackSectorSize = -1;
// Read comment
comment.clear();
while ((b = br.read_8()) != EOF && b != END_OF_FILE)
{
comment.push_back(b);
n++;
}
headerPtr = n; //set pointer to after comment
Logger() << "Comment in IMD file:"
<< fmt::format("{}",
comment);
//first read header
for (;;)
{
if (headerPtr >= inputFileSize-1)
{
break;
}
//first read header
header.ModeValue = br.read_8();
headerPtr++;
Modulation_Speed = getModulationandSpeed(header.ModeValue, &mfm);
Modulation_Speed = getModulationandSpeed(header.ModeValue, &fm);
header.track = br.read_8();
headerPtr++;
header.Head = br.read_8();
@@ -164,87 +169,239 @@ public:
headerPtr++;
sectorSize = getSectorSize(header.SectorSize);
//Read optional track map To Do
//Read optional sector head map To Do
unsigned optionalsector_map[header.numSectors];
//The Sector Cylinder Map has one entry for each sector, and contains the logical Cylinder ID for the corresponding sector in the Sector Numbering Map.
if (header.Head & SEC_CYL_MAP_FLAG)
{
//Read optional cylinder map
for (b = 0; b < header.numSectors; b++)
{
optionalsector_map[b] = br.read_8();
headerPtr++;
}
blnOptionalCylinderMap = true; //set bool so we know there is an optional cylinder map
header.Head = header.Head^SEC_CYL_MAP_FLAG; //remove flag 10000001 ^ 10000000 = 00000001 and 10000000 ^ 10000000 = 00000000
}
//Read optional sector head map
//The Sector Head Map has one entry for each sector, and contains the logical Head ID for the corresponding sector in the Sector Numbering Map.
unsigned optionalhead_map[header.numSectors];
if (header.Head & SEC_HEAD_MAP_FLAG)
{
//Read optional sector head map
for (b = 0; b < header.numSectors; b++)
{
optionalhead_map[b] = br.read_8();
headerPtr++;
}
blnOptionalHeadMap = true; //set bool so we know there is an optional head map
header.Head = header.Head^SEC_HEAD_MAP_FLAG; //remove flag 01000001 ^ 01000001 = 00000001 and 01000000 ^ 0100000 = 00000000 for writing sector head later
}
//read sector numbering map
std::vector<unsigned> sector_map(header.numSectors);
sector_skew.clear();
for (int b = 0; b < header.numSectors; b++)
{
sector_map[b] = br.read_8();
headerPtr++;
sector_skew.clear();
for (b = 0; b < header.numSectors; b++)
{
uint8_t t;
t = br.read_8();
sector_skew.push_back(t);
headerPtr++;
}
auto ibm = config.mutable_encoder()->mutable_ibm();
auto trackdata = ibm->add_trackdata();
trackdata->set_target_clock_period_us(1e3 / Modulation_Speed);
trackdata->set_target_rotational_period_ms(200);
if (trackSectorSize < 0)
{
trackSectorSize = sectorSize;
// this is the first sector we've read, use it settings for
// per-track data
trackdata->set_track(header.track);
trackdata->set_head(header.Head);
trackdata->set_sector_size(sectorSize);
trackdata->set_use_fm(fm);
}
else if (trackSectorSize != sectorSize)
{
Error() << "IMD: multiple sector sizes per track are "
"currently unsupported";
}
auto sectors = trackdata->mutable_sectors();
//read the sectors
for (int s = 0; s < header.numSectors; s++)
{
Bytes sectordata;
const auto& sector = image->put(header.track, header.Head, sector_map[s]);
Bytes compressed(sectorSize);
int SectorID;
SectorID = sector_skew[s];
const auto& sector = image->put(header.track, header.Head, SectorID);
sector->logicalSector = SectorID;
//read the status of the sector
unsigned int Status_Sector = br.read_8();
headerPtr++;
switch (Status_Sector)
{
case 0: /* Sector data unavailable - could not be read */
break;
/*fluxengine knows of a few sector statussen but not all of the statussen in IMD.
* // the statussen are in sector.h. Translation to fluxengine is as follows:
* Statussen fluxengine | Status IMD
*--------------------------------------------------------------------------------------------------------------------
* OK, | 1, 2 (Normal data: (Sector Size) of (compressed) bytes follow)
* BAD_CHECKSUM, | 5, 6, 7, 8
* MISSING, sector not found | 0 (Sector data unavailable - could not be read)
* DATA_MISSING, sector present but no data found | 3, 4
* CONFLICT, |
* INTERNAL_ERROR |
*/
case 0: /* Sector data unavailable - could not be read */
case 1: /* Normal data: (Sector Size) bytes follow */
sectordata = br.read(sectorSize);
headerPtr += sectorSize;
sector->data.writer().append(sectordata);
break;
sector->status = Sector::MISSING;
break;
case 2: /* Compressed: All bytes in sector have same value (xx) */
sectordata = br.read(1);
headerPtr++;
sector->data.writer().append(sectordata);
case 1: /* Normal data: (Sector Size) bytes follow */
sectordata = br.read(sectorSize);
headerPtr += sectorSize;
sector->data.writer().append(sectordata);
sector->status = Sector::OK;
break;
for (int k = 1; k < sectorSize; k++)
{
//fill data till sector is full
sector->data.writer().append(sectordata);
}
break;
case 2: /* Compressed: All bytes in sector have same value (xx) */
compressed[0] = br.read_8();
headerPtr++;
for (int k = 1; k < sectorSize; k++)
{
//fill data till sector is full
br.seek(headerPtr);
compressed[k] = br.read_8();
}
sector->data.writer().append(compressed);
sector->status = Sector::OK;
break;
case 3: /* Normal data with "Deleted-Data address mark" */
case 4: /* Compressed with "Deleted-Data address mark"*/
case 5: /* Normal data read with data error */
case 6: /* Compressed read with data error" */
case 7: /* Deleted data read with data error" */
case 8: /* Compressed, Deleted read with data error" */
default:
Error() << fmt::format("don't understand IMD disks with sector status {}", Status_Sector);
}
sector->status = Sector::OK;
sector->logicalTrack = header.track;
sector->physicalTrack = Mapper::remapTrackLogicalToPhysical(header.track);
sector->logicalSide = sector->physicalHead = header.Head;
sector->logicalSector = (sector_map[s]);
case 3: /* Normal data with "Deleted-Data address mark" */
sector->status = Sector::DATA_MISSING;
sectordata = br.read(sectorSize);
headerPtr += sectorSize;
sector->data.writer().append(sectordata);
break;
case 4: /* Compressed with "Deleted-Data address mark"*/
compressed[0] = br.read_8();
headerPtr++;
for (int k = 1; k < sectorSize; k++)
{
//fill data till sector is full
br.seek(headerPtr);
compressed[k] = br.read_8();
}
sector->data.writer().append(compressed);
sector->status = Sector::DATA_MISSING;
break;
case 5: /* Normal data read with data error*/
sectordata = br.read(sectorSize);
headerPtr += sectorSize;
sector->status = Sector::BAD_CHECKSUM;
sector->data.writer().append(sectordata);
break;
case 6: /* Compressed read with data error*/
compressed[0] = br.read_8();
headerPtr++;
for (int k = 1; k < sectorSize; k++)
{
//fill data till sector is full
br.seek(headerPtr);
compressed[k] = br.read_8();
}
sector->data.writer().append(compressed);
sector->status = Sector::BAD_CHECKSUM;
break;
case 7: /* Deleted data read with data error*/
sectordata = br.read(sectorSize);
headerPtr += sectorSize;
sector->status = Sector::BAD_CHECKSUM;
sector->data.writer().append(sectordata);
break;
case 8: /* Compressed, Deleted read with data error*/
compressed[0] = br.read_8();
headerPtr++;
for (int k = 1; k < sectorSize; k++)
{
//fill data till sector is full
br.seek(headerPtr);
compressed[k] = br.read_8();
}
sector->data.writer().append(compressed);
sector->status = Sector::BAD_CHECKSUM;
break;
default:
Error() << fmt::format("IMD: Don't understand IMD files with sector status {}, track {}, sector {}", Status_Sector, header.track, s);
}
if (blnOptionalCylinderMap) //there was een optional cylinder map. write it to the sector
//The Sector Cylinder Map has one entry for each sector, and contains the logical Cylinder ID for the corresponding sector in the Sector Numbering Map.
{
sector->physicalTrack = Mapper::remapTrackLogicalToPhysical(header.track);
sector->logicalTrack = optionalsector_map[s];
blnOptionalCylinderMap = false;
}
else
{
sector->logicalTrack = header.track;
sector->physicalTrack = Mapper::remapTrackLogicalToPhysical(header.track);
}
if (blnOptionalHeadMap) //there was een optional head map. write it to the sector
//The Sector Head Map has one entry for each sector, and contains the logical Head ID for the corresponding sector in the Sector Numbering Map.
{
sector->physicalHead = header.Head;
sector->logicalSide = optionalhead_map[s];
blnOptionalHeadMap = false;
}
else
{
sector->logicalSide = header.Head;
sector->physicalHead = header.Head;
}
}
}
//Write format detected in IMD image to screen to help user set the right write parameters
if (config.encoder().format_case() != EncoderProto::FormatCase::FORMAT_NOT_SET)
Logger() << "IMD: overriding configured format";
image->setGeometry({
.numTracks = header.track,
.numSides = header.Head + 1U,
.numSectors = header.numSectors,
.sectorSize = sectorSize
});
size_t headSize = header.numSectors * sectorSize;
size_t trackSize = headSize * (header.Head + 1);
image->calculateSize();
const Geometry& geometry = image->getGeometry();
size_t headSize = ((header.numSectors) * (sectorSize));
size_t trackSize = (headSize * (header.Head + 1));
Logger() << fmt::format("IMD: {} tracks, {} heads; {}; {} kbps; {} sectors; sectorsize {};"
" sectormap {}; {} kB total\n",
header.track, header.Head + 1,
mfm ? "MFM" : "FM",
Modulation_Speed, header.numSectors, sectorSize, sector_skew, (header.track+1) * trackSize / 1024);
Logger() << "IMD: read "
<< fmt::format("{} tracks, {} heads; {}; {} kbps; {} sectoren; sectorsize {}; {} kB total.",
header.track + 1, header.Head + 1,
fm ? "FM" : "MFM",
Modulation_Speed, header.numSectors, sectorSize, (header.track+1) * trackSize / 1024);
if (!config.has_heads())
{
auto* heads = config.mutable_heads();
heads->set_start(0);
heads->set_end(geometry.numSides - 1);
}
if (!config.has_tracks())
{
auto* tracks = config.mutable_tracks();
tracks->set_start(0);
tracks->set_end(geometry.numTracks - 1);
}
return image;
}
};

View File

@@ -1,5 +1,10 @@
comment: 'Hewlett-Packard LIF 770kB 3.5" DSDD'
drive {
high_density: false
rotational_period_ms: 200
}
image_reader {
filename: "hplif770.img"
img {
@@ -8,7 +13,7 @@ image_reader {
trackdata {
sector_size: 1024
sector_range {
start_sector: 0
start_sector: 1
sector_count: 5
}
}
@@ -23,13 +28,13 @@ encoder {
sector_size: 1024
gap0: 80
gap2: 22
gap3: 44
gap3: 80
sectors {
sector: 0
sector: 1
sector: 2
sector: 3
sector: 4
sector: 5
}
}
}