Power System Platform  2026w23a-beta
Loading...
Searching...
No Matches
ATPPSPBridge.cpp
1#include "ATPPSPBridge.h"
2#include <wx/process.h>
3
4
5namespace
6{
7#ifdef _WIN32
8
9 constexpr wchar_t ATP_EVENT[] = L"PSPBridge_ATPReady";
10 constexpr wchar_t PSP_EVENT[] = L"PSPBridge_PSPReady";
11 constexpr wchar_t SHM_NAME[] = L"PSPBridgeSharedMemory";
12
13#else
14
15 // POSIX object names must begin with '/'
16 constexpr char ATP_EVENT[] = "/PSPBridge_ATPReady";
17 constexpr char PSP_EVENT[] = "/PSPBridge_PSPReady";
18 constexpr char SHM_NAME[] = "/PSPBridgeSharedMemory";
19
20#endif
21}
22
23ATPPSPBridge::ATPPSPBridge()
24{
25}
26
27ATPPSPBridge::~ATPPSPBridge()
28{
29 Disconnect();
30}
31
32bool ATPPSPBridge::Connect(unsigned timeout, unsigned retryInterval)
33{
34 wxStopWatch sw;
35 wxProgressDialog wait(_("Connecting"), _("Connecting to ATP, please wait."), timeout, nullptr, wxPD_AUTO_HIDE | wxPD_SMOOTH | wxPD_CAN_ABORT);
36
37 while (true)
38 {
39 if (!wait.Update(sw.Time()))
40 return false;
41
42 Disconnect();
43
44#ifdef _WIN32
45
46 // ATP event
47 m_hATPReady = OpenEventW(SYNCHRONIZE, FALSE, ATP_EVENT);
48
49 if (m_hATPReady)
50 {
51 // PSP event
52 m_hPSPReady = OpenEventW(EVENT_MODIFY_STATE | SYNCHRONIZE, FALSE, PSP_EVENT);
53
54 if (m_hPSPReady)
55 {
56 // Shared memory
57 m_hMapFile = OpenFileMappingW(FILE_MAP_ALL_ACCESS, FALSE, SHM_NAME);
58
59 if (m_hMapFile)
60 {
61 m_data = static_cast<SharedData*>(MapViewOfFile(m_hMapFile, FILE_MAP_ALL_ACCESS, 0, 0, 0));
62
63 if (m_data)
64 return true;
65 }
66 }
67 }
68
69#else
70
71 // ATP semaphore
72 m_hATPReady = sem_open(ATP_EVENT, 0);
73
74 if (m_hATPReady != SEM_FAILED)
75 {
76 // PSP semaphore
77 m_hPSPReady = sem_open(PSP_EVENT, 0);
78
79 if (m_hPSPReady != SEM_FAILED)
80 {
81 // Shared memory
82 m_hMapFile = shm_open(SHM_NAME, O_RDWR, 0);
83
84 if (m_hMapFile >= 0)
85 {
86 m_data = nullptr;
87 struct stat st;
88 if (fstat(m_hMapFile, &st) == 0)
89 m_data = static_cast<SharedData*>(mmap(nullptr, st.st_size, PROT_READ | PROT_WRITE, MAP_SHARED, m_hMapFile, 0));
90
91 if (m_data != MAP_FAILED)
92 return true;
93
94 m_data = nullptr;
95 }
96 }
97 }
98
99#endif
100
101 Disconnect();
102
103 if (sw.Time() >= timeout)
104 return false;
105
106 wxMilliSleep(retryInterval);
107 wxTheApp->Yield();
108 }
109}
110
111void ATPPSPBridge::Disconnect()
112{
113#ifdef _WIN32
114
115 if (m_data) {
116 UnmapViewOfFile(m_data);
117 m_data = nullptr;
118 }
119
120 if (m_hMapFile) {
121 CloseHandle(m_hMapFile);
122 m_hMapFile = nullptr;
123 }
124
125 if (m_hATPReady) {
126 CloseHandle(m_hATPReady);
127 m_hATPReady = nullptr;
128 }
129
130 if (m_hPSPReady) {
131 CloseHandle(m_hPSPReady);
132 m_hPSPReady = nullptr;
133 }
134
135#else
136
137 if (m_data) {
138 struct stat st;
139 if (m_hMapFile >= 0 && fstat(m_hMapFile, &st) == 0)
140 munmap(m_data, st.st_size);
141
142 m_data = nullptr;
143 }
144
145 if (m_hMapFile >= 0) {
146 close(m_hMapFile);
147 m_hMapFile = -1;
148 }
149
150 if (m_hATPReady != SEM_FAILED) {
151 sem_close(m_hATPReady);
152 m_hATPReady = SEM_FAILED;
153 }
154
155 if (m_hPSPReady != SEM_FAILED) {
156 sem_close(m_hPSPReady);
157 m_hPSPReady = SEM_FAILED;
158 }
159
160#endif
161 m_atpPid = 0;
162}
163
164bool ATPPSPBridge::WaitATP()
165{
166#ifdef _WIN32
167
168 if (!m_hATPReady)
169 return false;
170
171 while (true)
172 {
173 DWORD ret = WaitForSingleObject(m_hATPReady, 100);
174
175 switch (ret)
176 {
177 case WAIT_OBJECT_0:
178 // ATP signaled
179 return true;
180
181 case WAIT_TIMEOUT:
182 // Check whether ATP is still running
183 if (m_atpPid != 0 && !wxProcess::Exists(m_atpPid))
184 return false;
185 break;
186
187 default:
188 return false;
189 }
190 }
191
192#else
193
194 if (m_hATPReady == SEM_FAILED)
195 return false;
196
197 while (true)
198 {
199 timespec ts;
200 if (clock_gettime(CLOCK_REALTIME, &ts) != 0)
201 return false;
202
203 ts.tv_nsec += 100000000; // 100 ms
204
205 if (ts.tv_nsec >= 1000000000)
206 {
207 ts.tv_sec++;
208 ts.tv_nsec -= 1000000000;
209 }
210
211 if (sem_timedwait(m_hATPReady, &ts) == 0)
212 return true;
213
214 if (errno != ETIMEDOUT)
215 return false;
216
217 // Check whether ATP is still running
218 if (m_atpPid != 0 && !wxProcess::Exists(m_atpPid))
219 return false;
220 }
221
222#endif
223}
224
225bool ATPPSPBridge::ReleaseATP()
226{
227#ifdef _WIN32
228
229 if (!m_hPSPReady)
230 return false;
231
232 return SetEvent(m_hPSPReady) != FALSE;
233
234#else
235
236 if (m_hPSPReady == SEM_FAILED)
237 return false;
238
239 return sem_post(m_hPSPReady) == 0;
240
241#endif
242}
243
244SharedData& ATPPSPBridge::GetSharedData() const
245{
246 return *m_data;
247}
248
249bool ATPPSPBridge::IsConnected() const
250{
251 return m_data != nullptr;
252}