KiCad PCB EDA Suite
Loading...
Searching...
No Matches
eda_dde.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) 2014 Jean-Pierre Charras, jp.charras at wanadoo.fr
5 * Copyright The KiCad Developers, see AUTHORS.txt for contributors.
6 *
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License
9 * as published by the Free Software Foundation; either version 2
10 * of the License, or (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, you may find one here:
19 * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
20 * or you may search the http://www.gnu.org website for the version 2 license,
21 * or you may write to the Free Software Foundation, Inc.,
22 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
23 */
24
25#include <condition_variable>
26#include <mutex>
27#include <thread>
28
29#include <eda_dde.h>
30#include <kiway_player.h>
31#include <id.h>
32
33#include <wx/crt.h>
34
35
36static const wxString HOSTNAME( wxT( "localhost" ) );
47{
48public:
50 m_messageReady( false ),
51 m_shutdown( false )
52 {
53 // Do a dummy Connect so that wx will set up the socket stuff on the main thread, which is
54 // required even if you later make socket connections on another thread.
55 wxSocketClient* client = new wxSocketClient;
56 wxIPV4address addr;
57
58 addr.Hostname( HOSTNAME );
59 addr.Service( KICAD_PCB_PORT_SERVICE_NUMBER );
60
61 client->Connect( addr, false );
62
63 client->Close();
64 client->Destroy();
65
66 m_thread = std::thread( &ASYNC_SOCKET_HOLDER::worker, this );
67 }
68
70 {
71 {
72 std::lock_guard<std::mutex> lock( m_mutex );
73 m_shutdown = true;
74 }
75
76 m_cv.notify_one();
77
78 try
79 {
80 if( m_thread.joinable() )
81 m_thread.join();
82 }
83 catch( ... )
84 {
85 }
86 }
87
95 bool Send( int aService, const std::string& aMessage )
96 {
97 if( m_messageReady )
98 return false;
99
100 std::lock_guard<std::mutex> lock( m_mutex );
101
102 m_message = std::make_pair( aService, aMessage );
103 m_messageReady = true;
104 m_cv.notify_one();
105
106 return true;
107 }
108
109private:
113 void worker()
114 {
115 int port;
116 std::string message;
117
118 std::unique_lock<std::mutex> lock( m_mutex );
119
120 while( !m_shutdown )
121 {
122 m_cv.wait( lock, [&]() { return m_messageReady || m_shutdown; } );
123
124 if( m_shutdown )
125 break;
126
127 port = m_message.first;
128 message = m_message.second;
129
130 lock.unlock();
131
132 wxSocketClient* sock_client;
133 wxIPV4address addr;
134
135 // Create a connection
136 addr.Hostname( HOSTNAME );
137 addr.Service( port );
138
139 // Mini-tutorial for Connect() :-)
140 // (JP CHARRAS Note: see wxWidgets: sockets/client.cpp sample)
141 // ---------------------------
142 //
143 // There are two ways to use Connect(): blocking and non-blocking,
144 // depending on the value passed as the 'wait' (2nd) parameter.
145 //
146 // Connect(addr, true) will wait until the connection completes,
147 // returning true on success and false on failure. This call blocks
148 // the GUI (this might be changed in future releases to honor the
149 // wxSOCKET_BLOCK flag).
150 //
151 // Connect(addr, false) will issue a nonblocking connection request
152 // and return immediately. If the return value is true, then the
153 // connection has been already successfully established. If it is
154 // false, you must wait for the request to complete, either with
155 // WaitOnConnect() or by watching wxSOCKET_CONNECTION / LOST
156 // events (please read the documentation).
157 //
158 // WaitOnConnect() itself never blocks the GUI (this might change
159 // in the future to honor the wxSOCKET_BLOCK flag). This call will
160 // return false on timeout, or true if the connection request
161 // completes, which in turn might mean:
162 //
163 // a) That the connection was successfully established
164 // b) That the connection request failed (for example, because
165 // it was refused by the peer.
166 //
167 // Use IsConnected() to distinguish between these two.
168 //
169 // So, in a brief, you should do one of the following things:
170 //
171 // For blocking Connect:
172 //
173 // bool success = client->Connect(addr, true);
174 //
175 // For nonblocking Connect:
176 //
177 // client->Connect(addr, false);
178 //
179 // bool waitmore = true;
180 // while (! client->WaitOnConnect(seconds, millis) && waitmore )
181 // {
182 // // possibly give some feedback to the user,
183 // // update waitmore if needed.
184 // }
185 // bool success = client->IsConnected();
186 //
187 // And that's all :-)
188
189 sock_client = new wxSocketClient( wxSOCKET_BLOCK );
190 sock_client->SetTimeout( 1 ); // Time out in Seconds
191 sock_client->Connect( addr, false );
192 sock_client->WaitOnConnect( 0, 250 );
193
194 if( sock_client->Ok() && sock_client->IsConnected() )
195 {
196 sock_client->SetFlags( wxSOCKET_NOWAIT /*wxSOCKET_WAITALL*/ );
197 sock_client->Write( message.c_str(), message.length() );
198 }
199
200 sock_client->Close();
201 sock_client->Destroy();
202
203 m_messageReady = false;
204
205 lock.lock();
206 }
207 }
208
209 std::thread m_thread;
210 std::pair<int, std::string> m_message;
212 mutable std::mutex m_mutex;
213 std::condition_variable m_cv;
215};
216
217
218std::unique_ptr<ASYNC_SOCKET_HOLDER> socketHolder = nullptr;
219
220
230bool SendCommand( int aService, const std::string& aMessage )
231{
232 if( !socketHolder )
233 socketHolder.reset( new ASYNC_SOCKET_HOLDER() );
234
235 return socketHolder->Send( aService, aMessage );
236}
237
238
240{
241 if( socketHolder )
242 socketHolder.reset();
243}
Spin up a thread to send messages via a socket.
Definition eda_dde.cpp:47
void worker()
Actual task that sends data to the socket server.
Definition eda_dde.cpp:113
std::condition_variable m_cv
Definition eda_dde.cpp:213
std::mutex m_mutex
Definition eda_dde.cpp:212
std::pair< int, std::string > m_message
Definition eda_dde.cpp:210
std::thread m_thread
Definition eda_dde.cpp:209
bool Send(int aService, const std::string &aMessage)
Attempt to send a message if the thread is available.
Definition eda_dde.cpp:95
std::unique_ptr< ASYNC_SOCKET_HOLDER > socketHolder
Definition eda_dde.cpp:218
bool SendCommand(int aService, const std::string &aMessage)
Used by a client to sent (by a socket connection) a data to a server.
Definition eda_dde.cpp:230
void SocketCleanup()
Must be called to clean up the socket thread used by SendCommand.
Definition eda_dde.cpp:239
static const wxString HOSTNAME(wxT("localhost"))
DDE server & client.
#define KICAD_PCB_PORT_SERVICE_NUMBER
Pcbnew listens on this port for commands from Eeschema.
Definition eda_dde.h:40