OdbDesignLib
OdbDesign ODB++ Parsing Library
 
Loading...
Searching...
No Matches
Design.cpp
1#include "Design.h"
2#include "Design.h"
3#include "Package.h"
4#include "Logger.h"
5#include "../enums.h"
6#include "Part.h"
7#include "ProtobufMapHelpers.h"
8#include <memory>
9#include "Net.h"
10#include "../FileModel/Design/FileArchive.h"
11#include "../FileModel/Design/EdaDataFile.h"
12#include "../Text/Utf8Sanitizer.h"
13
14
15namespace Odb::Lib::ProductModel
16{
17 Design::Design()
18 {
19 }
20
21 Design::~Design()
22 {
23 m_components.clear();
24 m_componentsByName.clear();
25 m_nets.clear();
26 m_netsByName.clear();
27 m_packages.clear();
28 m_packagesByName.clear();
29 m_parts.clear();
30 m_partsByName.clear();
31 }
32
33 const std::string& Design::GetName() const
34 {
35 return m_name;
36 }
37
38 const std::string& Design::GetProductModel() const
39 {
40 return m_productModel;
41 }
42
43 const Net::Vector& Design::GetNets() const
44 {
45 return m_nets;
46 }
47
48 const Net::StringMap Design::GetNetsByName() const
49 {
50 return m_netsByName;
51 }
52
53 const Package::Vector& Design::GetPackages() const
54 {
55 return m_packages;
56 }
57
58 const Package::StringMap& Design::GetPackagesByName() const
59 {
60 return m_packagesByName;
61 }
62
63 const Component::Vector& Design::GetComponents() const
64 {
65 return m_components;
66 }
67
68 const Component::StringMap& Design::GetComponentsByName() const
69 {
70 return m_componentsByName;
71 }
72
73 std::shared_ptr<Component> Design::GetComponent(const std::string& refDes) const
74 {
75 auto findIt = m_componentsByName.find(refDes);
76 if (findIt != m_componentsByName.end())
77 {
78 return findIt->second;
79 }
80
81 return nullptr;
82 }
83
84 const Part::Vector& Design::GetParts() const
85 {
86 return m_parts;
87 }
88
89 const Part::StringMap& Design::GetPartsByName() const
90 {
91 return m_partsByName;
92 }
93
94 std::shared_ptr<Net> Design::GetNet(const std::string& name) const
95 {
96 auto findIt = m_netsByName.find(name);
97 if (findIt != m_netsByName.end())
98 {
99 return findIt->second;
100 }
101 return nullptr;
102 }
103
104 std::shared_ptr<Net> Design::GetNoneNet() const
105 {
106 return GetNet(NONE_NET_NAME);
107 }
108
109 bool Design::Build(std::string path)
110 {
111 auto pFileModel = std::make_shared<FileModel::Design::FileArchive>(path);
112 if (pFileModel->ParseFileModel())
113 {
114 return Build(pFileModel);
115 }
116 return false;
117 }
118
119 bool Design::Build(std::shared_ptr<FileModel::Design::FileArchive> pFileModel)
120 {
121 if (pFileModel == nullptr) return false;
122
123 m_pFileModel = pFileModel;
124
125 //m_productModel = m_pFileModel->GetProductName();
126 //m_name = m_pFileModel->GetProductName();
127
128 // atomic elements
129 if (! BuildNets()) return false;
130 if (! BuildPackages()) return false;
131 if (! BuildAllParts()) return false;
132 if (! BuildAllComponents()) return false;
133
134 // built from relationships between atomic elements
135 if (! BuildPlacementsFromComponentsFiles()) return false;
136
137 // already built from BuildPlacements()
138 //if (! BuildNoneNet()) return false;
139 //if (! BreakSinglePinNets()) return false;
140
141 if (CLIP_FILEMODEL_AFTER_BUILD)
142 {
143 ClipFileModel();
144 }
145
146 return true;
147 }
148
149 std::shared_ptr<FileModel::Design::FileArchive> Design::GetFileModel() const
150 {
151 return m_pFileModel;
152 }
153
154 void Design::ClipFileModel()
155 {
156 m_pFileModel = nullptr;
157 }
158
159 std::unique_ptr<Odb::Lib::Protobuf::ProductModel::Design> Design::to_protobuf() const
160 {
161 auto pDesignMsg = std::make_unique<Odb::Lib::Protobuf::ProductModel::Design>();
162 pDesignMsg->set_name(Odb::Lib::Text::ToUtf8(m_name));
163 pDesignMsg->set_productmodel(Odb::Lib::Text::ToUtf8(m_productModel));
164
165 if (m_pFileModel != nullptr)
166 {
167 pDesignMsg->mutable_filemodel()->CopyFrom(*m_pFileModel->to_protobuf());
168 }
169
170 for (const auto& pNet : m_nets)
171 {
172 pDesignMsg->add_nets()->CopyFrom(*pNet->to_protobuf());
173 }
174
175 FillProtobufMapWithSanitizedKeys(*pDesignMsg->mutable_netsbyname(), m_netsByName);
176
177 for (const auto& pPackage : m_packages)
178 {
179 pDesignMsg->add_packages()->CopyFrom(*pPackage->to_protobuf());
180 }
181
182 FillProtobufMapWithSanitizedKeys(*pDesignMsg->mutable_packagesbyname(), m_packagesByName);
183
184 for (const auto& pComponent : m_components)
185 {
186 pDesignMsg->add_components()->CopyFrom(*pComponent->to_protobuf());
187 }
188
189 FillProtobufMapWithSanitizedKeys(*pDesignMsg->mutable_componentsbyname(), m_componentsByName);
190
191 for (const auto& pPart : m_parts)
192 {
193 pDesignMsg->add_parts()->CopyFrom(*pPart->to_protobuf());
194 }
195
196 FillProtobufMapWithSanitizedKeys(*pDesignMsg->mutable_partsbyname(), m_partsByName);
197
198#ifndef NDEBUG
199 // Debug-only assertion: verify all string fields are valid UTF-8 before serialization
201#endif
202
203 return pDesignMsg;
204 }
205
206 void Design::from_protobuf(const Odb::Lib::Protobuf::ProductModel::Design& message)
207 {
208 m_name = message.name();
209 m_productModel = message.productmodel();
210
211 m_pFileModel = std::make_shared<FileModel::Design::FileArchive>();
212 m_pFileModel->from_protobuf(message.filemodel());
213
214 for (const auto& pNetMsg : message.nets())
215 {
216 auto pNet = std::make_shared<Net>("", -1);
217 pNet->from_protobuf(pNetMsg);
218 m_nets.push_back(pNet);
219 }
220
221 for (const auto& kvNetMsg : message.netsbyname())
222 {
223 auto pNet = std::make_shared<Net>("", -1);
224 pNet->from_protobuf(kvNetMsg.second);
225 m_netsByName[kvNetMsg.first] = pNet;
226 }
227
228 for (const auto& pPackageMsg : message.packages())
229 {
230 auto pPackage = std::make_shared<Package>("", -1);
231 pPackage->from_protobuf(pPackageMsg);
232 m_packages.push_back(pPackage);
233 }
234
235 for (const auto& kvPackageMsg : message.packagesbyname())
236 {
237 auto pPackage = std::make_shared<Package>("", -1);
238 pPackage->from_protobuf(kvPackageMsg.second);
239 m_packagesByName[kvPackageMsg.first] = pPackage;
240 }
241
242 for (const auto& pComponentMsg : message.components())
243 {
244 auto pComponent = std::make_shared<Component>("", "", nullptr, -1, BoardSide::BsNone, nullptr);
245 pComponent->from_protobuf(pComponentMsg);
246 m_components.push_back(pComponent);
247 }
248
249 for (const auto& kvComponentMsg : message.componentsbyname())
250 {
251 auto pComponent = std::make_shared<Component>("", "", nullptr, -1, BoardSide::BsNone, nullptr);
252 pComponent->from_protobuf(kvComponentMsg.second);
253 m_componentsByName[kvComponentMsg.first] = pComponent;
254 }
255
256 for (const auto& pPartMsg : message.parts())
257 {
258 auto pPart = std::make_shared<Part>("");
259 pPart->from_protobuf(pPartMsg);
260 m_parts.push_back(pPart);
261 }
262
263 for (const auto& kvPartMsg : message.partsbyname())
264 {
265 auto pPart = std::make_shared<Part>("");
266 pPart->from_protobuf(kvPartMsg.second);
267 m_partsByName[kvPartMsg.first] = pPart;
268 }
269 }
270
271 bool Design::BuildAllComponents()
272 {
273 if (m_pFileModel == nullptr) return false;
274 const auto& steps = m_pFileModel->GetStepsByName();
275 if (steps.empty()) return false;
276 auto& pStepDirectory = steps.begin()->second;
277
278 // top components layer
279 auto pTopComponentsFile = pStepDirectory->GetTopComponentsFile();
280 if (pTopComponentsFile == nullptr) return false;
281 if (! BuildComponents(pTopComponentsFile)) return false;
282
283 // bottom layer components
284 auto pBottomComponentsFile = pStepDirectory->GetBottomComponentsFile();
285 if (pBottomComponentsFile == nullptr) return false;
286 if (!BuildComponents(pBottomComponentsFile)) return false;
287
288 return true;
289 }
290
291 bool Design::BuildComponents(const Odb::Lib::FileModel::Design::ComponentsFile* pComponentsFile)
292 {
293 const auto& componentRecords = pComponentsFile->GetComponentRecords();
294 for (const auto& pComponentRecord : componentRecords)
295 {
296 auto& pPackage = m_packages[pComponentRecord->pkgRef];
297 auto index = pComponentRecord->index;
298 auto& pPart = m_partsByName[pComponentRecord->partName];
299 auto pComponent = std::make_shared<Component>(pComponentRecord->compName, pComponentRecord->partName, pPackage, index, pComponentsFile->GetSide(), pPart);
300
301 m_components.push_back(pComponent);
302 m_componentsByName[pComponent->GetRefDes()] = pComponent;
303 }
304
305 return true;
306 }
307
308 bool Design::BuildVias()
309 {
310 return false;
311 }
312
313 bool Design::BuildNets()
314 {
315 if (m_pFileModel == nullptr) return false;
316
317 const auto& steps = m_pFileModel->GetStepsByName();
318 if (steps.empty()) return false;
319
320 auto& pStepDirectory = steps.begin()->second;
321 const auto& edaData = pStepDirectory->GetEdaDataFile();
322 const auto& netRecords = edaData.GetNetRecords();
323
324 for (const auto& pNetRecord : netRecords)
325 {
326 auto pNet = std::make_shared<Net>(pNetRecord->name, pNetRecord->index);
327 m_nets.push_back(pNet);
328 m_netsByName[pNet->GetName()] = pNet;
329 }
330
331 return true;
332 }
333
334 bool Design::BuildPackages()
335 {
336 if (m_pFileModel == nullptr) return false;
337
338 const auto& steps = m_pFileModel->GetStepsByName();
339 if (steps.empty()) return false;
340
341 auto& pStepDirectory = steps.begin()->second;
342 const auto& edaData = pStepDirectory->GetEdaDataFile();
343 const auto& packageRecords = edaData.GetPackageRecords();
344
345 for (const auto& pPackageRecord : packageRecords)
346 {
347 auto index = pPackageRecord->index;
348 auto pPackage = std::make_shared<Package>(pPackageRecord->name, index);
349
350 for (const auto& pPinRecord : pPackageRecord->m_pinRecords)
351 {
352 // TODO: figure out how to handle size_t -> non-size_t conversion
353 pPackage->AddPin(pPinRecord->name);
354 }
355
356 m_packages.push_back(pPackage);
357 m_packagesByName[pPackage->GetName()] = pPackage;
358 }
359
360 return true;
361 }
362
363 bool Design::BuildAllParts()
364 {
365 if (m_pFileModel == nullptr) return false;
366
367 const auto& steps = m_pFileModel->GetStepsByName();
368 if (steps.empty()) return false;
369
370 auto& pStepDirectory = steps.begin()->second;
371
372 auto pTopComponentsFile = pStepDirectory->GetTopComponentsFile();
373 if (pTopComponentsFile == nullptr) return false;
374 if (! BuildParts(pTopComponentsFile)) return false;
375
376 auto pBottomComponentsFile = pStepDirectory->GetBottomComponentsFile();
377 if (pBottomComponentsFile == nullptr) return false;
378 if (! BuildParts(pBottomComponentsFile)) return false;
379
380 return true;
381 }
382
383 bool Design::BuildParts(const Odb::Lib::FileModel::Design::ComponentsFile* pComponentsFile)
384 {
385 const auto& componentRecords = pComponentsFile->GetComponentRecords();
386 for (const auto& pComponentRecord : componentRecords)
387 {
388 auto& partName = pComponentRecord->partName;
389 auto findIt = m_partsByName.find(partName);
390 if (findIt == m_partsByName.end())
391 {
392 auto pPart = std::make_shared<Part>(partName);
393 m_parts.push_back(pPart);
394 m_partsByName[partName] = pPart;
395 }
396 }
397
398 return true;
399 }
400
401 bool Design::BuildPlacementsFromComponentsFiles()
402 {
403 if (m_pFileModel == nullptr) return false;
404
405 const auto& steps = m_pFileModel->GetStepsByName();
406 if (steps.empty()) return false;
407
408 // "first" step when there are >1 steps
409 auto& pStepDirectory = steps.begin()->second;
410
411 auto pTopComponentsFile = pStepDirectory->GetTopComponentsFile();
412 if (pTopComponentsFile == nullptr) return false;
413 if (! BuildPlacementsFromComponentsFile(pTopComponentsFile)) return false;
414
415 auto pBottomComponentsFile = pStepDirectory->GetBottomComponentsFile();
416 if (pBottomComponentsFile == nullptr) return false;
417 if (!BuildPlacementsFromComponentsFile(pBottomComponentsFile)) return false;
418
419 return true;
420 }
421
422 bool Design::BuildPlacementsFromComponentsFile(const Odb::Lib::FileModel::Design::ComponentsFile* pComponentsFile)
423 {
424 const auto& componentRecords = pComponentsFile->GetComponentRecords();
425 for (const auto& pComponentRecord : componentRecords)
426 {
427 const auto& toeprintRecords = pComponentRecord->m_toeprintRecords;
428 for (const auto& pToeprintRecord : toeprintRecords)
429 {
430 auto& toeprintName = pToeprintRecord->name;
431 auto pinNumber = pToeprintRecord->pinNumber;
432 auto netNumber = pToeprintRecord->netNumber;
433 auto& refDes = pComponentRecord->compName;
434 //auto subnetNumber = pToeprintRecord->subnetNumber;
435
436 // -1 means no connection for the component pin
437 if (netNumber != static_cast<unsigned int>(-1))
438 {
439 if (!CreatePinConnection(refDes, netNumber, pinNumber, toeprintName)) return false;
440 }
441 }
442 }
443
444 return true;
445 }
446
447 bool Design::CreatePinConnection(const std::string& refDes, unsigned int netNumber, unsigned int pinNumber, const std::string& pinName)
448 {
449 if (netNumber < m_nets.size())
450 {
451 auto& pComponent = m_componentsByName[refDes];
452 if (pComponent == nullptr) return false;
453
454 auto pPin = pComponent->GetPackage()->GetPin(pinNumber);
455 if (pPin == nullptr) return false;
456
457 auto& pNet = m_nets[netNumber];
458 if (pNet == nullptr) return false;
459
460 if (!pNet->AddPinConnection(pComponent, pPin)) return false;
461 return true;
462 }
463 else
464 {
465 logwarn("netNumber out of range: " + std::to_string(netNumber) + ", size = " + std::to_string(m_nets.size()));
466 }
467
468 return false;
469 }
470
471 bool Design::BuildNoneNet()
472 {
473 auto pStepDirectory = m_pFileModel->GetStepDirectory();
474 if (pStepDirectory == nullptr) return false;
475
476 const auto& edaData = pStepDirectory->GetEdaDataFile();
477 auto findIt = edaData.GetNetRecordsByName().find(NONE_NET_NAME);
478 if (findIt == edaData.GetNetRecordsByName().end()) return false;
479
480 auto& pNoneNet = findIt->second;
481 if (pNoneNet == nullptr) return false;
482
483 if (!CreateNetConnections(pNoneNet, pStepDirectory)) return false;
484
485 return true;
486 }
487
488 bool Design::BreakSinglePinNets()
489 {
490 const auto& pNoneNet = GetNoneNet();
491 if (pNoneNet == nullptr) return false;
492
493 auto& pinConnections = pNoneNet->GetPinConnections();
494 while (!pinConnections.empty())
495 {
496 const auto& pExistingPinConnection = pinConnections.back();
497
498 std::string newNetName = "$NC_" + pExistingPinConnection->GetComponent()->GetRefDes() + "_" + pExistingPinConnection->GetPin()->GetName();
499 auto pNewNet = std::make_shared<Net>(newNetName, -1);
500 pNewNet->AddPinConnection(pExistingPinConnection->GetComponent(), pExistingPinConnection->GetPin());
501 m_nets.push_back(pNewNet);
502 m_netsByName[pNewNet->GetName()] = pNewNet;
503
504 pinConnections.pop_back();
505 }
506
507 return true;
508 }
509
510 bool Design::BuildPlacementsFromEdaDataFile()
511 {
512 auto pStepDirectory = m_pFileModel->GetStepDirectory();
513 if (pStepDirectory == nullptr) return false;
514
515 const auto& edaData = pStepDirectory->GetEdaDataFile();
516
517 for (const auto& pNetRecord : edaData.GetNetRecords())
518 {
519 if (!CreateNetConnections(pNetRecord, pStepDirectory)) return false;
520 }
521
522 return true;
523 }
524
525 bool Design::CreateNetConnections(const std::shared_ptr<Odb::Lib::FileModel::Design::EdaDataFile::NetRecord>& pNetRecord, const std::shared_ptr<FileModel::Design::StepDirectory>& pStepDirectory)
526 {
527 for (const auto& pSubnetRecord : pNetRecord->m_subnetRecords)
528 {
529 if (pSubnetRecord->type == FileModel::Design::EdaDataFile::NetRecord::SubnetRecord::Type::Toeprint)
530 {
531 const FileModel::Design::ComponentsFile* pComponentsFileToUse = nullptr;
532
533 auto side = pSubnetRecord->side;
534 if (side == BoardSide::Top)
535 {
536 pComponentsFileToUse = pStepDirectory->GetTopComponentsFile();
537 }
538 else //if (side == BoardSide::Bottom)
539 {
540 pComponentsFileToUse = pStepDirectory->GetBottomComponentsFile();
541 }
542
543 if (pComponentsFileToUse == nullptr) return false;
544
545 auto componentNumber = pSubnetRecord->componentNumber;
546 if (componentNumber >= pComponentsFileToUse->GetComponentRecords().size()) return false;
547
548 auto& pComponentRecord = pComponentsFileToUse->GetComponentRecords()[componentNumber];
549 if (pComponentRecord == nullptr) return false;
550
551 auto toeprintNumber = pSubnetRecord->toeprintNumber;
552 if (toeprintNumber >= pComponentRecord->m_toeprintRecords.size()) return false;
553
554 auto& pToeprintRecord = pComponentRecord->m_toeprintRecords[toeprintNumber];
555 if (pToeprintRecord == nullptr) return false;
556
557 auto& toeprintName = pToeprintRecord->name;
558 auto pinNumber = pToeprintRecord->pinNumber;
559 auto netNumber = pToeprintRecord->netNumber;
560 auto& refDes = pComponentRecord->compName;
561 //auto subnetNumber = pToeprintRecord->subnetNumber;
562
563 if (!CreatePinConnection(refDes, netNumber, pinNumber, toeprintName)) return false;
564 }
565 else if (pSubnetRecord->type == FileModel::Design::EdaDataFile::NetRecord::SubnetRecord::Type::Via)
566 {
567 // ?
568 }
569 }
570
571 return true;
572 }
573
574} // namespace Odb::Lib::ProductModel
void AssertAllStringFieldsAreValidUtf8(const google::protobuf::Message &msg, std::string_view msgName)
Debug-only assertion to verify all string fields in a message are valid UTF-8.