KiCad PCB EDA Suite
pcbnew/cross-probing.cpp
Go to the documentation of this file.
1 /*
2  * This program source code file is part of KiCad, a free EDA CAD application.
3  *
4  * Copyright (C) 2019-2020 KiCad Developers, see AUTHORS.txt for contributors.
5  *
6  * This program is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU General Public License
8  * as published by the Free Software Foundation; either version 2
9  * of the License, or (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, you may find one here:
18  * http://www.gnu.org/licenses/old-licenses/gpl-3.0.html
19  * or you may search the http://www.gnu.org website for the version 2 license,
20  * or you may write to the Free Software Foundation, Inc.,
21  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
22  */
23 
24 
34 #include <class_board.h>
35 #include <class_module.h>
36 #include <class_track.h>
37 #include <class_zone.h>
38 #include <collectors.h>
39 #include <eda_dde.h>
40 #include <fctsys.h>
41 #include <kiface_i.h>
42 #include <kiway_express.h>
43 #include <macros.h>
45 #include <pcb_edit_frame.h>
46 #include <pcb_painter.h>
47 #include <pcbnew.h>
48 #include <pcbnew_settings.h>
49 #include <pgm_base.h>
50 #include <tool/tool_manager.h>
51 #include <tools/pcb_actions.h>
52 #include <tools/selection_tool.h>
53 #include <wx/tokenzr.h>
54 
55 /* Execute a remote command send by Eeschema via a socket,
56  * port KICAD_PCB_PORT_SERVICE_NUMBER
57  * cmdline = received command from Eeschema
58  * Commands are
59  * $PART: "reference" put cursor on component
60  * $PIN: "pin name" $PART: "reference" put cursor on the footprint pin
61  * $NET: "net name" highlight the given net (if highlight tool is active)
62  * $CLEAR Clear existing highlight
63  * They are a keyword followed by a quoted string.
64  */
65 void PCB_EDIT_FRAME::ExecuteRemoteCommand( const char* cmdline )
66 {
67  char line[1024];
68  wxString msg;
69  wxString modName;
70  char* idcmd;
71  char* text;
72  int netcode = -1;
73  bool multiHighlight = false;
74  MODULE* module = NULL;
75  D_PAD* pad = NULL;
76  BOARD* pcb = GetBoard();
77 
78  CROSS_PROBING_SETTINGS& crossProbingSettings = GetPcbNewSettings()->m_CrossProbing;
79 
81  KIGFX::RENDER_SETTINGS* renderSettings = view->GetPainter()->GetSettings();
82 
83  strncpy( line, cmdline, sizeof(line) - 1 );
84  line[sizeof(line) - 1] = 0;
85 
86  idcmd = strtok( line, " \n\r" );
87  text = strtok( NULL, "\"\n\r" );
88 
89  if( idcmd == NULL )
90  return;
91 
92  if( strcmp( idcmd, "$NET:" ) == 0 )
93  {
94  if( !crossProbingSettings.auto_highlight )
95  return;
96 
97  wxString net_name = FROM_UTF8( text );
98 
99  NETINFO_ITEM* netinfo = pcb->FindNet( net_name );
100 
101  if( netinfo )
102  {
103  netcode = netinfo->GetNet();
104 
105  MSG_PANEL_ITEMS items;
106  netinfo->GetMsgPanelInfo( this, items );
107  SetMsgPanel( items );
108  }
109  }
110  if( strcmp( idcmd, "$NETS:" ) == 0 )
111  {
112  if( !crossProbingSettings.auto_highlight )
113  return;
114 
115  wxStringTokenizer netsTok = wxStringTokenizer( FROM_UTF8( text ), "," );
116  bool first = true;
117 
118  while( netsTok.HasMoreTokens() )
119  {
120  NETINFO_ITEM* netinfo = pcb->FindNet( netsTok.GetNextToken() );
121 
122  if( netinfo )
123  {
124  if( first )
125  {
126  // TODO: Once buses are included in netlist, show bus name
127  MSG_PANEL_ITEMS items;
128  netinfo->GetMsgPanelInfo( this, items );
129  SetMsgPanel( items );
130  first = false;
131 
132  pcb->SetHighLightNet( netinfo->GetNet() );
133  renderSettings->SetHighlight( true, netinfo->GetNet() );
134  multiHighlight = true;
135  }
136  else
137  {
138  pcb->SetHighLightNet( netinfo->GetNet(), true );
139  renderSettings->SetHighlight( true, netinfo->GetNet(), true );
140  }
141  }
142  }
143 
144  netcode = -1;
145  }
146  else if( strcmp( idcmd, "$PIN:" ) == 0 )
147  {
148  wxString pinName = FROM_UTF8( text );
149 
150  text = strtok( NULL, " \n\r" );
151 
152  if( text && strcmp( text, "$PART:" ) == 0 )
153  text = strtok( NULL, "\"\n\r" );
154 
155  modName = FROM_UTF8( text );
156 
157  module = pcb->FindModuleByReference( modName );
158 
159  if( module )
160  pad = module->FindPadByName( pinName );
161 
162  if( pad )
163  netcode = pad->GetNetCode();
164 
165  if( module == NULL )
166  msg.Printf( _( "%s not found" ), modName );
167  else if( pad == NULL )
168  msg.Printf( _( "%s pin %s not found" ), modName, pinName );
169  else
170  msg.Printf( _( "%s pin %s found" ), modName, pinName );
171 
172  SetStatusText( msg );
173  }
174  else if( strcmp( idcmd, "$PART:" ) == 0 )
175  {
176  pcb->ResetNetHighLight();
177 
178  modName = FROM_UTF8( text );
179 
180  module = pcb->FindModuleByReference( modName );
181 
182  if( module )
183  msg.Printf( _( "%s found" ), modName );
184  else
185  msg.Printf( _( "%s not found" ), modName );
186 
187  SetStatusText( msg );
188  }
189  else if( strcmp( idcmd, "$SHEET:" ) == 0 )
190  {
191  msg.Printf( _( "Selecting all from sheet \"%s\"" ), FROM_UTF8( text ) );
192  wxString sheetUIID( FROM_UTF8( text ) );
193  SetStatusText( msg );
195  static_cast<void*>( &sheetUIID ) );
196  return;
197  }
198  else if( strcmp( idcmd, "$CLEAR" ) == 0 )
199  {
200  renderSettings->SetHighlight( false );
201  view->UpdateAllLayersColor();
202 
203  pcb->ResetNetHighLight();
204  SetMsgPanel( pcb );
205 
206  GetCanvas()->Refresh();
207  return;
208  }
209 
210  BOX2I bbox = { { 0, 0 }, { 0, 0 } };
211 
212  if( module )
213  {
214  bbox = module->GetBoundingBox();
215 
216  if( pad )
217  m_toolManager->RunAction( PCB_ACTIONS::highlightItem, true, (void*) pad );
218  else
219  m_toolManager->RunAction( PCB_ACTIONS::highlightItem, true, (void*) module );
220  }
221  else if( netcode > 0 || multiHighlight )
222  {
223  if( !multiHighlight )
224  {
225  renderSettings->SetHighlight( ( netcode >= 0 ), netcode );
226  pcb->SetHighLightNet( netcode );
227  }
228  else
229  {
230  // Just pick the first one for area calculation
231  netcode = *pcb->GetHighLightNetCodes().begin();
232  }
233 
234  pcb->HighLightON();
235 
236  auto merge_area = [netcode, &bbox]( BOARD_CONNECTED_ITEM* aItem )
237  {
238  if( aItem->GetNetCode() == netcode )
239  {
240  if( bbox.GetWidth() == 0 )
241  bbox = aItem->GetBoundingBox();
242  else
243  bbox.Merge( aItem->GetBoundingBox() );
244  }
245  };
246 
247  if( crossProbingSettings.center_on_items )
248  {
249  for( auto zone : pcb->Zones() )
250  merge_area( zone );
251 
252  for( auto track : pcb->Tracks() )
253  merge_area( track );
254 
255  for( auto mod : pcb->Modules() )
256  for( auto mod_pad : mod->Pads() )
257  merge_area( mod_pad );
258  }
259  }
260  else
261  {
262  renderSettings->SetHighlight( false );
263  }
264 
265  if( crossProbingSettings.center_on_items && bbox.GetWidth() > 0 && bbox.GetHeight() > 0 )
266  {
267  auto bbSize = bbox.Inflate( bbox.GetWidth() * 0.2f ).GetSize();
268  auto screenSize = view->ToWorld( GetCanvas()->GetClientSize(), false );
269  screenSize.x = std::max( 10.0, screenSize.x );
270  screenSize.y = std::max( 10.0, screenSize.y );
271  double ratio = std::max( fabs( bbSize.x / screenSize.x ),
272  fabs( bbSize.y / screenSize.y ) );
273 
274  // Try not to zoom on every cross-probe; it gets very noisy
275  if( crossProbingSettings.zoom_to_fit && ( ratio < 0.1 || ratio > 1.0 ) )
276  view->SetScale( view->GetScale() / ratio );
277 
278  view->SetCenter( bbox.Centre() );
279  }
280 
281  view->UpdateAllLayersColor();
282  // Ensure the display is refreshed, because in some installs the refresh is done only
283  // when the gal canvas has the focus, and that is not the case when crossprobing from
284  // Eeschema:
285  GetCanvas()->Refresh();
286 }
287 
288 
289 std::string FormatProbeItem( BOARD_ITEM* aItem )
290 {
291  MODULE* module;
292 
293  if( !aItem )
294  return "$CLEAR: \"HIGHLIGHTED\""; // message to clear highlight state
295 
296  switch( aItem->Type() )
297  {
298  case PCB_MODULE_T:
299  module = (MODULE*) aItem;
300  return StrPrintf( "$PART: \"%s\"", TO_UTF8( module->GetReference() ) );
301 
302  case PCB_PAD_T:
303  {
304  module = (MODULE*) aItem->GetParent();
305  wxString pad = ((D_PAD*)aItem)->GetName();
306 
307  return StrPrintf( "$PART: \"%s\" $PAD: \"%s\"",
308  TO_UTF8( module->GetReference() ),
309  TO_UTF8( pad ) );
310  }
311 
312  case PCB_MODULE_TEXT_T:
313  {
314  module = static_cast<MODULE*>( aItem->GetParent() );
315 
316  TEXTE_MODULE* text_mod = static_cast<TEXTE_MODULE*>( aItem );
317 
318  const char* text_key;
319 
320  /* This can't be a switch since the break need to pull out
321  * from the outer switch! */
322  if( text_mod->GetType() == TEXTE_MODULE::TEXT_is_REFERENCE )
323  text_key = "$REF:";
324  else if( text_mod->GetType() == TEXTE_MODULE::TEXT_is_VALUE )
325  text_key = "$VAL:";
326  else
327  break;
328 
329  return StrPrintf( "$PART: \"%s\" %s \"%s\"",
330  TO_UTF8( module->GetReference() ),
331  text_key,
332  TO_UTF8( text_mod->GetText() ) );
333  }
334 
335  default:
336  break;
337  }
338 
339  return "";
340 }
341 
342 
343 /* Send a remote command to Eeschema via a socket,
344  * aSyncItem = item to be located on schematic (module, pin or text)
345  * Commands are
346  * $PART: "reference" put cursor on component anchor
347  * $PART: "reference" $PAD: "pad number" put cursor on the component pin
348  * $PART: "reference" $REF: "reference" put cursor on the component ref
349  * $PART: "reference" $VAL: "value" put cursor on the component value
350  */
352 {
353  std::string packet = FormatProbeItem( aSyncItem );
354 
355  if( !packet.empty() )
356  {
357  if( Kiface().IsSingle() )
358  SendCommand( MSG_TO_SCH, packet.c_str() );
359  else
360  {
361  // Typically ExpressMail is going to be s-expression packets, but since
362  // we have existing interpreter of the cross probe packet on the other
363  // side in place, we use that here.
364  Kiway().ExpressMail( FRAME_SCH, MAIL_CROSS_PROBE, packet, this );
365  }
366  }
367 }
368 
369 
370 void PCB_EDIT_FRAME::SendCrossProbeNetName( const wxString& aNetName )
371 {
372  std::string packet = StrPrintf( "$NET: \"%s\"", TO_UTF8( aNetName ) );
373 
374  if( !packet.empty() )
375  {
376  if( Kiface().IsSingle() )
377  SendCommand( MSG_TO_SCH, packet.c_str() );
378  else
379  {
380  // Typically ExpressMail is going to be s-expression packets, but since
381  // we have existing interpreter of the cross probe packet on the other
382  // side in place, we use that here.
383  Kiway().ExpressMail( FRAME_SCH, MAIL_CROSS_PROBE, packet, this );
384  }
385  }
386 }
387 
388 
390 {
391  std::string& payload = mail.GetPayload();
392 
393  switch( mail.Command() )
394  {
396  {
397  NETLIST netlist;
398  STRING_FORMATTER sf;
399  for( auto& module : this->GetBoard()->Modules() )
400  {
401  netlist.AddComponent( new COMPONENT( module->GetFPID(), module->GetReference(),
402  module->GetValue(), module->GetPath() ) );
403  }
404  netlist.Format(
405  "pcb_netlist", &sf, 0, CTL_OMIT_FILTERS | CTL_OMIT_NETS | CTL_OMIT_FILTERS );
406  payload = sf.GetString();
407  break;
408  }
409  case MAIL_CROSS_PROBE:
410  ExecuteRemoteCommand( payload.c_str() );
411  break;
412 
413  case MAIL_PCB_UPDATE:
415  break;
416 
417  case MAIL_IMPORT_FILE:
418  {
419  // Extract file format type and path (plugin type and path separated with \n)
420  size_t split = payload.find( '\n' );
421  wxCHECK( split != std::string::npos, /*void*/ );
422  int importFormat;
423 
424  try
425  {
426  importFormat = std::stoi( payload.substr( 0, split ) );
427  }
428  catch( std::invalid_argument& )
429  {
430  wxFAIL;
431  importFormat = -1;
432  }
433 
434  std::string path = payload.substr( split + 1 );
435  wxASSERT( !path.empty() );
436 
437  if( importFormat >= 0 )
438  importFile( path, importFormat );
439 
440  break;
441  }
442 
443  // many many others.
444  default:
445  ;
446  }
447 }
448 
NETINFO_ITEM * FindNet(int aNetcode) const
Function FindNet searches for a net with the given netcode.
KIGFX::VIEW * GetView() const
Definition: tool_manager.h:284
KIWAY_EXPRESS carries a payload from one KIWAY_PLAYER to another within a PROJECT.
Definition: kiway_express.h:39
KIWAY & Kiway() const
Function Kiway returns a reference to the KIWAY that this object has an opportunity to participate in...
Definition: kiway_holder.h:56
int GetNetCode() const
Function GetNetCode.
DDE server & client.
void SendCrossProbeNetName(const wxString &aNetName)
Sends a net name to eeschema for highlighting.
int StrPrintf(std::string *aResult, const char *aFormat,...)
Function StrPrintf is like sprintf() but the output is appended to a std::string instead of to a char...
Definition: richio.cpp:74
static wxString FROM_UTF8(const char *cstring)
function FROM_UTF8 converts a UTF8 encoded C string to a wxString for all wxWidgets build modes.
Definition: macros.h:114
bool importFile(const wxString &aFileName, int aFileType)
Load the given filename but sets the path to the current project path.
RENDER_SETTINGS Contains all the knowledge about how graphical objects are drawn on any output surfac...
void HighLightON(bool aValue=true)
Enable or disable net highlighting.
BOARD_ITEM is a base class for any item which can be embedded within the BOARD container class,...
VECTOR2D ToWorld(const VECTOR2D &aCoord, bool aAbsolute=true) const
Function ToWorld() Converts a screen space point/vector to a point/vector in world space coordinates.
Definition: view.cpp:475
static TOOL_ACTION highlightItem
Definition: pcb_actions.h:409
#define MSG_TO_SCH
Definition: eda_dde.h:46
PCB_DRAW_PANEL_GAL * GetCanvas() const override
Return a pointer to GAL-based canvas of given EDA draw frame.
bool RunAction(const std::string &aActionName, bool aNow=false, T aParam=NULL)
Function RunAction() Runs the specified action.
Definition: tool_manager.h:140
class D_PAD, a pad in a footprint
Definition: typeinfo.h:90
static TOOL_ACTION updatePcbFromSchematic
Definition: actions.h:156
Fetch a netlist from PCB layout.
Definition: mail_type.h:47
bool SendCommand(int service, const char *cmdline)
Definition: eda_dde.cpp:132
PCBNEW_SETTINGS * GetPcbNewSettings()
BOARD_CONNECTED_ITEM is a base class derived from BOARD_ITEM for items that can be connected and have...
PAINTER * GetPainter() const
Function GetPainter() Returns the painter object used by the view for drawing VIEW_ITEMS.
Definition: view.h:199
A single base class (TRACK) represents both tracks and vias, with subclasses for curved tracks (ARC) ...
This file contains miscellaneous commonly used macros and functions.
const wxString GetReference() const
Function GetReference.
Definition: class_module.h:433
void AddComponent(COMPONENT *aComponent)
Function AddComponent adds aComponent to the NETLIST.
void KiwayMailIn(KIWAY_EXPRESS &aEvent) override
Function KiwayMailIn receives KIWAY_EXPRESS messages from other players.
Cross-probing behavior.
Definition: app_settings.h:30
class MODULE, a footprint
Definition: typeinfo.h:89
const EDA_RECT GetBoundingBox() const override
Function GetBoundingBox returns the orthogonal, bounding box of this object for display purposes.
D_PAD * FindPadByName(const wxString &aPadName) const
Function FindPadByName returns a D_PAD* with a matching name.
void ResetNetHighLight()
Function ResetNetHighLight Reset all high light data to the init state.
void SetCenter(const VECTOR2D &aCenter)
Function SetCenter() Sets the center point of the VIEW (i.e.
Definition: view.cpp:604
NETLIST stores all of information read from a netlist along with the flags used to update the NETLIST...
Definition: pcb_netlist.h:212
#define NULL
bool IsSingle() const
Function IsSingle is this KIFACE_I running under single_top?
Definition: kiface_i.h:117
MODULES & Modules()
Definition: class_board.h:266
void SetMsgPanel(const std::vector< MSG_PANEL_ITEM > &aList)
Clear the message panel and populates it with the contents of aList.
void ExecuteRemoteCommand(const char *cmdline) override
Execute a remote command send by Eeschema via a socket, port KICAD_PCB_PORT_SERVICE_NUMBER (currently...
coord_type GetWidth() const
Definition: box2.h:196
#define CTL_OMIT_FILTERS
Definition: pcb_netlist.h:349
KIFACE_I & Kiface()
Global KIFACE_I "get" accessor.
const std::string & GetString()
Definition: richio.h:475
void SetHighLightNet(int aNetCode, bool aMulti=false)
Function SetHighLightNet Select the netcode to be highlighted.
BOX2< Vec > & Merge(const BOX2< Vec > &aRect)
Function Merge modifies the position and size of the rectangle in order to contain aRect.
Definition: box2.h:385
#define CTL_OMIT_NETS
Omit pads net names (useless in library)
std::string FormatProbeItem(BOARD_ITEM *aItem)
virtual void Refresh(bool aEraseBackground=true, const wxRect *aRect=NULL) override
Update the board display after modifying it by a python script (note: it is automatically called by a...
bool zoom_to_fit
Zoom to fit items (ignored if center_on_items is off)
Definition: app_settings.h:33
COMPONENT is used to store components and all of their related information found in a netlist.
Definition: pcb_netlist.h:80
const std::set< int > & GetHighLightNetCodes() const
Function GetHighLightNetCode.
Definition: class_board.h:397
virtual void SetScale(double aScale, VECTOR2D aAnchor={ 0, 0 })
Function SetScale() Sets the scaling factor, zooming around a given anchor point.
Definition: view.cpp:578
class TEXTE_MODULE, text in a footprint
Definition: typeinfo.h:93
VTBL_ENTRY void ExpressMail(FRAME_T aDestination, MAIL_T aCommand, std::string &aPayload, wxWindow *aSource=NULL)
Function ExpressMail send aPayload to aDestination from aSource.
Definition: kiway.cpp:428
void SendMessageToEESCHEMA(BOARD_ITEM *objectToSync)
Function SendMessageToEESCHEMA sends a message to the schematic editor so that it may move its cursor...
virtual RENDER_SETTINGS * GetSettings()=0
Function GetAdapter Returns pointer to current settings that are going to be used when drawing items.
bool auto_highlight
Automatically turn on highlight mode in the target frame.
Definition: app_settings.h:34
NETINFO_ITEM handles the data for a net.
Definition: netinfo.h:65
BOX2< Vec > & Inflate(coord_type dx, coord_type dy)
Function Inflate inflates the rectangle horizontally by dx and vertically by dy.
Definition: box2.h:301
ZONE_CONTAINERS & Zones()
Definition: class_board.h:280
TOOL_MANAGER * m_toolManager
Definition: tools_holder.h:48
see class PGM_BASE
void SetHighlight(bool aEnabled, int aNetcode=-1, bool aMulti=false)
Function SetHighlight Turns on/off highlighting - it may be done for the active layer or the specifie...
Vec Centre() const
Definition: box2.h:78
int GetNet() const
Function GetNet.
Definition: netinfo.h:223
static TOOL_ACTION selectOnSheetFromEeschema
Selects all components on sheet from Eeschema crossprobing.
Definition: pcb_actions.h:83
Import a different format file.
Definition: mail_type.h:45
BOARD holds information pertinent to a Pcbnew printed circuit board.
Definition: class_board.h:180
#define _(s)
Definition: 3d_actions.cpp:33
void Format(const char *aDocName, OUTPUTFORMATTER *aOut, int aNestLevel, int aCtl=0)
#define TO_UTF8(wxstring)
coord_type GetHeight() const
Definition: box2.h:197
MODULE * FindModuleByReference(const wxString &aReference) const
Function FindModuleByReference searches for a MODULE within this board with the given reference desig...
std::vector< MSG_PANEL_ITEM > MSG_PANEL_ITEMS
Definition: msgpanel.h:102
PCB<->SCH, CVPCB->SCH cross-probing.
Definition: mail_type.h:39
TOOL_MANAGER * GetToolManager() const
Return the MVC controller.
Definition: tools_holder.h:74
BOARD * GetBoard() const
CROSS_PROBING_SETTINGS m_CrossProbing
Definition: app_settings.h:141
VIEW.
Definition: view.h:61
void GetMsgPanelInfo(EDA_DRAW_FRAME *aFrame, std::vector< MSG_PANEL_ITEM > &aList) override
Function GetMsgPanelInfo returns the information about the NETINFO_ITEM in aList to display in the me...
MAIL_T Command()
Function Command returns the MAIL_T associated with this mail.
Definition: kiway_express.h:52
void UpdateAllLayersColor()
Function UpdateAllLayersColor() Applies the new coloring scheme to all layers.
Definition: view.cpp:798
double GetScale() const
Function GetScale()
Definition: view.h:257
BOARD_ITEM_CONTAINER * GetParent() const
bool center_on_items
Automatically pan to cross-probed items.
Definition: app_settings.h:32
STRING_FORMATTER implements OUTPUTFORMATTER to a memory buffer.
Definition: richio.h:445
std::string & GetPayload()
Function Payload returns the payload, which can be any text but it typicall self identifying s-expres...
Definition: kiway_express.h:62
SCH->PCB forward update.
Definition: mail_type.h:43
TRACKS & Tracks()
Definition: class_board.h:257
KICAD_T Type() const
Function Type()
Definition: base_struct.h:193