Hi, thank you very much Gribo, nice to open SCH document.
Here is my work in C++/Qt to read the .PCBDOC files, sorry I didn't write the documentation, but that could help someone who want to do the same thing (display the board on the screen with the components, their names and values, and all the lines / arcs). I let here only the code to read the binary files, the others are no so hard to understand in ASCII).
To extract the components value :
if (file.open(QIODevice::ReadOnly)) {
// Read the file extracted
QDataStream streamIn(&file);
streamIn.setByteOrder(QDataStream::LittleEndian);
QByteArray separator;
separator.resize(4);
streamIn.readRawData(separator.data(), 4);
QByteArray sizeOfFieldsHexa;
sizeOfFieldsHexa.append(separator.at(1));
int sizeOfFields = sizeOfFieldsHexa.toHex().toInt(NULL, 16) + 5;
qDebug() << "Sep :" << separator.toHex();
qDebug() << "Raw file size" << file.size();
qDebug() << "Size of fields w sep" << sizeOfFields;
do
{
streamIn.skipRawData(1);
quint8 numLayer;
streamIn >> numLayer;
streamIn.skipRawData(6);
quint16 numComponent;
streamIn >> numComponent;
streamIn.skipRawData(4);
quint32 posXs, posYs;
streamIn >> posXs;
streamIn >> posYs;
streamIn.skipRawData(6);
double angleRotTmp;
streamIn >> angleRotTmp;
streamIn.skipRawData(6);
bool isADesignator;
streamIn >> isADesignator;
streamIn.skipRawData(sizeOfFields-28-19);
quint8 sizeOfString;
streamIn >> sizeOfString;
QByteArray tmpString;
tmpString.resize(sizeOfString-1);
streamIn.skipRawData(4);
streamIn.readRawData(tmpString.data(), sizeOfString-1);
QString str = QString::fromLocal8Bit(tmpString);
streamIn.skipRawData(4); // skip the new separator
if (((numLayer == 33) || (numLayer == 34)) && numComponent != 65535) // mech 33 => top overlay & numComponent is a real component number
{
if (numComponent >= compCommentList.size()) // sometimes the num comp doesn't follow : 100, 101, 102, 106,107
{
compCommentList.resize(numComponent+1);
compDesignList.resize(numComponent+1);
//qDebug() << "Resize";
}
if (!isADesignator) { // it's a comment (first)
compCommentList[numComponent] = str;
//qDebug() << "Description[" << numComponent << "] found :" << str;
}
else // it's a designator (second)
{
compDesignList[numComponent] = str;
//qDebug() << "Designator[" << numComponent << "] found :" << str;
}
}
} while(!file.atEnd());
qDebug() << "Start checking designator / description pairs";
for (int i=0 ; i<compCommentList.size() ; i++) {
if (!compCommentList[i].isEmpty() && !compDesignList[i].isEmpty())
{
for (int j=0 ; j<(*p_tmpComponentsList).size() ; j++) {
if ((*p_tmpComponentsList)[j].designator == compDesignList[i]) {
(*p_tmpComponentsList)[j].description = compCommentList[i];
//qDebug() << "Pair [" << j << "] found :" << (*p_tmpComponentsList)[j].designator << "description :" << (*p_tmpComponentsList)[j].description;
counterComp++;
}
}
}
}
qDebug() << counterComp << "components in /Texts/Data";
if (nbComponents == counterComp)
return true; // success
else {
QMessageBox msgBox;
msgBox.setText(QString("Error : descriptor / designator missing in Texts/Data, ") + QString::number(nbComponents-counterComp) + " cannot be loaded.");
msgBox.setIcon(QMessageBox::Critical);
msgBox.exec();
}
}
To extract the strings :
if (file.open(QIODevice::ReadOnly)) {
// Read the file extracted
QDataStream streamIn(&file);
streamIn.setByteOrder(QDataStream::LittleEndian);
QByteArray separator;
separator.resize(4);
streamIn.readRawData(separator.data(), 4);
QByteArray sizeOfFieldsHexa;
sizeOfFieldsHexa.append(separator.at(1));
int sizeOfFields = sizeOfFieldsHexa.toHex().toInt(NULL, 16) + 5;
qDebug() << "Sep :" << separator.toHex();
qDebug() << "Raw file size" << file.size();
qDebug() << "Size of fields w sep" << sizeOfFields;
m_listPosTexts.clear();
m_listStringTexts.clear();
m_listRotationTexts.clear();
m_listTypeTexts.clear();
m_listHeigthTexts.clear();
do
{
streamIn.skipRawData(1);
quint8 numLayer;
streamIn >> numLayer;
streamIn.skipRawData(12);
quint32 posXs, posYs;
streamIn >> posXs;
streamIn >> posYs;
quint32 textHeight;
streamIn >> textHeight;
streamIn.skipRawData(2);
double angleRotTmp;
streamIn >> angleRotTmp;
streamIn.skipRawData(1);
quint32 textWidth;
streamIn >> textWidth;
bool isADescriptionText;
streamIn >> isADescriptionText;
bool isADesignatorText;
streamIn >> isADesignatorText;
streamIn.skipRawData(sizeOfFields-28-19);
quint8 sizeOfString;
streamIn >> sizeOfString;
QByteArray tmpString;
tmpString.resize(sizeOfString-1);
streamIn.skipRawData(4);
streamIn.readRawData(tmpString.data(), sizeOfString-1);
QString str = QString::fromLocal8Bit(tmpString);
streamIn.skipRawData(4); // skip the new separator
double posXs_mm = (double)(posXs) / 10000.0 * 0.0254;
double posYs_mm = (double)(posYs) / 10000.0 * 0.0254;
double textHeight_mm = (double)(textHeight) / 10000.0 * 0.0254;
if ((numLayer == 33) && !str.contains("MMBX receptacle")) // mech 33 => top overlay
{
//qDebug() << "Text on layer :" << numLayer << " Xs=" << posXs_mm << " Ys=" << posYs_mm << "Size :" << sizeOfString << " String :" << str << "Rotat. :" << angleRotTmp;
m_listPosTexts.append(QVector2D(posXs_mm, posYs_mm));
m_listStringTexts.append(str);
m_listRotationTexts.append(angleRotTmp);
if (isADesignatorText)
m_listTypeTexts.append(_DESIGNATOR_TEXT);
else if (isADescriptionText)
m_listTypeTexts.append(_DESCRIPTION_TEXT);
else
m_listTypeTexts.append(_FREE_TEXT);
m_listHeigthTexts.append(textHeight_mm);
counterTexts++;
}
} while(!file.atEnd());
qDebug() << counterTexts << "strings in /Texts/Data";
}
To extract the tracks :
if (file.open(QIODevice::ReadOnly)) {
// Read the file extracted
QDataStream streamIn(&file);
streamIn.setByteOrder(QDataStream::LittleEndian);
QByteArray separator;
separator.resize(4);
streamIn.readRawData(separator.data(), 4);
QByteArray sizeOfFieldsHexa;
sizeOfFieldsHexa.append(separator.at(1));
int sizeOfFields = sizeOfFieldsHexa.toHex().toInt(NULL, 16) + 5;
const int sizeDatasAtEndToSkip = sizeOfFields - 4 - 2 - 12 - 4 - 4 - 4 - 4 + 4; // +5 at end to skip the next separator
qDebug() << "Sep :" << separator.toHex();
qDebug() << "Raw file size" << file.size();
qDebug() << "Size of fields w sep" << sizeOfFields;
qDebug() << "Size to skip at end" << sizeDatasAtEndToSkip;
m_listLayersTracks.clear();
m_listPointStartTracks.clear();
m_listPointEndTracks.clear();
do
{
streamIn.skipRawData(1);
quint8 numLayer;
streamIn >> numLayer;
streamIn.skipRawData(12);
quint32 posXs, posYs, posXe, posYe;
streamIn >> posXs;
streamIn >> posYs;
streamIn >> posXe;
streamIn >> posYe;
streamIn.skipRawData(sizeDatasAtEndToSkip);
double posXs_mm = (double)(posXs) / 10000.0 * 0.0254;
double posYs_mm = (double)(posYs) / 10000.0 * 0.0254;
double posXe_mm = (double)(posXe) / 10000.0 * 0.0254;
double posYe_mm = (double)(posYe) / 10000.0 * 0.0254;
if ((numLayer == m_numBoardOutlineFromPCBDOC) || (numLayer == 66) || (numLayer == 67)) // mech 60 for P581 => 60 or mech10 or mech11
{
if (posXs_mm > maxX)
maxX = posXs_mm;
if (posYs_mm > maxY)
maxY = posYs_mm;
if (posXe_mm > maxX)
maxX = posXe_mm;
if (posYe_mm > maxY)
maxY = posYe_mm;
if (posXs_mm < minX)
minX = posXs_mm;
if (posYs_mm < minY)
minY = posYs_mm;
if (posXe_mm < minX)
minX = posXe_mm;
if (posYe_mm < minY)
minY = posYe_mm;
m_minimumTracksVertex = QPointF(minX, minY);
m_maximumTracksVertex = QPointF(maxX, maxY);
//qDebug() << "Track on layer : " << numLayer << " Xs=" << posXs_mm << " Ys=" << posYs_mm << " Xe=" << posXe_mm << " Ye=" << posYe_mm ;
m_listLayersTracks.append(numLayer);
m_listPointStartTracks.append(QVector2D(posXs_mm, posYs_mm));
m_listPointEndTracks.append(QVector2D(posXe_mm, posYe_mm));
counterTracks++;
}
} while(!file.atEnd());
qDebug() << "Track vertex min=" << m_minimumTracksVertex << " Max=" << m_maximumTracksVertex;
qDebug() << counterTracks << "tracks in /Tracks/Data";
}
To extract the arcs :
if (file.open(QIODevice::ReadOnly)) {
// Read the file extracted
QDataStream streamIn(&file);
streamIn.setByteOrder(QDataStream::LittleEndian);
QByteArray separator;
separator.resize(4);
streamIn.readRawData(separator.data(), 4);
QByteArray sizeOfFieldsHexa;
sizeOfFieldsHexa.append(separator.at(1));
int sizeOfFields = sizeOfFieldsHexa.toHex().toInt(NULL, 16) + 5;
const int sizeDatasAtEndToSkip = sizeOfFields - 4 - 2 - 12 - 4 - 4 - 4 - 8 - 8 + 4; // +5 at end to skip the next separator
qDebug() << "Sep :" << separator.toHex();
qDebug() << "Raw file size" << file.size();
qDebug() << "Size of fields w sep" << sizeOfFields;
qDebug() << "Size to skip at end" << sizeDatasAtEndToSkip;
m_listLayersArcs.clear();
m_listCenterArcs.clear();
m_listRadiusArcs.clear();
m_listStartAngleArcs.clear();
m_listEndAngleArcs.clear();
do
{
streamIn.skipRawData(1);
quint8 numLayer;
streamIn >> numLayer;
streamIn.skipRawData(12);
quint32 posX, posY, radius;
streamIn >> posX;
streamIn >> posY;
streamIn >> radius;
float startAngle, endAngle;
streamIn >> startAngle;
streamIn >> endAngle;
streamIn.skipRawData(sizeDatasAtEndToSkip);
double posXcenter_mm = (double)(posX) / 10000.0 * 0.0254;
double posYcenter_mm = (double)(posY) / 10000.0 * 0.0254;
double radius_mm = (double)(radius) / 10000.0 * 0.0254;
if ((numLayer == m_numBoardOutlineFromPCBDOC) || (numLayer == 66) || (numLayer == 67)) { // mech 60 for P581 => 60 or mech10 or mech11
//qDebug() << "Arc on layer : " << numLayer << " X=" << posXcenter_mm << " Y=" << posYcenter_mm << " R=" << radius_mm << " StartA=" << startAngle << " EndA=" << endAngle ;
m_listLayersArcs.append(numLayer);
m_listCenterArcs.append(QVector2D(posXcenter_mm, posYcenter_mm));
m_listRadiusArcs.append(radius_mm);
m_listStartAngleArcs.append(startAngle);
m_listEndAngleArcs.append(endAngle);
counterArcs++;
}
} while(!file.atEnd());
qDebug() << counterArcs << "arcs in /Arcs/Data";
file.close();
}