HAL  v4.5.0-83-g30c8f0afc
The Hardware Analyzer - a comprehensive reverse engineering and manipulation framework for gate-level netlists.
saleae_directory.cpp
Go to the documentation of this file.
1 #ifdef STANDALONE_PARSER
2 #include "saleae_directory.h"
3 #else
6 #endif
7 
8 #include "rapidjson/document.h"
9 #include "rapidjson/reader.h"
10 #include "rapidjson/filereadstream.h"
11 
12 #include <iostream>
13 #include <sstream>
14 
15 namespace hal
16 {
17 
18  SaleaeDirectory::SaleaeDirectory(const std::string &path, bool create)
19  : mDirectoryFile(path), mNextAvailableIndex(0), mStoreRequest(0)
20  {
21  if (create) return;
22  parse_json();
23  mById.clear();
24  mByName.clear();
25  int n = mNetEntries.size();
26  for (int i=0; i<n; i++)
27  {
28  const SaleaeDirectoryNetEntry& sdne = mNetEntries.at(i);
29  mByName.insert(std::make_pair(sdne.name(),i));
30  if (sdne.id()) mById.insert(std::make_pair(sdne.id(),i));
31  }
32  }
33 
35  {
36  for (const SaleaeDirectoryNetEntry& sdne : mNetEntries)
37  for (const SaleaeDirectoryFileIndex& sdfi : sdne.indexes())
38  {
39  std::string dfPath = get_datafile_path(sdfi.index());
40  std::remove(dfPath.c_str());
41  }
42  mNetEntries.clear();
43  mComposedEntryMap.clear();
44  mById.clear();
45  mByName.clear();
46  mNextAvailableIndex = 0;
47  mStoreRequest = 0;
48  std::remove(mDirectoryFile.c_str());
49  }
50 
52  {
53  FILE* ff = fopen(mDirectoryFile.c_str(), "rb");
54  if (!ff)
55  {
56  std::cerr << "cannot open SALEAE directory file <" << mDirectoryFile << ">" << std::endl;
57  return false;
58  }
59 
60  mNetEntries.clear();
61  mById.clear();
62  mByName.clear();
63 
64  char buffer[65536];
65  rapidjson::FileReadStream frs(ff, buffer, sizeof(buffer));
66  rapidjson::Document document;
67  document.ParseStream<0, rapidjson::UTF8<>, rapidjson::FileReadStream>(frs);
68  fclose(ff);
69 
70  if (document.HasParseError() || !document.HasMember("saleae"))
71  {
72  std::cerr << "cannot parse SALEAE directory file <" << mDirectoryFile << ">" << std::endl;
73  return false;
74  }
75  auto jsaleae = document["saleae"].GetObject();
76  if (jsaleae.HasMember("nets"))
77  {
78  for (auto& jnet : jsaleae["nets"].GetArray())
79  {
80  uint32_t id = 0;
81  std::string name;
82  if (jnet.HasMember("id")) id = jnet["id"].GetUint();
83  if (jnet.HasMember("name")) name = jnet["name"].GetString();
85  if (jnet.HasMember("indexes"))
86  {
87  for (auto& jinx : jnet["indexes"].GetArray())
88  {
89  int inx = jinx["index"].GetInt();
90  uint64_t tBeg = jinx["t_beg"].GetUint64();
91  uint64_t tEnd = jinx["t_end"].GetUint64();
92  uint64_t nVal = jinx["n_val"].GetUint64();
93  sdne.addIndex(SaleaeDirectoryFileIndex(inx, tBeg, tEnd, nVal));
94  if (inx >= mNextAvailableIndex) mNextAvailableIndex = inx + 1;
95  }
96  }
97  int n = mNetEntries.size();
98  mNetEntries.push_back(sdne);
99  if (id) mById.insert(std::make_pair(id,n));
100  mByName.insert(std::make_pair(name,n));
101  }
102  }
103 
104  // be backward compatible and read groups tag
105  if (jsaleae.HasMember("groups"))
106  {
107  for (auto& jgrp : jsaleae["groups"].GetArray())
108  {
109  uint32_t gid = 0;
110  std::string gname;
111  if (jgrp.HasMember("id")) gid = jgrp["id"].GetUint();
112  if (jgrp.HasMember("name")) gname = jgrp["name"].GetString();
114  if (jgrp.HasMember("nets"))
115  {
116  for (auto& jgnet : jgrp["nets"].GetArray())
117  {
118  uint32_t nid = jgnet["id"].GetInt();
119  sdce.add_child(nid);
120  }
121  }
122  mComposedEntryMap[sdce.uniqueKey()] = sdce;
123  }
124  }
125 
126  if (jsaleae.HasMember("composed"))
127  {
128  for (auto& jcmpsd : jsaleae["composed"].GetArray())
129  {
130  bool ok = true;
131  uint32_t id = 0;
132  std::string name;
134  if (jcmpsd.HasMember("id")) id = jcmpsd["id"].GetUint();
135  if (jcmpsd.HasMember("name")) name = jcmpsd["name"].GetString();
136  if (jcmpsd.HasMember("type")) tp = (SaleaeDirectoryNetEntry::Type) jcmpsd["type"].GetUint();
137  if (id && tp != SaleaeDirectoryNetEntry::None)
138  {
140  if (jcmpsd.HasMember("nets"))
141  {
142  for (auto& jgnet : jcmpsd["nets"].GetArray())
143  {
144  uint32_t nid = jgnet["id"].GetInt();
145  sdce.add_child(nid);
146  }
147  }
148  if (jcmpsd.HasMember("children"))
149  {
150  for (auto& jchld : jcmpsd["children"].GetArray())
151  {
152  sdce.add_child(jchld.GetInt());
153  }
154  }
155  if (jcmpsd.HasMember("data"))
156  {
157  std::vector<int> vdata;
158  for (auto& jdata : jcmpsd["data"].GetArray())
159  vdata.push_back(jdata.GetInt());
160  sdce.set_data(vdata);
161  }
162  else
163  {
165  ok = false;
166  }
167  if (jcmpsd.HasMember("filter"))
168  {
169  sdce.set_filter_entry(jcmpsd["filter"].GetInt());
170  }
171  mComposedEntryMap[sdce.uniqueKey()]=sdce;
172  }
173  }
174  }
175  return true;
176  }
177 
178 #ifndef STANDALONE_PARSER
179  bool SaleaeDirectory::write_json() const
180  {
181  JsonWriteDocument jwd;
182  JsonWriteObject& jsaleae = jwd.add_object("saleae");
183  JsonWriteArray& jnets = jsaleae.add_array("nets");
184  for (const SaleaeDirectoryNetEntry& net : mNetEntries)
185  {
186  JsonWriteObject& jnet = jnets.add_object();
187  jnet["id"] = (int) net.id();
188  jnet["name"] = net.name();
189  JsonWriteArray& jindexes = jnet.add_array("indexes");
190  for (const SaleaeDirectoryFileIndex& inx : net.indexes())
191  {
192  JsonWriteObject& jinx = jindexes.add_object();
193  jinx["index"] = inx.index();
194  jinx["t_beg"] = inx.beginTime();
195  jinx["t_end"] = inx.endTime();
196  jinx["n_val"] = inx.numberValues();
197  jinx.close();
198  }
199  jindexes.close();
200  jnet.close();
201  }
202  jnets.close();
203  if (!mComposedEntryMap.empty())
204  {
205  JsonWriteArray& jcmpsds = jsaleae.add_array(("composed"));
206  for (auto it=mComposedEntryMap.begin(); it!=mComposedEntryMap.end(); ++it)
207  {
208  const SaleaeDirectoryComposedEntry& cmpsd = it->second;
209  JsonWriteObject& jcmpsd = jcmpsds.add_object();
210  jcmpsd["id"] = (int) cmpsd.id();
211  jcmpsd["name"] = cmpsd.name();
212  jcmpsd["type"] = (int) cmpsd.type();
213  JsonWriteArray& jgnets = jcmpsd.add_array("children");
214  for (int childKey : cmpsd.get_children())
215  {
216  jgnets << childKey;
217  }
218  jgnets.close();
219  if (!cmpsd.get_data().empty())
220  {
221  JsonWriteArray& jdata = jcmpsd.add_array("data");
222  for (int dat : cmpsd.get_data())
223  jdata << dat;
224  jdata.close();
225  }
226  if (cmpsd.get_filter_entry())
227  {
228  jcmpsd["filter"] = cmpsd.get_filter_entry();
229  }
230  jcmpsd.close();
231  }
232  jcmpsds.close();
233  }
234  jsaleae.close();
235  return jwd.serialize(mDirectoryFile);
236  }
237 #endif
238 
239  std::vector<SaleaeDirectoryNetEntry> SaleaeDirectory::dump() const
240  {
241  // std::cout << "<" << mDirectoryFile << ">" << std::endl;
242  // for (const SaleaeDirectoryNetEntry& sdne : mNetEntries)
243  // {
244  // std::cout << sdne.name() << "[" << sdne.id() << "] :";
245  // for (const SaleaeDirectoryFileIndex& sdfi : sdne.indexes())
246  // std::cout << " <" << sdfi.index() << "," << sdfi.beginTime() << "," << sdfi.endTime() << "," << sdfi.numberValues() << ">";
247  // std::cout << std::endl;
248  // }
249  // std::cout << "---------------------" << std::endl;
250  return mNetEntries;
251  }
252 
253  void SaleaeDirectory::update_file_indexes(std::unordered_map<int,SaleaeDirectoryFileIndex>& fileIndexes)
254  {
255  for (SaleaeDirectoryNetEntry& sdne : mNetEntries)
256  {
257  if (sdne.mFileIndexes.empty()) continue;
258  int inx = sdne.mFileIndexes.back().index();
259  auto it = fileIndexes.find(inx);
260  if (it != fileIndexes.end())
261  {
262  sdne.mFileIndexes.pop_back();
263  sdne.mFileIndexes.push_back(it->second);
264  }
265  }
266  }
267 
269  {
270  int inetentry = -1;
271  if (sdne.id())
272  {
273  auto it = mById.find(sdne.id());
274  if (it != mById.end()) inetentry = it->second;
275  }
276  if (inetentry<0)
277  {
278  auto it = mByName.find(sdne.name());
279  if (it != mByName.end())
280  {
281  inetentry = it->second;
282  if (sdne.id() > 0)
283  mById.insert(std::make_pair(sdne.id(),inetentry));
284  }
285  }
286  if (inetentry<0)
287  {
288  int n = mNetEntries.size();
289  mByName.insert(std::make_pair(sdne.name(),n));
290  if (sdne.id()) mById.insert(std::make_pair(sdne.id(),n));
291  mNetEntries.push_back(sdne);
292  }
293  else
294  {
295  mNetEntries[inetentry] = sdne;
296  }
297  for (const SaleaeDirectoryFileIndex& sdfi : sdne.indexes())
298  if (sdfi.index() >= mNextAvailableIndex) mNextAvailableIndex = sdfi.index() + 1;
299  }
300 
302  {
304  }
305 
306  int SaleaeDirectory::getIndex(const SaleaeDirectoryNetEntry& sdnep) const
307  {
308  return sdnep.dataFileIndex();
309  }
310 
311  std::string SaleaeDirectory::get_datafile_path(const std::string& nam, uint32_t id) const
312  {
313  int index = get_datafile_index(nam, id);
314  if (index < 0) return std::string();
315  return get_datafile_path(index);
316  }
317 
318  int SaleaeDirectory::get_datafile_index(const std::string &nam, uint32_t id) const
319  {
320  if (id)
321  {
322  auto it = mById.find(id);
323  if (it != mById.end()) return getIndex(mNetEntries.at(it->second));
324  }
325  auto jt = mByName.find(nam);
326  if (jt == mByName.end()) return -1;
327  return getIndex(mNetEntries.at(jt->second));
328  }
329 
331  {
332  uint64_t retval = 0;
333  for (const SaleaeDirectoryNetEntry& sdne : mNetEntries)
334  {
335  for (const SaleaeDirectoryFileIndex& sdfi : sdne.indexes())
336  {
337  if (sdfi.endTime() > retval) retval = sdfi.endTime();
338  }
339  }
340  return retval;
341  }
342 
343  void SaleaeDirectory::rename_net(uint32_t id, const std::string& nam)
344  {
345 #ifndef STANDALONE_PARSER
347 #endif
348  auto it = mById.find(id);
349  if (it == mById.end()) return;
350  mNetEntries[it->second].rename(nam);
351  }
352 
353  std::vector<SaleaeDirectory::ListEntry> SaleaeDirectory::get_net_list() const
354  {
355  std::vector<ListEntry> retval;
356  for (const SaleaeDirectoryNetEntry& sdne : mNetEntries)
357  {
358  int inx = -1;
359  uint64_t size = 0;
360  for (const SaleaeDirectoryFileIndex& sdfi : sdne.indexes())
361  {
362  if (inx < 0) inx = sdfi.index();
363  size += sdfi.numberValues();
364  }
365  retval.push_back({sdne.id(),sdne.name(),inx,size});
366  }
367  return retval;
368  }
369 
371  {
372  if (mFileIndexes.empty()) return -1;
373  return mFileIndexes.back().index();
374  }
375 
377  {
378  if (index < 0) return std::string();
379  std::ostringstream fname;
380  fname << "digital_" << index << ".bin";
381  return fname.str();
382  }
383 
384  std::string SaleaeDirectory::get_directory() const
385  {
386  size_t pos = mDirectoryFile.find_last_of(folderSeparator);
387  if (pos==std::string::npos) return std::string();
388  return mDirectoryFile.substr(0,pos);
389  }
390 
391  std::string SaleaeDirectory::get_filename() const
392  {
393  return mDirectoryFile;
394  }
395 
397  : SaleaeDirectoryNetEntry(other), mChildKeys(other.mChildKeys), mData(other.mData), mFilterEntry(other.mFilterEntry)
398  {;}
399 
401  {;}
402 
403  void SaleaeDirectoryComposedEntry::set_data(const std::vector<int>& dat)
404  {
405  mData = dat;
406  }
407 
409  {
410  auto it = mChildKeys.begin();
411  while (it != mChildKeys.end())
412  {
413  if (*it == key)
414  it = mChildKeys.erase(it);
415  else
416  ++it;
417  }
418  }
419 
421  {
422  const char* ctype[] = {"None", "Group", "Boolean", "Trigger" };
423  std::cout << ctype[mType] << ": " << mId << " <" << mName << ">\n";
424  for (int childKey : mChildKeys)
425  std::cout << " <" << childKey << ">\n";
426  std::cout << "data:";
427  for (int x : mData) std::cout << " " << x;
428  std::cout << "\nfilter:";
429  if (mFilterEntry)
430  std::cout << " <" << mFilterEntry << ">\n";
431  else
432  std::cout << " ---\n";
433  std::cout << "=============" << std::endl;
434  }
435 
437  {
438  if (!mId) return 0;
439  return mType * sComposedBaseKey + mId;
440  }
441 
443  {
444 #ifndef STANDALONE_PARSER
446 #endif
447  mComposedEntryMap[sdce.uniqueKey()] = sdce;
448  }
449 
451  {
452 #ifndef STANDALONE_PARSER
454 #endif
455  SaleaeDirectoryComposedEntry needle("search",id,tp);
456  auto it = mComposedEntryMap.find(needle.uniqueKey());
457  if (it != mComposedEntryMap.end())
458  mComposedEntryMap.erase(it);
459  }
460 
462  {
463  SaleaeDirectoryComposedEntry needle("search",id,tp);
464  auto it = mComposedEntryMap.find(needle.uniqueKey());
465  if (it == mComposedEntryMap.end()) return SaleaeDirectoryComposedEntry();
466  return it->second;
467  }
468 
469  std::vector<SaleaeDirectoryComposedEntry> SaleaeDirectory::get_composed_list() const
470  {
471  std::vector<SaleaeDirectoryComposedEntry> retval;
472  for (auto it=mComposedEntryMap.begin(); it!=mComposedEntryMap.end(); ++it)
473  retval.push_back(it->second);
474  return retval;
475  }
476 
477 
478 #ifndef STANDALONE_PARSER
480 
481  SaleaeDirectoryStoreRequest::SaleaeDirectoryStoreRequest(SaleaeDirectory* sd)
482  : mSaleaeDirectory(sd)
483  {
484  ++mSaleaeDirectory->mStoreRequest;
485  }
486 
488  {
489  if (--mSaleaeDirectory->mStoreRequest <= 0)
490  {
491  if (!sWriteDisabled)
492  mSaleaeDirectory->write_json();
493  }
494  }
495 #endif
496 }
u32 size
JsonWriteObject & add_object()
bool serialize(const std::string &filename)
JsonWriteObject & add_object(const std::string &tag)
JsonWriteArray & add_array(const std::string &tag)
The SaleaeDirectoryComposedEntry class represents a composed waveform. There are currently three type...
void add_child(int key)
Add an additional child key to composed.
SaleaeDirectoryComposedEntry(const std::string nam=std::string(), uint32_t id_=0, Type tp=None)
void dump() const
Dump to stdout.
~SaleaeDirectoryComposedEntry()
void set_data(const std::vector< int > &dat)
Setter for data list described above.
void set_filter_entry(int filt)
Setter for filter pointer described above.
void remove_child(int key)
Remove child key from composed.
The SaleaeDirectoryFileIndex class represents a single SALEAE data file. The class comprises the inde...
The SaleaeDirectory class provides the API for the SALEAE directory file. The SALEAE directory file w...
void rename_net(uint32_t id, const std::string &nam)
Change waveform name entry for net identified by id.
int get_datafile_index(const std::string &nam, uint32_t id) const
Get waveform datafile index for net identified by name and id.
void clearAll()
Remove all files and reset internal variables.
void add_or_replace_net(SaleaeDirectoryNetEntry &sdne)
Add net entry if not yet existing, replace existing entry otherwise.
bool parse_json()
Parse .json file into class instance.
std::string get_directory() const
Get path to SALEAE directory without filename.
std::vector< SaleaeDirectoryNetEntry > dump() const
Dump content of class instance to console for debugging purpose.
std::string get_datafile_name(int index) const
Get waveform datafile name without path (digital_XXX.bin)
SaleaeDirectory(const std::string &path, bool create=false)
constructor
std::vector< SaleaeDirectoryComposedEntry > get_composed_list() const
Getter to list of all composed waveform entries.
void add_or_replace_composed(SaleaeDirectoryComposedEntry sdce)
Add composed waveform entry (Group, Boolean, Trigger)
void remove_composed(uint32_t id, SaleaeDirectoryNetEntry::Type tp)
Remove composed waveform entry identified by id an type.
void update_file_indexes(std::unordered_map< int, SaleaeDirectoryFileIndex > &fileIndexes)
Update file index information (like number of transitions, end time ...) after writing SALEAE files.
SaleaeDirectoryComposedEntry get_composed(uint32_t id, SaleaeDirectoryNetEntry::Type tp) const
Getter for pointer to composed waveform entry allowing modifications.
std::vector< ListEntry > get_net_list() const
Getter for all net entries.
std::string get_datafile_path(int index) const
Get full path to waveform data file.
std::string get_filename() const
Get full path to saleae directory file including filename (/.../saleae.json)
uint64_t get_max_time() const
Getter for maximum time.
The SaleaeDirectoryNetEntry class represents a regular waveform for a single simulated net....
int dataFileIndex() const
Return last data file index (currently there should be no more than one)
Type mType
Type
@ Boolean
@ Trigger
@ None
@ Group
int uniqueKey() const
Unique key as reference (used e.g. in mComposedEntryMap)
uint32_t id() const
Getter for waveform ID = simulated net ID.
std::string mName
const std::vector< SaleaeDirectoryFileIndex > & indexes() const
Getter for list of associated binary files indexes.
std::vector< SaleaeDirectoryFileIndex > mFileIndexes
uint32_t mId
static const int sComposedBaseKey
void addIndex(const SaleaeDirectoryFileIndex &sdfe)
Add index for binary file to net entry instance.
std::string name() const
Getter for waveform name.
The SaleaeDirectoryStoreRequest class is useful to bundle requests for updating SALEAE directory....
void remove(std::filesystem::path file_path)
bool save(std::filesystem::path file_path, GateLibrary *gate_lib, bool overwrite=false)
Definition: defines.h:45
Net * net
std::string name
const char folderSeparator