OpenCPN Partial API docs
Loading...
Searching...
No Matches
SencManager.cpp
1/***************************************************************************
2 *
3 * Project: OpenCPN
4 * Purpose: S57 Chart Object
5 * Author: David Register
6 *
7 ***************************************************************************
8 * Copyright (C) 2010 by David S. Register *
9 * *
10 * This program is free software; you can redistribute it and/or modify *
11 * it under the terms of the GNU General Public License as published by *
12 * the Free Software Foundation; either version 2 of the License, or *
13 * (at your option) any later version. *
14 * *
15 * This program is distributed in the hope that it will be useful, *
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
18 * GNU General Public License for more details. *
19 * *
20 * You should have received a copy of the GNU General Public License *
21 * along with this program; if not, write to the *
22 * Free Software Foundation, Inc., *
23 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *
24 **************************************************************************/
25
26// For compilers that support precompilation, includes "wx.h".
27#include "wx/wxprec.h"
28
29#ifndef WX_PRECOMP
30#include "wx/wx.h"
31#endif // precompiled headers
32
33#include "s57chart.h"
34#include "Osenc.h"
35#include "chartbase.h"
36#include "chcanv.h"
37#include "ocpn_frame.h"
38
39extern MyFrame *gFrame;
40extern int g_nCPUCount;
41extern S57ClassRegistrar *g_poRegistrar;
42
43SENCThreadManager *g_SencThreadManager;
44
45//----------------------------------------------------------------------------------
46// SENCJobTicket Implementation
47//----------------------------------------------------------------------------------
48SENCJobTicket::SENCJobTicket() {
49 m_SENCResult = SENC_BUILD_INACTIVE;
50 m_status = THREAD_INACTIVE;
51}
52
53const wxEventType wxEVT_OCPN_BUILDSENCTHREAD = wxNewEventType();
54
55//----------------------------------------------------------------------------------
56// OCPN_BUILDSENC_ThreadEvent Implementation
57//----------------------------------------------------------------------------------
58OCPN_BUILDSENC_ThreadEvent::OCPN_BUILDSENC_ThreadEvent(wxEventType commandType,
59 int id)
60 : wxEvent(id, commandType) {
61 stat = 0;
62}
63
64OCPN_BUILDSENC_ThreadEvent::~OCPN_BUILDSENC_ThreadEvent() {}
65
66wxEvent *OCPN_BUILDSENC_ThreadEvent::Clone() const {
68 newevent->stat = this->stat;
69 newevent->type = this->type;
70 newevent->m_ticket = this->m_ticket;
71
72 return newevent;
73}
74
75//----------------------------------------------------------------------------------
76// SENCThreadManager Implementation
77//----------------------------------------------------------------------------------
78SENCThreadManager::SENCThreadManager() {
79 // ideally we would use the cpu count -1, and only launch jobs
80 // when the idle load average is sufficient (greater than 1)
81 int nCPU = wxMax(1, wxThread::GetCPUCount());
82 if (g_nCPUCount > 0) nCPU = g_nCPUCount;
83
84 // obviously there's at least one CPU!
85 if (nCPU < 1) nCPU = 1;
86
87 m_max_jobs = wxMax(nCPU - 1, 1);
88 // m_max_jobs = 1;
89
90 wxLogDebug("SENC: nCPU: %d m_max_jobs :%d\n", nCPU, m_max_jobs);
91
92 // Create/connect a dynamic event handler slot for messages from the worker
93 // threads
94 Connect(
95 wxEVT_OCPN_BUILDSENCTHREAD,
96 (wxObjectEventFunction)(wxEventFunction)&SENCThreadManager::OnEvtThread);
97
98 // m_timer.Connect(wxEVT_TIMER, wxTimerEventHandler(
99 // glTextureManager::OnTimer ), NULL, this); m_timer.Start(500);
100}
101
102SENCThreadManager::~SENCThreadManager() {
103 // ClearJobList();
104}
105
106SENCThreadStatus SENCThreadManager::ScheduleJob(SENCJobTicket *ticket) {
107 // Do not add a job if there is already a job pending for this chart, by name
108 for (size_t i = 0; i < ticket_list.size(); i++) {
109 if (ticket_list[i]->m_FullPath000 == ticket->m_FullPath000)
110 return THREAD_PENDING;
111 }
112
113 ticket->m_status = THREAD_PENDING;
114 ticket_list.push_back(ticket);
115
116 // printf("Scheduling job: %s\n", (const
117 // char*)ticket->m_FullPath000.mb_str()); printf("Job count: %d\n",
118 // ticket_list.size());
119 StartTopJob();
120 return THREAD_PENDING;
121}
122
123void SENCThreadManager::StartTopJob() {
124 SENCJobTicket *startCandidate;
125 // Get the running job count
126 int nRunning = 0;
127 for (size_t i = 0; i < ticket_list.size(); i++) {
128 if (ticket_list[i]->m_status == THREAD_STARTED) nRunning++;
129 }
130
131 // OK to start one?
132 if (nRunning < m_max_jobs) {
133 // Find the first eligible
134 startCandidate = NULL;
135 for (size_t i = 0; i < ticket_list.size(); i++) {
136 if (ticket_list[i]->m_status == THREAD_PENDING) {
137 startCandidate = ticket_list[i];
138 break;
139 }
140 }
141
142 // Found one?
143 if (startCandidate) {
144 // printf("Starting job: %s\n", (const
145 // char*)startCandidate->m_FullPath000.mb_str());
146
147 SENCBuildThread *thread = new SENCBuildThread(startCandidate, this);
148 startCandidate->m_thread = thread;
149 startCandidate->m_status = THREAD_STARTED;
150 thread->SetPriority(20);
151 thread->Run();
152 nRunning++;
153 }
154 }
155
156 if (nRunning) {
157 wxString count;
158 count.Printf(" %ld", ticket_list.size());
159 if (gFrame->GetPrimaryCanvas())
160 gFrame->GetPrimaryCanvas()->SetAlertString(_("Preparing vector chart ") +
161 count);
162 }
163}
164
165void SENCThreadManager::FinishJob(SENCJobTicket *ticket) {
166 // printf("Finishing job: %s\n", (const
167 // char*)ticket->m_FullPath000.mb_str());
168
169 // Find and remove the ticket from the list
170 for (size_t i = 0; i < ticket_list.size(); i++) {
171 if (ticket_list[i] == ticket) {
172 // printf(" Removing job: %s\n", (const
173 // char*)ticket->m_FullPath000.mb_str());
174
175 ticket_list.erase(ticket_list.begin() + i);
176 // printf("Job count: %d\n", ticket_list.size());
177
178 break;
179 }
180 }
181
182#if 1
183 int nRunning = 0;
184 for (size_t i = 0; i < ticket_list.size(); i++) {
185 if (ticket_list[i]->m_status == THREAD_STARTED) nRunning++;
186 }
187
188 if (nRunning) {
189 wxString count;
190 count.Printf(" %ld", ticket_list.size());
191 if (gFrame->GetPrimaryCanvas())
192 gFrame->GetPrimaryCanvas()->SetAlertString(_("Preparing vector chart ") +
193 count);
194 } else {
195 if (gFrame->GetPrimaryCanvas())
196 gFrame->GetPrimaryCanvas()->SetAlertString("");
197 }
198#endif
199}
200
201int SENCThreadManager::GetJobCount() { return ticket_list.size(); }
202
203bool SENCThreadManager::IsChartInTicketlist(s57chart *chart) {
204 for (size_t i = 0; i < ticket_list.size(); i++) {
205 if (ticket_list[i]->m_chart == chart) return true;
206 }
207 return false;
208}
209
210bool SENCThreadManager::SetChartPointer(s57chart *chart, void *new_ptr) {
211 // Find the ticket
212 for (size_t i = 0; i < ticket_list.size(); i++) {
213 if (ticket_list[i]->m_chart == chart) {
214 ticket_list[i]->m_chart = (s57chart *)new_ptr;
215 return true;
216 }
217 }
218 return false;
219}
220
221#define NBAR_LENGTH 40
222
223void SENCThreadManager::OnEvtThread(OCPN_BUILDSENC_ThreadEvent &event) {
224 OCPN_BUILDSENC_ThreadEvent Sevent(wxEVT_OCPN_BUILDSENCTHREAD, 0);
225
226 switch (event.type) {
227 case SENC_BUILD_STARTED:
228 // printf("SENC build started\n");
229 Sevent.type = SENC_BUILD_STARTED;
230 Sevent.m_ticket = event.m_ticket;
231
232 break;
233 case SENC_BUILD_DONE_NOERROR:
234 // printf("SENC build done no error\n");
235 Sevent.type = SENC_BUILD_DONE_NOERROR;
236 Sevent.m_ticket = event.m_ticket;
237 FinishJob(event.m_ticket);
238 StartTopJob();
239
240 break;
241 case SENC_BUILD_DONE_ERROR:
242 // printf("SENC build done ERROR\n");
243 Sevent.type = SENC_BUILD_DONE_ERROR;
244 Sevent.m_ticket = event.m_ticket;
245 FinishJob(event.m_ticket);
246 StartTopJob();
247
248 break;
249 default:
250 break;
251 }
252 if (gFrame) gFrame->GetEventHandler()->AddPendingEvent(Sevent);
253}
254
255//----------------------------------------------------------------------------------
256// SENCBuildThread Implementation
257//----------------------------------------------------------------------------------
258
259SENCBuildThread::SENCBuildThread(SENCJobTicket *ticket,
260 SENCThreadManager *manager) {
261 m_FullPath000 = ticket->m_FullPath000;
262 m_SENCFileName = ticket->m_SENCFileName;
263 m_manager = manager;
264 m_ticket = ticket;
265
266 Create();
267}
268
269void *SENCBuildThread::Entry() {
270 // #ifdef __MSVC__
271 // _set_se_translator(my_translate);
272
273 // On Windows, if anything in this thread produces a SEH exception (like
274 // access violation) we handle the exception locally, and simply alow the
275 // thread to exit smoothly with no results. Upstream will notice that nothing
276 // got done, and maybe try again later.
277
278 try
279 // #endif
280 {
281 // Start the SENC build
282 Osenc senc;
283
284 senc.setRegistrar(g_poRegistrar);
285 senc.setRefLocn(m_ticket->ref_lat, m_ticket->ref_lon);
286 senc.SetLODMeters(m_ticket->m_LOD_meters);
287 senc.setNoErrDialog(true);
288
289 m_ticket->m_SENCResult = SENC_BUILD_STARTED;
290 OCPN_BUILDSENC_ThreadEvent Sevent(wxEVT_OCPN_BUILDSENCTHREAD, 0);
291 Sevent.stat = 0;
292 Sevent.type = SENC_BUILD_STARTED;
293 Sevent.m_ticket = m_ticket;
294 if (m_manager) m_manager->QueueEvent(Sevent.Clone());
295
296 int ret = senc.createSenc200(m_FullPath000, m_SENCFileName, false);
297
298 OCPN_BUILDSENC_ThreadEvent Nevent(wxEVT_OCPN_BUILDSENCTHREAD, 0);
299 Nevent.stat = ret;
300 Nevent.m_ticket = m_ticket;
301 if (ret == ERROR_INGESTING000)
302 Nevent.type = SENC_BUILD_DONE_ERROR;
303 else
304 Nevent.type = SENC_BUILD_DONE_NOERROR;
305
306 m_ticket->m_SENCResult = Sevent.type;
307 if (m_manager) m_manager->QueueEvent(Nevent.Clone());
308
309 // if(ret == ERROR_INGESTING000)
310 // return BUILD_SENC_NOK_PERMANENT;
311 // else
312 // return ret;
313
314 return 0;
315 } // try
316
317 // #ifdef __MSVC__
318 catch (const std::exception &e /*SE_Exception e*/) {
319 const char *msg = e.what();
320 if (m_manager) {
321 // OCPN_CompressionThreadEvent
322 // Nevent(wxEVT_OCPN_COMPRESSIONTHREAD, 0);
323 // m_ticket->b_isaborted = true;
324 // Nevent.SetTicket(m_ticket);
325 // Nevent.type = 0;
326 // m_manager->QueueEvent(Nevent.Clone());
327 }
328
329 return 0;
330 }
331 // #endif
332}
General chart base definitions.
Generic Chart canvas base.
Main application frame.
Definition ocpn_frame.h:138
Definition Osenc.h:401
Manager for S57 chart SENC creation threads.
Represents an S57 format electronic navigational chart in OpenCPN.
Definition s57chart.h:122