KiCad PCB EDA Suite
eeschema/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 Jean-Pierre Charras, jp.charras at wanadoo.fr
5  * Copyright (C) 2011 Wayne Stambaugh <stambaughw@verizon.net>
6  * Copyright (C) 2004-2020 KiCad Developers, see AUTHORS.txt for contributors.
7  *
8  * This program is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU General Public License
10  * as published by the Free Software Foundation; either version 2
11  * of the License, or (at your option) any later version.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with this program; if not, you may find one here:
20  * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
21  * or you may search the http://www.gnu.org website for the version 2 license,
22  * or you may write to the Free Software Foundation, Inc.,
23  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
24  */
25 
26 #include <fctsys.h>
27 #include <pgm_base.h>
28 #include <kiface_i.h>
29 #include <kiway_express.h>
30 #include <macros.h>
31 #include <eda_dde.h>
32 #include <sch_edit_frame.h>
33 #include <general.h>
34 #include <lib_item.h>
35 #include <lib_pin.h>
36 #include <sch_component.h>
37 #include <sch_sheet.h>
38 #include <sch_view.h>
39 #include <reporter.h>
41 #include <tools/ee_actions.h>
43 
44 
46  bool aSearchHierarchy,
47  SCH_SEARCH_T aSearchType,
48  const wxString& aSearchText )
49 {
50  SCH_SHEET_PATH* sheetWithComponentFound = NULL;
51  SCH_COMPONENT* Component = NULL;
52  wxPoint pos;
53  LIB_PIN* pin = nullptr;
54  SCH_SHEET_LIST sheetList( g_RootSheet );
55  SCH_ITEM* foundItem = nullptr;
56 
57  if( !aSearchHierarchy )
58  sheetList.push_back( *g_CurrentSheet );
59  else
60  sheetList.BuildSheetList( g_RootSheet );
61 
62  for( SCH_SHEET_PATH& sheet : sheetList)
63  {
64  SCH_SCREEN* screen = sheet.LastScreen();
65 
66  for( auto item : screen->Items().OfType( SCH_COMPONENT_T ) )
67  {
68  SCH_COMPONENT* pSch = static_cast<SCH_COMPONENT*>( item );
69 
70  if( aReference.CmpNoCase( pSch->GetRef( &sheet ) ) == 0 )
71  {
72  Component = pSch;
73  sheetWithComponentFound = &sheet;
74 
75  if( aSearchType == HIGHLIGHT_PIN )
76  {
77  pos = pSch->GetPosition(); // temporary: will be changed if the pin is found.
78  pin = pSch->GetPin( aSearchText );
79 
80  if( pin )
81  {
82  pos += pin->GetPosition();
83  foundItem = Component;
84  break;
85  }
86  }
87  else
88  {
89  pos = pSch->GetPosition();
90  foundItem = Component;
91  break;
92  }
93  }
94  }
95 
96  if( foundItem )
97  break;
98  }
99 
100  if( Component )
101  {
102  if( *sheetWithComponentFound != *g_CurrentSheet )
103  {
104  sheetWithComponentFound->LastScreen()->SetZoom( m_frame->GetScreen()->GetZoom() );
105  *g_CurrentSheet = *sheetWithComponentFound;
107  }
108 
109  wxPoint delta;
110  pos -= Component->GetPosition();
111  delta = Component->GetTransform().TransformCoordinate( pos );
112  pos = delta + Component->GetPosition();
113 
115  m_frame->CenterScreen( pos, false );
116  }
117 
118  /* Print diag */
119  wxString msg_item;
120  wxString msg;
121 
122  if( aSearchType == HIGHLIGHT_PIN )
123  msg_item.Printf( _( "pin %s" ), aSearchText );
124  else
125  msg_item = _( "component" );
126 
127  if( Component )
128  {
129  if( foundItem )
130  msg.Printf( _( "%s %s found" ), aReference, msg_item );
131  else
132  msg.Printf( _( "%s found but %s not found" ), aReference, msg_item );
133  }
134  else
135  msg.Printf( _( "Component %s not found" ), aReference );
136 
137  m_frame->SetStatusText( msg );
138 
139  m_probingPcbToSch = true; // recursion guard
140  {
141  // Clear any existing highlighting
143 
144  if( foundItem )
145  m_toolMgr->RunAction( EE_ACTIONS::addItemToSel, true, foundItem );
146  }
147  m_probingPcbToSch = false;
148 
149  m_frame->GetCanvas()->Refresh();
150 
151  return foundItem;
152 }
153 
154 
173 void SCH_EDIT_FRAME::ExecuteRemoteCommand( const char* cmdline )
174 {
176  char line[1024];
177 
178  strncpy( line, cmdline, sizeof(line) - 1 );
179  line[ sizeof(line) - 1 ] = '\0';
180 
181  char* idcmd = strtok( line, " \n\r" );
182  char* text = strtok( NULL, "\"\n\r" );
183 
184  if( idcmd == NULL )
185  return;
186 
187  if( strcmp( idcmd, "$NET:" ) == 0 )
188  {
189  m_SelectedNetName = FROM_UTF8( text );
191 
192  SetStatusText( _( "Selected net: " ) + UnescapeString( m_SelectedNetName ) );
193  return;
194  }
195 
196  if( strcmp( idcmd, "$CLEAR:" ) == 0 )
197  {
198  if( text && strcmp( text, "HIGHLIGHTED" ) == 0 )
199  {
200  GetCanvas()->GetView()->HighlightItem( nullptr, nullptr );
201  GetCanvas()->Refresh();
202  }
203 
204  return;
205  }
206 
207  if( text == NULL )
208  return;
209 
210  if( strcmp( idcmd, "$PART:" ) != 0 )
211  return;
212 
213  wxString part_ref = FROM_UTF8( text );
214 
215  /* look for a complement */
216  idcmd = strtok( NULL, " \n\r" );
217 
218  if( idcmd == NULL ) // Highlight component only (from Cvpcb or Pcbnew)
219  {
220  // Highlight component part_ref, or clear Highlight, if part_ref is not existing
221  editor->FindComponentAndItem( part_ref, true, HIGHLIGHT_COMPONENT, wxEmptyString );
222  return;
223  }
224 
225  text = strtok( NULL, "\"\n\r" );
226 
227  if( text == NULL )
228  return;
229 
230  wxString msg = FROM_UTF8( text );
231 
232  if( strcmp( idcmd, "$REF:" ) == 0 )
233  {
234  // Highlighting the reference itself isn't actually that useful, and it's harder to
235  // see. Highlight the parent and display the message.
236  editor->FindComponentAndItem( part_ref, true, HIGHLIGHT_COMPONENT, msg );
237  }
238  else if( strcmp( idcmd, "$VAL:" ) == 0 )
239  {
240  // Highlighting the value itself isn't actually that useful, and it's harder to see.
241  // Highlight the parent and display the message.
242  editor->FindComponentAndItem( part_ref, true, HIGHLIGHT_COMPONENT, msg );
243  }
244  else if( strcmp( idcmd, "$PAD:" ) == 0 )
245  {
246  editor->FindComponentAndItem( part_ref, true, HIGHLIGHT_PIN, msg );
247  }
248  else
249  {
250  editor->FindComponentAndItem( part_ref, true, HIGHLIGHT_COMPONENT, wxEmptyString );
251  }
252 }
253 
254 
255 std::string FormatProbeItem( EDA_ITEM* aItem, SCH_COMPONENT* aComp )
256 {
257  // This is a keyword followed by a quoted string.
258 
259  // Cross probing to Pcbnew if a pin or a component is found
260  switch( aItem->Type() )
261  {
262  case SCH_FIELD_T:
263  if( aComp )
264  return StrPrintf( "$PART: \"%s\"", TO_UTF8( aComp->GetField( REFERENCE )->GetText() ) );
265  break;
266 
267  case SCH_COMPONENT_T:
268  aComp = (SCH_COMPONENT*) aItem;
269  return StrPrintf( "$PART: \"%s\"", TO_UTF8( aComp->GetField( REFERENCE )->GetText() ) );
270 
271  case SCH_SHEET_T:
272  {
273  SCH_SHEET* sheet = (SCH_SHEET*)aItem;
274  return StrPrintf( "$SHEET: \"%s\"", TO_UTF8( sheet->m_Uuid.AsString() ) );
275  }
276 
277  case SCH_PIN_T:
278  {
279  SCH_PIN* pin = (SCH_PIN*) aItem;
280  aComp = pin->GetParentComponent();
281 
282  if( !pin->GetNumber().IsEmpty() )
283  {
284  return StrPrintf( "$PIN: \"%s\" $PART: \"%s\"",
285  TO_UTF8( pin->GetNumber() ),
286  TO_UTF8( aComp->GetField( REFERENCE )->GetText() ) );
287  }
288  else
289  {
290  return StrPrintf( "$PART: \"%s\"",
291  TO_UTF8( aComp->GetField( REFERENCE )->GetText() ) );
292  }
293  }
294 
295  default:
296  break;
297  }
298 
299  return "";
300 }
301 
302 
304 {
305  wxASSERT( aObjectToSync ); // fix the caller
306 
307  if( !aObjectToSync )
308  return;
309 
310  std::string packet = FormatProbeItem( aObjectToSync, aLibItem );
311 
312  if( !packet.empty() )
313  {
314  if( Kiface().IsSingle() )
315  SendCommand( MSG_TO_PCB, packet.c_str() );
316  else
317  {
318  // Typically ExpressMail is going to be s-expression packets, but since
319  // we have existing interpreter of the cross probe packet on the other
320  // side in place, we use that here.
322  }
323  }
324 }
325 
326 
327 void SCH_EDIT_FRAME::SendCrossProbeNetName( const wxString& aNetName )
328 {
329  // The command is a keyword followed by a quoted string.
330 
331  std::string packet = StrPrintf( "$NET: \"%s\"", TO_UTF8( aNetName ) );
332 
333  if( !packet.empty() )
334  {
335  if( Kiface().IsSingle() )
336  SendCommand( MSG_TO_PCB, packet.c_str() );
337  else
338  {
339  // Typically ExpressMail is going to be s-expression packets, but since
340  // we have existing interpreter of the cross probe packet on the other
341  // side in place, we use that here.
343  }
344  }
345 }
346 
347 
349 {
350  std::string packet = "$CLEAR\n";
351 
352  if( Kiface().IsSingle() )
353  SendCommand( MSG_TO_PCB, packet.c_str() );
354  else
355  {
356  // Typically ExpressMail is going to be s-expression packets, but since
357  // we have existing interpreter of the cross probe packet on the other
358  // side in place, we use that here.
360  }
361 }
362 
363 
365 {
366  std::string& payload = mail.GetPayload();
367 
368  switch( mail.Command() )
369  {
370  case MAIL_CROSS_PROBE:
371  ExecuteRemoteCommand( payload.c_str() );
372  break;
373 
375  if( payload.find( "quiet-annotate" ) != std::string::npos )
376  {
377  SCH_SCREENS schematic;
378  schematic.UpdateSymbolLinks();
379  SCH_SHEET_LIST sheets( g_RootSheet );
380  sheets.AnnotatePowerSymbols();
381  AnnotateComponents( true, UNSORTED, INCREMENTAL_BY_REF, 0, false, false, true,
383  }
384 
385  if( payload.find( "no-annotate" ) == std::string::npos )
386  {
387  // Ensure schematic is OK for netlist creation (especially that it is fully annotated):
388  if( !prepareForNetlist() )
389  return;
390  }
391 
392  {
393  NETLIST_OBJECT_LIST* net_atoms = BuildNetListBase();
394  NETLIST_EXPORTER_KICAD exporter( this, net_atoms, g_ConnectionGraph );
395  STRING_FORMATTER formatter;
396 
397  exporter.Format( &formatter, GNL_ALL );
398 
399  payload = formatter.GetString();
400  }
401  break;
402 
404  try
405  {
407  controlTool->BackAnnotateFootprints( payload );
408  }
409  catch( const IO_ERROR& DBG( ioe ) )
410  {
411  DBG( printf( "%s: ioe:%s\n", __func__, TO_UTF8( ioe.What() ) );)
412  }
413  break;
414 
415  case MAIL_SCH_REFRESH:
416  {
417  SCH_SCREENS schematic;
418  schematic.UpdateSymbolLinks();
419  schematic.TestDanglingEnds();
420 
422  GetCanvas()->Refresh();
423  break;
424  }
425  case MAIL_IMPORT_FILE:
426  {
427  // Extract file format type and path (plugin type and path separated with \n)
428  size_t split = payload.find( '\n' );
429  wxCHECK( split != std::string::npos, /*void*/ );
430  int importFormat;
431 
432  try
433  {
434  importFormat = std::stoi( payload.substr( 0, split ) );
435  }
436  catch( std::invalid_argument& )
437  {
438  wxFAIL;
439  importFormat = -1;
440  }
441 
442  std::string path = payload.substr( split + 1 );
443  wxASSERT( !path.empty() );
444 
445  if( importFormat >= 0 )
446  importFile( path, importFormat );
447  }
448  break;
449 
450  case MAIL_SCH_SAVE:
451  if( SaveProject() )
452  payload = "success";
453  break;
454 
455  case MAIL_SCH_UPDATE:
457  break;
458 
459  default:
460  ;
461  }
462 }
SCH_SHEET_LIST.
KIGFX::SCH_VIEW * GetView() const override
Function GetView() Returns a pointer to the VIEW instance used in the panel.
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
TOOL_MANAGER * GetToolManager() const
Return the MVC controller.
NETLIST_OBJECT_LIST * BuildNetListBase(bool updateStatusText=true)
Create a flat list which stores all connected objects.
DDE server & client.
KIGFX::VIEW_CONTROLS * GetViewControls() const
Function GetViewControls() Returns a pointer to the VIEW_CONTROLS instance used in the panel.
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:62
void SendCrossProbeNetName(const wxString &aNetName)
Sends a net name to pcbnew for highlighting.
Fetch a netlist from schematics.
Definition: mail_type.h:46
CVPCB->SCH footprint stuffing.
Definition: mail_type.h:40
double GetZoom() const
Function GetZoom returns the current "zoom factor", which is a measure of "internal units per device ...
Definition: base_screen.h:240
void SendCrossProbeClearHighlight()
Tells PcbNew to clear the existing highlighted net, if one exists.
TOOL_MANAGER * m_toolMgr
Definition: tool_base.h:218
void AnnotateComponents(bool aAnnotateSchematic, ANNOTATE_ORDER_T aSortOption, ANNOTATE_OPTION_T aAlgoOption, int aStartNumber, bool aResetAnnotation, bool aRepairTimestamps, bool aLockUnits, REPORTER &aReporter)
Annotate the components in the schematic that are not currently annotated.
EE_TYPE OfType(KICAD_T aType)
Definition: sch_rtree.h:219
void UpdateAllItems(int aUpdateFlags)
Updates all items in the view according to the given flags.
Definition: view.cpp:1444
bool RunAction(const std::string &aActionName, bool aNow=false, T aParam=NULL)
Function RunAction() Runs the specified action.
Definition: tool_manager.h:139
Annotate incrementally using the first free reference number.
wxString AsString() const
Definition: common.cpp:170
LIB_PIN * GetPin(const wxString &number)
Find a symbol pin by number.
bool SendCommand(int service, const char *cmdline)
Definition: eda_dde.cpp:132
void DisplayCurrentSheet()
Draw the current sheet on the display.
Definition: hierarch.cpp:218
std::string FormatProbeItem(EDA_ITEM *aItem, SCH_COMPONENT *aComp)
Item needs to be redrawn.
Definition: view_item.h:61
void Format(OUTPUTFORMATTER *aOutputFormatter, int aCtl)
Function Format outputs this s-expression netlist into aOutputFormatter.
CONNECTION_GRAPH * g_ConnectionGraph
This also wants to live in the eventual SCHEMATIC object.
CVPCB->SCH save the schematic.
Definition: mail_type.h:41
static TOOL_ACTION updateNetHighlighting
Definition: ee_actions.h:204
bool importFile(const wxString &aFileName, int aFileType)
Load the given filename but sets the path to the current project path.
void HighlightItem(EDA_ITEM *aItem, LIB_PIN *aPin=nullptr)
Definition: sch_view.cpp:226
Field Reference of part, i.e. "IC21".
wxPoint TransformCoordinate(const wxPoint &aPoint) const
Calculate a new coordinate according to the mirror/rotation transform.
Definition: transform.cpp:42
This file contains miscellaneous commonly used macros and functions.
NETLIST_OBJECT_LIST is a container holding and owning NETLIST_OBJECTs, which are connected items in a...
SCH_FIELD * GetField(int aFieldNdx) const
Returns a field in this symbol.
SCH_SCREEN * GetScreen() const override
Return a pointer to a BASE_SCREEN or one of its derivatives.
const wxString & GetNumber() const
Definition: sch_pin.h:104
SCH_EDITOR_CONTROL.
#define TO_UTF8(wxstring)
Macro TO_UTF8 converts a wxString to a UTF8 encoded C string for all wxWidgets build modes.
Definition: macros.h:48
PCB->SCH forward update.
Definition: mail_type.h:44
void SendMessageToPCBNEW(EDA_ITEM *aObjectToSync, SCH_COMPONENT *aPart)
Send a message to Pcbnew via a socket connection.
SCH_ITEM * FindComponentAndItem(const wxString &aReference, bool aSearchHierarchy, SCH_SEARCH_T aSearchType, const wxString &aSearchText)
Finds a component in the schematic and an item in this component.
void BackAnnotateFootprints(const std::string &aChangedSetOfReferences)
Definition: backanno.cpp:45
static TOOL_ACTION updateSchematicFromPcb
Definition: actions.h:157
static TOOL_ACTION addItemToSel
Selects an item (specified as the event parameter).
Definition: ee_actions.h:61
#define NULL
bool IsSingle() const
Function IsSingle is this KIFACE_I running under single_top?
Definition: kiface_i.h:117
SCH_SHEET_PATH * g_CurrentSheet
With the new connectivity algorithm, many more places than before want to know what the current sheet...
bool prepareForNetlist()
Verify that annotation is complete so that a proper netlist is even possible.
TRANSFORM & GetTransform() const
SCH_DRAW_PANEL * GetCanvas() const override
Return a pointer to GAL-based canvas of given EDA draw frame.
KIFACE_I & Kiface()
Global KIFACE_I "get" accessor.
Annotate by position of component in the schematic sheet object list.
NETLIST_EXPORTER_KICAD generates the kicad netlist format supported by pcbnew.
void KiwayMailIn(KIWAY_EXPRESS &aEvent) override
Function KiwayMailIn receives KIWAY_EXPRESS messages from other players.
const std::string & GetString()
Definition: richio.h:475
static TOOL_ACTION clearSelection
Clears the current selection.
Definition: ee_actions.h:58
virtual bool SetZoom(double iu_per_du)
Function SetZoom adjusts the current zoom factor.
Definition: base_screen.cpp:88
virtual void SetCrossHairCursorPosition(const VECTOR2D &aPosition, bool aWarpView=true)=0
Moves the graphic crosshair cursor to the requested position expressed in world coordinates.
SCH_SHEET_PATH.
const wxString GetRef(const SCH_SHEET_PATH *aSheet, bool aIncludeUnit=false)
Return the reference for the given sheet path.
void BuildSheetList(SCH_SHEET *aSheet)
Function BuildSheetList builds the list of sheets and their sheet path from aSheet.
The the schematic editor to refresh the display.
Definition: mail_type.h:48
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...
Sheet symbol placed in a schematic, and is the entry point for a sub schematic.
Definition: sch_sheet.h:215
const KIID m_Uuid
Definition: base_struct.h:169
wxPoint GetPosition() const override
Definition: lib_pin.h:432
wxString m_SelectedNetName
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:427
see class PGM_BASE
void UpdateSymbolLinks(bool aForce=false)
Initialize or reinitialize the weak reference to the LIB_PART for each SCH_COMPONENT found in the ful...
SCH_SEARCH_T
Schematic search type used by the socket link with Pcbnew.
SCH_SCREEN * LastScreen()
Function LastScreen.
void TestDanglingEnds()
Import a different format file.
Definition: mail_type.h:45
#define _(s)
Definition: 3d_actions.cpp:33
wxString UnescapeString(const wxString &aSource)
Definition: string.cpp:131
EE_RTREE & Items()
Definition: sch_screen.h:127
#define GNL_ALL
#define MSG_TO_PCB
Definition: eda_dde.h:45
SCH_COMPONENT describes a real schematic component.
Definition: sch_component.h:99
wxPoint GetPosition() const override
Function GetPosition.
EDA_ITEM is a base class for most all the KiCad significant classes, used in schematics and boards.
Definition: base_struct.h:166
void ExecuteRemoteCommand(const char *cmdline) override
Execute a remote command send by Pcbnew via a socket, port KICAD_SCH_PORT_SERVICE_NUMBER (currently 4...
virtual void CenterScreen(const wxPoint &aCenterPoint, bool aWarpPointer)
PCB<->SCH, CVPCB->SCH cross-probing.
Definition: mail_type.h:39
void AnnotatePowerSymbols()
Function AnnotatePowerSymbols Silently annotates the not yet annotated power symbols of the entire hi...
#define DBG(x)
Definition: fctsys.h:33
TOOL_MANAGER * m_toolManager
SCH_SHEET * g_RootSheet
static REPORTER & GetInstance()
Definition: reporter.cpp:104
MAIL_T Command()
Function Command returns the MAIL_T associated with this mail.
Definition: kiway_express.h:52
STRING_FORMATTER implements OUTPUTFORMATTER to a memory buffer.
Definition: richio.h:445
SCH_COMPONENT * GetParentComponent() const
Definition: sch_pin.cpp:64
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
SCH_ITEM is a base class for any item which can be embedded within the SCHEMATIC container class,...
Definition: sch_item.h:147
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
virtual const wxString & GetText() const
Return the string associated with the text object.
Definition: eda_text.h:123
Container class that holds multiple SCH_SCREEN objects in a hierarchy.
Definition: sch_screen.h:491
KICAD_T Type() const
Function Type()
Definition: base_struct.h:212