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 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 
37 #include <fctsys.h>
38 #include <pgm_base.h>
39 #include <kiface_i.h>
40 #include <kiway_express.h>
41 #include <pcb_edit_frame.h>
42 #include <eda_dde.h>
43 #include <macros.h>
44 
45 #include <pcbnew_id.h>
46 #include <class_board.h>
47 #include <class_module.h>
48 #include <class_track.h>
49 #include <class_zone.h>
50 
51 #include <collectors.h>
52 #include <pcbnew.h>
53 #include <board_netlist_updater.h>
54 #include <netlist_reader.h>
55 #include <pcb_netlist.h>
57 
58 #include <tools/pcb_actions.h>
59 #include <tool/tool_manager.h>
60 #include <tools/selection_tool.h>
61 #include <pcb_draw_panel_gal.h>
62 #include <pcb_painter.h>
63 
64 /* Execute a remote command send by Eeschema via a socket,
65  * port KICAD_PCB_PORT_SERVICE_NUMBER
66  * cmdline = received command from Eeschema
67  * Commands are
68  * $PART: "reference" put cursor on component
69  * $PIN: "pin name" $PART: "reference" put cursor on the footprint pin
70  * $NET: "net name" highlight the given net (if highlight tool is active)
71  * They are a keyword followed by a quoted string.
72  */
73 void PCB_EDIT_FRAME::ExecuteRemoteCommand( const char* cmdline )
74 {
75  char line[1024];
76  wxString msg;
77  wxString modName;
78  char* idcmd;
79  char* text;
80  MODULE* module = NULL;
81  D_PAD* pad = NULL;
82  BOARD* pcb = GetBoard();
83  wxPoint pos;
84 
85  strncpy( line, cmdline, sizeof(line) - 1 );
86  line[sizeof(line) - 1] = 0;
87 
88  idcmd = strtok( line, " \n\r" );
89  text = strtok( NULL, "\"\n\r" );
90 
91  if( idcmd == NULL )
92  return;
93 
94  if( strcmp( idcmd, "$NET:" ) == 0 )
95  {
97  {
98  wxString net_name = FROM_UTF8( text );
99  NETINFO_ITEM* netinfo = pcb->FindNet( net_name );
100  int netcode = 0;
101 
102  if( netinfo )
103  netcode = netinfo->GetNet();
104 
105  if( IsGalCanvasActive() )
106  {
107  auto view = m_toolManager->GetView();
108  auto rs = view->GetPainter()->GetSettings();
109  rs->SetHighlight( true, netcode );
110  view->UpdateAllLayersColor();
111 
112  BOX2I bbox;
113  bool first = true;
114 
115  auto merge_area = [netcode, &bbox, &first]( BOARD_CONNECTED_ITEM* aItem )
116  {
117  if( aItem->GetNetCode() == netcode )
118  {
119  if( first )
120  {
121  bbox = aItem->GetBoundingBox();
122  first = false;
123  }
124  else
125  {
126  bbox.Merge( aItem->GetBoundingBox() );
127  }
128  }
129  };
130 
131  for( auto zone : pcb->Zones() )
132  merge_area( zone );
133 
134  for( auto track : pcb->Tracks() )
135  merge_area( track );
136 
137  for( auto mod : pcb->Modules() )
138  for ( auto mod_pad : mod->Pads() )
139  merge_area( mod_pad );
140 
141  if( netcode > 0 && bbox.GetWidth() > 0 && bbox.GetHeight() > 0 )
142  {
143  auto bbSize = bbox.Inflate( bbox.GetWidth() * 0.2f ).GetSize();
144  auto screenSize = view->ToWorld( GetGalCanvas()->GetClientSize(), false );
145  double ratio = std::max( fabs( bbSize.x / screenSize.x ),
146  fabs( bbSize.y / screenSize.y ) );
147  double scale = view->GetScale() / ratio;
148 
149  view->SetScale( scale );
150  view->SetCenter( bbox.Centre() );
151  }
152 
153  GetGalCanvas()->Refresh();
154  }
155  else
156  {
157  if( netcode > 0 )
158  {
159  pcb->HighLightON();
160  pcb->SetHighLightNet( netcode );
161  }
162  else
163  {
164  pcb->HighLightOFF();
165  pcb->SetHighLightNet( -1 );
166  }
167  }
168  }
169 
170  return;
171  }
172 
173  if( text == NULL )
174  return;
175 
176  if( strcmp( idcmd, "$PART:" ) == 0 )
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  if( module )
190  pos = module->GetPosition();
191  }
192  else if( strcmp( idcmd, "$SHEET:" ) == 0 )
193  {
194  msg.Printf( _( "Selecting all from sheet \"%s\"" ), FROM_UTF8( text ) );
195  wxString sheetStamp( FROM_UTF8( text ) );
196  SetStatusText( msg );
198  static_cast<void*>( &sheetStamp ) );
199  return;
200  }
201  else if( strcmp( idcmd, "$PIN:" ) == 0 )
202  {
203  wxString pinName;
204  int netcode = -1;
205 
206  pinName = FROM_UTF8( text );
207 
208  text = strtok( NULL, " \n\r" );
209 
210  if( text && strcmp( text, "$PART:" ) == 0 )
211  text = strtok( NULL, "\"\n\r" );
212 
213  modName = FROM_UTF8( text );
214 
215  module = pcb->FindModuleByReference( modName );
216 
217  if( module )
218  pad = module->FindPadByName( pinName );
219 
220  if( pad )
221  {
222  netcode = pad->GetNetCode();
223 
224  // put cursor on the pad:
225  pos = pad->GetPosition();
226  }
227 
228  if( netcode > 0 ) // highlight the pad net
229  {
230  pcb->HighLightON();
231  pcb->SetHighLightNet( netcode );
232  }
233  else
234  {
235  pcb->HighLightOFF();
236  pcb->SetHighLightNet( -1 );
237  }
238 
239  if( module == NULL )
240  {
241  msg.Printf( _( "%s not found" ), modName );
242  }
243  else if( pad == NULL )
244  {
245  msg.Printf( _( "%s pin %s not found" ), modName, pinName );
246  SetCurItem( module );
247  }
248  else
249  {
250  msg.Printf( _( "%s pin %s found" ), modName, pinName );
251  SetCurItem( pad );
252  }
253 
254  SetStatusText( msg );
255  }
256 
257  if( module ) // if found, center the module on screen, and redraw the screen.
258  {
259  if( IsGalCanvasActive() )
260  {
262  true,
263  pad ?
264  static_cast<BOARD_ITEM*>( pad ) :
265  static_cast<BOARD_ITEM*>( module )
266  );
267  }
268  else
269  {
270  SetCrossHairPosition( pos );
271  RedrawScreen( pos, false );
272  }
273  }
274 }
275 
276 
277 std::string FormatProbeItem( BOARD_ITEM* aItem )
278 {
279  MODULE* module;
280 
281  if( !aItem )
282  return "$CLEAR: \"HIGHLIGHTED\""; // message to clear highlight state
283 
284  switch( aItem->Type() )
285  {
286  case PCB_MODULE_T:
287  module = (MODULE*) aItem;
288  return StrPrintf( "$PART: \"%s\"", TO_UTF8( module->GetReference() ) );
289 
290  case PCB_PAD_T:
291  {
292  module = (MODULE*) aItem->GetParent();
293  wxString pad = ((D_PAD*)aItem)->GetName();
294 
295  return StrPrintf( "$PART: \"%s\" $PAD: \"%s\"",
296  TO_UTF8( module->GetReference() ),
297  TO_UTF8( pad ) );
298  }
299 
300  case PCB_MODULE_TEXT_T:
301  {
302  module = static_cast<MODULE*>( aItem->GetParent() );
303 
304  TEXTE_MODULE* text_mod = static_cast<TEXTE_MODULE*>( aItem );
305 
306  const char* text_key;
307 
308  /* This can't be a switch since the break need to pull out
309  * from the outer switch! */
310  if( text_mod->GetType() == TEXTE_MODULE::TEXT_is_REFERENCE )
311  text_key = "$REF:";
312  else if( text_mod->GetType() == TEXTE_MODULE::TEXT_is_VALUE )
313  text_key = "$VAL:";
314  else
315  break;
316 
317  return StrPrintf( "$PART: \"%s\" %s \"%s\"",
318  TO_UTF8( module->GetReference() ),
319  text_key,
320  TO_UTF8( text_mod->GetText() ) );
321  }
322 
323  default:
324  break;
325  }
326 
327  return "";
328 }
329 
330 
331 /* Send a remote command to Eeschema via a socket,
332  * aSyncItem = item to be located on schematic (module, pin or text)
333  * Commands are
334  * $PART: "reference" put cursor on component anchor
335  * $PART: "reference" $PAD: "pad number" put cursor on the component pin
336  * $PART: "reference" $REF: "reference" put cursor on the component ref
337  * $PART: "reference" $VAL: "value" put cursor on the component value
338  */
340 {
341  std::string packet = FormatProbeItem( aSyncItem );
342 
343  if( packet.size() )
344  {
345  if( Kiface().IsSingle() )
346  SendCommand( MSG_TO_SCH, packet.c_str() );
347  else
348  {
349  // Typically ExpressMail is going to be s-expression packets, but since
350  // we have existing interpreter of the cross probe packet on the other
351  // side in place, we use that here.
352  Kiway().ExpressMail( FRAME_SCH, MAIL_CROSS_PROBE, packet, this );
353  }
354  }
355 }
356 
357 
358 void PCB_EDIT_FRAME::SendCrossProbeNetName( const wxString& aNetName )
359 {
360  std::string packet = StrPrintf( "$NET: \"%s\"", TO_UTF8( aNetName ) );
361 
362  if( packet.size() )
363  {
364  if( Kiface().IsSingle() )
365  SendCommand( MSG_TO_SCH, packet.c_str() );
366  else
367  {
368  // Typically ExpressMail is going to be s-expression packets, but since
369  // we have existing interpreter of the cross probe packet on the other
370  // side in place, we use that here.
371  Kiway().ExpressMail( FRAME_SCH, MAIL_CROSS_PROBE, packet, this );
372  }
373  }
374 }
375 
376 
378 {
379  const std::string& payload = mail.GetPayload();
380 
381  switch( mail.Command() )
382  {
383  case MAIL_CROSS_PROBE:
384  ExecuteRemoteCommand( payload.c_str() );
385  break;
386 
387  case MAIL_SCH_PCB_UPDATE:
388  {
389  NETLIST netlist;
390  size_t split = payload.find( '\n' );
391  wxCHECK( split != std::string::npos, /*void*/ );
392 
393  // Extract options and netlist
394  std::string options = payload.substr( 0, split );
395  std::string netlistData = payload.substr( split + 1 );
396 
397  // Quiet update options
398  bool by_reference = options.find( "by-reference" ) != std::string::npos;
399  bool by_timestamp = options.find( "by-timestamp" ) != std::string::npos;
400  wxASSERT( !( by_reference && by_timestamp ) ); // only one at a time please
401 
402  try
403  {
404  STRING_LINE_READER* lineReader = new STRING_LINE_READER( netlistData, _( "Eeschema netlist" ) );
405  KICAD_NETLIST_READER netlistReader( lineReader, &netlist );
406  netlistReader.LoadNetlist();
407  }
408  catch( const IO_ERROR& )
409  {
410  assert( false ); // should never happen
411  }
412 
413  if( by_reference || by_timestamp )
414  {
415  netlist.SetDeleteExtraFootprints( false );
416  netlist.SetFindByTimeStamp( by_timestamp );
417  netlist.SetReplaceFootprints( true );
418 
419  BOARD_NETLIST_UPDATER updater( this, GetBoard() );
420  updater.SetLookupByTimestamp( by_timestamp );
421  updater.SetDeleteUnusedComponents( false );
422  updater.SetReplaceFootprints( true );
423  updater.SetDeleteSinglePadNets( false );
424  updater.UpdateNetlist( netlist );
425  }
426  else
427  {
428  DIALOG_UPDATE_PCB updateDialog( this, &netlist );
429  updateDialog.ShowModal();
430 
431  auto selectionTool = static_cast<SELECTION_TOOL*>(
432  m_toolManager->FindTool( "pcbnew.InteractiveSelection" ) );
433 
434  if( !selectionTool->GetSelection().Empty() )
435  GetToolManager()->InvokeTool( "pcbnew.InteractiveEdit" );
436  }
437 
438  break;
439  }
440 
441  case MAIL_IMPORT_FILE:
442  {
443  // Extract file format type and path (plugin type and path separated with \n)
444  size_t split = payload.find( '\n' );
445  wxCHECK( split != std::string::npos, /*void*/ );
446  int importFormat;
447 
448  try
449  {
450  importFormat = std::stoi( payload.substr( 0, split ) );
451  }
452  catch( std::invalid_argument& )
453  {
454  wxFAIL;
455  importFormat = -1;
456  }
457 
458  std::string path = payload.substr( split + 1 );
459  wxASSERT( !path.empty() );
460 
461  if( importFormat >= 0 )
462  importFile( path, importFormat );
463  }
464 
465  // many many others.
466  default:
467  ;
468  }
469 }
470 
TOOL_MANAGER * m_toolManager
Definition: draw_frame.h:128
NETINFO_ITEM * FindNet(int aNetcode) const
Function FindNet searches for a net with the given netcode.
KIGFX::VIEW * GetView() const
Definition: tool_manager.h:252
Class 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_player.h:60
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:53
Class KICAD_NETLIST_READER read the new s-expression based KiCad netlist format.
bool importFile(const wxString &aFileName, int aFileType)
Load the given filename but sets the path to the current project path.
Class BOARD_ITEM is a base class for any item which can be embedded within the BOARD container class,...
Class BOARD_NETLIST_UPDATER updates the BOARD with a new netlist.
Class BOARD to handle a board.
void SetDeleteSinglePadNets(bool aEnabled)
Enables "delete single pad nets" option
#define MSG_TO_SCH
Definition: eda_dde.h:46
EDA_DRAW_PANEL_GAL * GetGalCanvas() const
Return a pointer to GAL-based canvas of given EDA draw frame.
Definition: draw_frame.h:935
void SetCurItem(BOARD_ITEM *aItem, bool aDisplayInfo=true)
Function SetCurItem sets the currently selected item and displays it in the MsgPanel.
bool RunAction(const std::string &aActionName, bool aNow=false, T aParam=NULL)
Function RunAction() Runs the specified action.
Definition: tool_manager.h:125
void HighLightOFF()
Function HighLightOFF Disable highlight.
Definition: class_board.h:394
Classes to handle copper zones.
BOARD_NETLIST_UPDATER class definition.
class D_PAD, a pad in a footprint
Definition: typeinfo.h:90
void SetFindByTimeStamp(bool aFindByTimeStamp)
Definition: pcb_netlist.h:311
bool SendCommand(int service, const char *cmdline)
Definition: eda_dde.cpp:132
TOOL_BASE * FindTool(int aId) const
Function FindTool() Searches for a tool with given ID.
void SetLookupByTimestamp(bool aEnabled)
Enables component lookup by timestamp instead of reference
Class BOARD_CONNECTED_ITEM is a base class derived from BOARD_ITEM for items that can be connected an...
bool UpdateNetlist(NETLIST &aNetlist)
Function UpdateNetlist()
bool InvokeTool(TOOL_ID aToolId)
Function InvokeTool() Calls a tool by sending a tool activation event to tool of given ID.
PAINTER * GetPainter() const
Function GetPainter() Returns the painter object used by the view for drawing VIEW_ITEMS.
Definition: view.h:199
static TOOL_ACTION crossProbeSchToPcb
Definition: pcb_actions.h:380
KIFACE_I & Kiface()
Global KIFACE_I "get" accessor.
Definition: kicad.cpp:52
Functions relatives to tracks, vias and segments used to fill zones.
This file contains miscellaneous commonly used macros and functions.
TOOL_MANAGER * GetToolManager() const
Return the tool manager instance, if any.
Definition: draw_frame.h:941
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:386
bool IsGalCanvasActive() const
Function IsGalCanvasActive is used to check which canvas (GAL-based or standard) is currently in use.
Definition: draw_frame.h:928
#define TO_UTF8(wxstring)
Macro TO_UTF8 converts a wxString to a UTF8 encoded C string for all wxWidgets build modes.
Definition: macros.h:47
void KiwayMailIn(KIWAY_EXPRESS &aEvent) override
Function KiwayMailIn receives KIWAY_EXPRESS messages from other players.
class MODULE, a footprint
Definition: typeinfo.h:89
virtual void LoadNetlist() override
Function LoadNetlist loads the contents of the netlist file into aNetlist.
D_PAD * FindPadByName(const wxString &aPadName) const
Function FindPadByName returns a D_PAD* with a matching name.
void SetReplaceFootprints(bool aReplaceFootprints)
Definition: pcb_netlist.h:315
Class NETLIST stores all of information read from a netlist along with the flags used to update the N...
Definition: pcb_netlist.h:214
DLIST_ITERATOR_WRAPPER< MODULE > Modules()
Definition: class_board.h:255
bool IsSingle() const
Function IsSingle is this KIFACE_I running under single_top?
Definition: kiface_i.h:115
virtual void ExecuteRemoteCommand(const char *cmdline) override
Execute a remote command send by Eeschema via a socket, port KICAD_PCB_PORT_SERVICE_NUMBER (currently...
void SetReplaceFootprints(bool aEnabled)
Enables replacing footprints with new ones
const wxString & GetReference() const
Function GetReference.
Definition: class_module.h:462
SCH->PCB forward update.
Definition: mail_type.h:43
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:384
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...
void HighLightON()
Function HighLightON Enable highlight.
Definition: class_board.h:401
const 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
class TEXTE_MODULE, text in a footprint
Definition: typeinfo.h:93
void SetHighLightNet(int aNetCode)
Function SetHighLightNet.
Definition: class_board.h:379
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 GetSettings Returns pointer to current settings that are going to be used when drawing items...
virtual void RedrawScreen(const wxPoint &aCenterPoint, bool aWarpPointer)
Redraw the entire screen area by updating the scroll bars and mouse pointer in order to have aCenterP...
Class NETINFO_ITEM handles the data for a net.
Definition: netinfo.h:69
BOX2< Vec > & Inflate(coord_type dx, coord_type dy)
Function Inflate inflates the rectangle horizontally by dx and vertically by dy.
Definition: box2.h:300
ZONE_CONTAINERS & Zones()
Definition: class_board.h:257
const int scale
see class PGM_BASE
int GetNet() const
Function GetNet.
Definition: netinfo.h:231
static TOOL_ACTION selectOnSheetFromEeschema
Selects all components on sheet from Eeschema crossprobing.
Definition: pcb_actions.h:83
#define max(a, b)
Definition: auxiliary.h:86
Import a different format file.
Definition: mail_type.h:44
Class BOARD holds information pertinent to a Pcbnew printed circuit board.
Definition: class_board.h:171
void SetDeleteUnusedComponents(bool aEnabled)
Enables removing unused components
MODULE * FindModuleByReference(const wxString &aReference) const
Function FindModuleByReference searches for a MODULE within this board with the given reference desig...
PCB<->SCH, CVPCB->SCH cross-probing.
Definition: mail_type.h:39
DLIST_ITERATOR_WRAPPER< TRACK > Tracks()
Definition: class_board.h:254
Module description (excepted pads)
void SetDeleteExtraFootprints(bool aDeleteExtraFootprints)
Definition: pcb_netlist.h:300
BOARD * GetBoard() const
MAIL_T Command()
Function Command returns the MAIL_T associated with this mail.
Definition: kiway_express.h:52
void SetCrossHairPosition(const wxPoint &aPosition, bool aSnapToGrid=true)
Set the screen cross hair position to aPosition in logical (drawing) units.
const wxPoint GetPosition() const override
Definition: class_pad.h:220
BOARD_ITEM_CONTAINER * GetParent() const
Class STRING_LINE_READER is a LINE_READER that reads from a multiline 8 bit wide std::string.
Definition: richio.h:254
void SetHighlight(bool aEnabled, int aNetcode=-1)
Function SetHighlight Turns on/off highlighting - it may be done for the active layer or the specifie...
Definition: painter.h:140
Struct IO_ERROR is a class used to hold an error message and may be used when throwing exceptions con...
Definition: ki_exception.h:76
const wxPoint GetPosition() const override
Definition: class_module.h:183
#define mod(a, n)
Definition: greymap.cpp:24
int GetToolId() const
Definition: draw_frame.h:526
KICAD_T Type() const
Function Type()
Definition: base_struct.h:201