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-2019 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  m_frame->GetCanvas()->GetView()->HighlightItem( nullptr, nullptr );
144 
145  if( foundItem )
146  m_frame->GetCanvas()->GetView()->HighlightItem( foundItem, pin );
147  }
148  m_probingPcbToSch = false;
149 
150  m_frame->GetCanvas()->Refresh();
151 
152  return foundItem;
153 }
154 
155 
174 void SCH_EDIT_FRAME::ExecuteRemoteCommand( const char* cmdline )
175 {
177  char line[1024];
178 
179  strncpy( line, cmdline, sizeof(line) - 1 );
180  line[ sizeof(line) - 1 ] = '\0';
181 
182  char* idcmd = strtok( line, " \n\r" );
183  char* text = strtok( NULL, "\"\n\r" );
184 
185  if( idcmd == NULL )
186  return;
187 
188  if( strcmp( idcmd, "$NET:" ) == 0 )
189  {
190  m_SelectedNetName = FROM_UTF8( text );
192 
193  SetStatusText( _( "Selected net: " ) + UnescapeString( m_SelectedNetName ) );
194  return;
195  }
196 
197  if( strcmp( idcmd, "$CLEAR:" ) == 0 )
198  {
199  if( text && strcmp( text, "HIGHLIGHTED" ) == 0 )
200  {
201  GetCanvas()->GetView()->HighlightItem( nullptr, nullptr );
202  GetCanvas()->Refresh();
203  }
204 
205  return;
206  }
207 
208  if( text == NULL )
209  return;
210 
211  if( strcmp( idcmd, "$PART:" ) != 0 )
212  return;
213 
214  wxString part_ref = FROM_UTF8( text );
215 
216  /* look for a complement */
217  idcmd = strtok( NULL, " \n\r" );
218 
219  if( idcmd == NULL ) // Highlight component only (from Cvpcb or Pcbnew)
220  {
221  // Highlight component part_ref, or clear Highlight, if part_ref is not existing
222  editor->FindComponentAndItem( part_ref, true, HIGHLIGHT_COMPONENT, wxEmptyString );
223  return;
224  }
225 
226  text = strtok( NULL, "\"\n\r" );
227 
228  if( text == NULL )
229  return;
230 
231  wxString msg = FROM_UTF8( text );
232 
233  if( strcmp( idcmd, "$REF:" ) == 0 )
234  {
235  // Highlighting the reference itself isn't actually that useful, and it's harder to
236  // see. Highlight the parent and display the message.
237  editor->FindComponentAndItem( part_ref, true, HIGHLIGHT_COMPONENT, msg );
238  }
239  else if( strcmp( idcmd, "$VAL:" ) == 0 )
240  {
241  // Highlighting the value itself isn't actually that useful, and it's harder to see.
242  // Highlight the parent and display the message.
243  editor->FindComponentAndItem( part_ref, true, HIGHLIGHT_COMPONENT, msg );
244  }
245  else if( strcmp( idcmd, "$PAD:" ) == 0 )
246  {
247  editor->FindComponentAndItem( part_ref, true, HIGHLIGHT_PIN, msg );
248  }
249  else
250  {
251  editor->FindComponentAndItem( part_ref, true, HIGHLIGHT_COMPONENT, wxEmptyString );
252  }
253 }
254 
255 
256 std::string FormatProbeItem( EDA_ITEM* aItem, SCH_COMPONENT* aComp )
257 {
258  // This is a keyword followed by a quoted string.
259 
260  // Cross probing to Pcbnew if a pin or a component is found
261  switch( aItem->Type() )
262  {
263  case SCH_FIELD_T:
264  if( aComp )
265  return StrPrintf( "$PART: \"%s\"", TO_UTF8( aComp->GetField( REFERENCE )->GetText() ) );
266  break;
267 
268  case SCH_COMPONENT_T:
269  aComp = (SCH_COMPONENT*) aItem;
270  return StrPrintf( "$PART: \"%s\"", TO_UTF8( aComp->GetField( REFERENCE )->GetText() ) );
271 
272  case SCH_SHEET_T:
273  {
274  SCH_SHEET* sheet = (SCH_SHEET*)aItem;
275  return StrPrintf( "$SHEET: \"%8.8lX\"", (unsigned long) sheet->GetTimeStamp() );
276  }
277 
278  case SCH_PIN_T:
279  {
280  SCH_PIN* pin = (SCH_PIN*) aItem;
281  aComp = pin->GetParentComponent();
282 
283  if( !pin->GetNumber().IsEmpty() )
284  {
285  return StrPrintf( "$PIN: \"%s\" $PART: \"%s\"",
286  TO_UTF8( pin->GetNumber() ),
287  TO_UTF8( aComp->GetField( REFERENCE )->GetText() ) );
288  }
289  else
290  {
291  return StrPrintf( "$PART: \"%s\"",
292  TO_UTF8( aComp->GetField( REFERENCE )->GetText() ) );
293  }
294  }
295 
296  default:
297  break;
298  }
299 
300  return "";
301 }
302 
303 
305 {
306  wxASSERT( aObjectToSync ); // fix the caller
307 
308  if( !aObjectToSync )
309  return;
310 
311  std::string packet = FormatProbeItem( aObjectToSync, aLibItem );
312 
313  if( !packet.empty() )
314  {
315  if( Kiface().IsSingle() )
316  SendCommand( MSG_TO_PCB, packet.c_str() );
317  else
318  {
319  // Typically ExpressMail is going to be s-expression packets, but since
320  // we have existing interpreter of the cross probe packet on the other
321  // side in place, we use that here.
323  }
324  }
325 }
326 
327 
328 void SCH_EDIT_FRAME::SendCrossProbeNetName( const wxString& aNetName )
329 {
330  // The command is a keyword followed by a quoted string.
331 
332  std::string packet = StrPrintf( "$NET: \"%s\"", TO_UTF8( aNetName ) );
333 
334  if( !packet.empty() )
335  {
336  if( Kiface().IsSingle() )
337  SendCommand( MSG_TO_PCB, packet.c_str() );
338  else
339  {
340  // Typically ExpressMail is going to be s-expression packets, but since
341  // we have existing interpreter of the cross probe packet on the other
342  // side in place, we use that here.
344  }
345  }
346 }
347 
348 
350 {
351  std::string packet = "$CLEAR\n";
352 
353  if( Kiface().IsSingle() )
354  SendCommand( MSG_TO_PCB, packet.c_str() );
355  else
356  {
357  // Typically ExpressMail is going to be s-expression packets, but since
358  // we have existing interpreter of the cross probe packet on the other
359  // side in place, we use that here.
361  }
362 }
363 
364 
366 {
367  std::string& payload = mail.GetPayload();
368 
369  switch( mail.Command() )
370  {
371  case MAIL_CROSS_PROBE:
372  ExecuteRemoteCommand( payload.c_str() );
373  break;
374 
376  if( payload.find( "quiet-annotate" ) != std::string::npos )
377  {
378  SCH_SCREENS schematic;
379  schematic.UpdateSymbolLinks();
380  SCH_SHEET_LIST sheets( g_RootSheet );
381  sheets.AnnotatePowerSymbols();
382  AnnotateComponents( true, UNSORTED, INCREMENTAL_BY_REF, 0, false, false, true,
384  }
385 
386  if( payload.find( "no-annotate" ) == std::string::npos )
387  {
388  // Ensure schematic is OK for netlist creation (especially that it is fully annotated):
389  if( !prepareForNetlist() )
390  return;
391  }
392 
393  {
394  NETLIST_OBJECT_LIST* net_atoms = BuildNetListBase();
395  NETLIST_EXPORTER_KICAD exporter( this, net_atoms, g_ConnectionGraph );
396  STRING_FORMATTER formatter;
397 
398  exporter.Format( &formatter, GNL_ALL );
399 
400  payload = formatter.GetString();
401  }
402  break;
403 
405  try
406  {
408  controlTool->BackAnnotateFootprints( payload );
409  }
410  catch( const IO_ERROR& DBG( ioe ) )
411  {
412  DBG( printf( "%s: ioe:%s\n", __func__, TO_UTF8( ioe.What() ) );)
413  }
414  break;
415 
416  case MAIL_SCH_REFRESH:
417  {
418  SCH_SCREENS schematic;
419  schematic.UpdateSymbolLinks();
420  schematic.TestDanglingEnds();
421 
423  GetCanvas()->Refresh();
424  break;
425  }
426  case MAIL_IMPORT_FILE:
427  {
428  // Extract file format type and path (plugin type and path separated with \n)
429  size_t split = payload.find( '\n' );
430  wxCHECK( split != std::string::npos, /*void*/ );
431  int importFormat;
432 
433  try
434  {
435  importFormat = std::stoi( payload.substr( 0, split ) );
436  }
437  catch( std::invalid_argument& )
438  {
439  wxFAIL;
440  importFormat = -1;
441  }
442 
443  std::string path = payload.substr( split + 1 );
444  wxASSERT( !path.empty() );
445 
446  if( importFormat >= 0 )
447  importFile( path, importFormat );
448  }
449  break;
450 
451  case MAIL_SCH_SAVE:
452  if( SaveProject() )
453  payload = "success";
454  break;
455 
456  default:
457  ;
458  }
459 }
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.
Definition: mail_type.h:45
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:219
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:109
Annotate incrementally using the first free reference number.
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:225
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:103
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
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
#define NULL
bool IsSingle() const
Function IsSingle is this KIFACE_I running under single_top?
Definition: kiface_i.h:115
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.
timestamp_t GetTimeStamp() const
Definition: base_struct.h:213
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.
void BuildSheetList(SCH_SHEET *aSheet)
Function BuildSheetList builds the list of sheets and their sheet path from aSheet.
const wxString GetRef(const SCH_SHEET_PATH *aSheet)
Return the reference for the given sheet path.
The the schematic editor to refresh the display.
Definition: mail_type.h:46
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:206
wxPoint GetPosition() const override
Definition: lib_pin.h:429
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:44
#define _(s)
Definition: 3d_actions.cpp:31
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:89
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:163
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:136
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:498
KICAD_T Type() const
Function Type()
Definition: base_struct.h:207