UbiAnyCard Ver2 2.0
KICC ED785 단말기 연동 TCP 서버
로딩중...
검색중...
일치하는것 없음
ED785Worker 클래스 참조final

#include <ED785Worker.h>

ED785Worker에 대한 협력 다이어그램:
Collaboration graph

클래스

struct  Request
struct  Response

Public 타입

using ResponseCallback = std::function<void(const Response &)>

Public 멤버 함수

 ED785Worker ()
bool enqueue (const Request &req)
bool start (int comPort, int baudRate, ResponseCallback callback)
void stop ()
 ~ED785Worker ()

정적 Public 속성

static constexpr int ResponseCmdInternal = 0xFFFF
static constexpr int ResponseGcdInitializationFailure = 0x0001
static constexpr int ResponseJcdInitializationFailure = 0x0001

Private 멤버 함수

bool createDummyWindow ()
void destroyDummyWindow ()
bool initializeED785 (int comPort, int baudRate)
void notifyInitializationFailure (const std::string &reason)
void shutdownED785 ()
void workerThread ()

정적 Private 멤버 함수

static LRESULT CALLBACK DummyWndProc (HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)

Private 속성

int m_baudRate
ResponseCallback m_callback
int m_comPort
std::mutex m_currentMutex
std::unique_ptr< CED785m_ed785
int m_expectGcd {-1}
int m_expectJcd {-1}
HWND m_hDummyWnd {nullptr}
std::mutex m_queueMutex
std::deque< Requestm_requestQueue
std::atomic< bool > m_running {false}
std::thread m_thread

멤버 타입정의 문서화

◆ ResponseCallback

using ED785Worker::ResponseCallback = std::function<void(const Response &)>

생성자 & 소멸자 문서화

◆ ED785Worker()

ED785Worker::ED785Worker ( )
14 : m_comPort(0), m_baudRate(0)
15{
16}
int m_comPort
Definition ED785Worker.h:72
int m_baudRate
Definition ED785Worker.h:73

다음을 참조함 : m_baudRate, m_comPort.

◆ ~ED785Worker()

ED785Worker::~ED785Worker ( )
19{
20 stop();
21}
void stop()
Definition ED785Worker.cpp:47

다음을 참조함 : stop().

이 함수 내부에서 호출하는 함수들에 대한 그래프입니다.:

멤버 함수 문서화

◆ createDummyWindow()

bool ED785Worker::createDummyWindow ( )
private
78{
79 // 윈도우 클래스 등록
80 WNDCLASSEXW wc = {0};
81 wc.cbSize = sizeof(WNDCLASSEXW);
82 wc.lpfnWndProc = DummyWndProc;
83 wc.hInstance = GetModuleHandleW(nullptr);
84 wc.lpszClassName = L"ED785WorkerDummy";
85
86 if (!RegisterClassExW(&wc))
87 {
88 DWORD err = GetLastError();
89 if (err != ERROR_CLASS_ALREADY_EXISTS)
90 {
91 Logger::error(std::wstring(L"ED785Worker - 윈도우 클래스 등록 실패: ") + std::to_wstring(err));
92 return false;
93 }
94 }
95
96 // 숨겨진 윈도우 생성
97 m_hDummyWnd = CreateWindowExW(
98 0, L"ED785WorkerDummy", L"ED785Worker",
99 WS_OVERLAPPEDWINDOW, 0, 0, 1, 1,
100 nullptr, nullptr, GetModuleHandleW(nullptr), this);
101
102 if (!m_hDummyWnd)
103 {
104 Logger::error(L"ED785Worker - 숨겨진 윈도우 생성 실패");
105 return false;
106 }
107
108 Logger::info(L"ED785Worker - 숨겨진 윈도우 생성 완료");
109 return true;
110}
HWND m_hDummyWnd
Definition ED785Worker.h:90
static LRESULT CALLBACK DummyWndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
Definition ED785Worker.cpp:121

다음을 참조함 : DummyWndProc(), m_hDummyWnd.

다음에 의해서 참조됨 : initializeED785().

이 함수 내부에서 호출하는 함수들에 대한 그래프입니다.:
이 함수를 호출하는 함수들에 대한 그래프입니다.:

◆ destroyDummyWindow()

void ED785Worker::destroyDummyWindow ( )
private
113{
114 if (m_hDummyWnd)
115 {
116 DestroyWindow(m_hDummyWnd);
117 m_hDummyWnd = nullptr;
118 }
119}

다음을 참조함 : m_hDummyWnd.

다음에 의해서 참조됨 : initializeED785(), shutdownED785().

이 함수를 호출하는 함수들에 대한 그래프입니다.:

◆ DummyWndProc()

LRESULT CALLBACK ED785Worker::DummyWndProc ( HWND hwnd,
UINT msg,
WPARAM wParam,
LPARAM lParam )
staticprivate
122{
123 // DLL에서 보내는 메시지 처리 (필요 시)
124 return DefWindowProcW(hwnd, msg, wParam, lParam);
125}

다음에 의해서 참조됨 : createDummyWindow().

이 함수를 호출하는 함수들에 대한 그래프입니다.:

◆ enqueue()

bool ED785Worker::enqueue ( const Request & req)
62{
63 std::scoped_lock lock(m_queueMutex);
64 if (m_requestQueue.size() > 100)
65 {
66 Logger::error(L"ED785Worker - 요청 큐 초과");
67 return false;
68 }
69
70 m_requestQueue.push_back(req);
71 wchar_t logBuf[128];
72 swprintf_s(logBuf, L"ED785Worker - 요청 큐에 추가 (큐 크기: %zu)", m_requestQueue.size());
73 Logger::debug(logBuf);
74 return true;
75}
std::mutex m_queueMutex
Definition ED785Worker.h:76
std::deque< Request > m_requestQueue
Definition ED785Worker.h:77

다음을 참조함 : m_queueMutex, m_requestQueue.

◆ initializeED785()

bool ED785Worker::initializeED785 ( int comPort,
int baudRate )
private
146{
147 // 숨겨진 윈도우 생성 (DLL이 윈도우 메시지를 사용할 수 있도록)
148 if (!createDummyWindow())
149 {
150 Logger::warn(L"ED785Worker - 윈도우 생성 실패");
151 notifyInitializationFailure("DUMMY_WINDOW_CREATE_FAILED");
152 return false;
153 }
154
155 // DLL 로드 및 함수 포인터 연결
156 m_ed785 = std::make_unique<CED785>();
157
158 // 윈도우 핸들 전달 (DLL이 메시지 기반일 수 있음)
159 int initResult = m_ed785->InitLoadLibrary(m_hDummyWnd);
160 if (initResult != TRUE)
161 {
162 wchar_t errBuf[128];
163 swprintf_s(errBuf, L"ED785Worker - DLL 로드 실패: %d", initResult);
164 Logger::error(errBuf);
166 notifyInitializationFailure("DLL_LOAD_FAILED:" + std::to_string(initResult));
167 return false;
168 }
169
170 Logger::info(L"ED785Worker - DLL 로드 완료");
171
172 // 시리얼 포트 연결
173 byte errMsg[512] = {0};
174 int loadResult = m_ed785->KLoad(comPort, baudRate, errMsg);
175 if (loadResult == -1)
176 {
177 // errMsg는 ASCII이므로 변환 필요
178 std::string errStrA(reinterpret_cast<char *>(errMsg));
179 int wlen = ::MultiByteToWideChar(CP_ACP, 0, errStrA.c_str(), -1, nullptr, 0);
180 std::wstring errStr;
181 if (wlen > 0)
182 {
183 errStr.resize(wlen);
184 ::MultiByteToWideChar(CP_ACP, 0, errStrA.c_str(), -1, errStr.data(), wlen);
185 }
186 Logger::error(L"ED785Worker - 시리얼 포트 연결 실패: " + errStr);
187 std::string notifyReason = errStrA.empty() ? "PORT_OPEN_FAILED" : errStrA;
188 notifyInitializationFailure(notifyReason);
189 m_ed785.reset();
191 return false;
192 }
193
194 wchar_t portLogBuf[128];
195 swprintf_s(portLogBuf, L"ED785Worker - 시리얼 포트 연결 완료 (COM%d, %d bps)", comPort, baudRate);
196 Logger::info(portLogBuf);
197
198 // 초기화 완료 - 단말정보는 TERMINFO 명령으로 별도 요청
199 // (초기화 시 직접 요청하면 응답 순서가 꼬여서 제거)
200 Logger::info(L"ED785Worker - 초기화 완료, 이벤트 폴링 시작");
201
202 return true;
203}
bool createDummyWindow()
Definition ED785Worker.cpp:77
std::unique_ptr< CED785 > m_ed785
Definition ED785Worker.h:67
void notifyInitializationFailure(const std::string &reason)
Definition ED785Worker.cpp:127
void destroyDummyWindow()
Definition ED785Worker.cpp:112

다음을 참조함 : createDummyWindow(), destroyDummyWindow(), m_ed785, m_hDummyWnd, notifyInitializationFailure().

다음에 의해서 참조됨 : workerThread().

이 함수 내부에서 호출하는 함수들에 대한 그래프입니다.:
이 함수를 호출하는 함수들에 대한 그래프입니다.:

◆ notifyInitializationFailure()

void ED785Worker::notifyInitializationFailure ( const std::string & reason)
private
128{
129 if (!m_callback)
130 return;
131
132 Response resp{};
136 resp.rcd = 0xFF;
137 resp.data.assign(reason.begin(), reason.end());
138 resp.dataLen = resp.data.size();
139 resp.hex.clear();
140 resp.hexLen = 0;
141
142 m_callback(resp);
143}
static constexpr int ResponseJcdInitializationFailure
Definition ED785Worker.h:18
ResponseCallback m_callback
Definition ED785Worker.h:82
static constexpr int ResponseGcdInitializationFailure
Definition ED785Worker.h:17
static constexpr int ResponseCmdInternal
Definition ED785Worker.h:16
Definition ED785Worker.h:31
int cmd
Definition ED785Worker.h:32

다음을 참조함 : ED785Worker::Response::cmd, ED785Worker::Response::data, ED785Worker::Response::dataLen, ED785Worker::Response::gcd, ED785Worker::Response::hex, ED785Worker::Response::hexLen, ED785Worker::Response::jcd, m_callback, ED785Worker::Response::rcd, ResponseCmdInternal, ResponseGcdInitializationFailure, ResponseJcdInitializationFailure.

다음에 의해서 참조됨 : initializeED785().

이 함수를 호출하는 함수들에 대한 그래프입니다.:

◆ shutdownED785()

void ED785Worker::shutdownED785 ( )
private
206{
207 if (!m_ed785)
208 return;
209
210 // 단말기 초기화 (대기 화면으로 복귀) - 0xFB, 0x14, 0x01
211 byte emptyData[512] = {0};
212 m_ed785->KReqCmd(0xFB, 0x14, 0x01, emptyData, emptyData);
213 Logger::info(L"ED785Worker - 단말기 대기 화면 복귀");
214
215 // 포트 연결 해제
216 m_ed785->KUnLoad();
217 Logger::info(L"ED785Worker - 시리얼 포트 연결 해제");
218
219 m_ed785.reset();
220
221 // 윈도우 제거
223}

다음을 참조함 : destroyDummyWindow(), m_ed785.

다음에 의해서 참조됨 : workerThread().

이 함수 내부에서 호출하는 함수들에 대한 그래프입니다.:
이 함수를 호출하는 함수들에 대한 그래프입니다.:

◆ start()

bool ED785Worker::start ( int comPort,
int baudRate,
ResponseCallback callback )
24{
25 if (m_running.load())
26 {
27 Logger::warn(L"ED785Worker - 이미 실행 중");
28 return false;
29 }
30
31 m_comPort = comPort;
32 m_baudRate = baudRate;
33 m_callback = std::move(callback);
34
35 // 워커 스레드 시작 (DLL 초기화는 워커 스레드 내에서 수행)
36 m_running = true;
37 m_thread = std::thread([this]()
38 { workerThread(); });
39
40 // 초기화 시간 확보
41 std::this_thread::sleep_for(std::chrono::milliseconds(500));
42
43 Logger::info(L"ED785Worker - 시작 완료");
44 return true;
45}
std::thread m_thread
Definition ED785Worker.h:68
std::atomic< bool > m_running
Definition ED785Worker.h:69
void workerThread()
Definition ED785Worker.cpp:225

다음을 참조함 : m_baudRate, m_callback, m_comPort, m_running, m_thread, workerThread().

다음에 의해서 참조됨 : wWinMain().

이 함수 내부에서 호출하는 함수들에 대한 그래프입니다.:
이 함수를 호출하는 함수들에 대한 그래프입니다.:

◆ stop()

void ED785Worker::stop ( )
48{
49 if (!m_running.load())
50 return;
51
52 Logger::info(L"ED785Worker - 중지 시작");
53
54 m_running = false;
55 if (m_thread.joinable())
56 m_thread.join();
57
58 Logger::info(L"ED785Worker - 중지 완료");
59}

다음을 참조함 : m_running, m_thread.

다음에 의해서 참조됨 : wWinMain(), ~ED785Worker().

이 함수를 호출하는 함수들에 대한 그래프입니다.:

◆ workerThread()

void ED785Worker::workerThread ( )
private
226{
227 Logger::info(L"ED785Worker - 워커 스레드 시작");
228
229 // 워커 스레드에서 DLL 초기화 (단일 스레드 보장)
231 {
232 Logger::error(L"ED785Worker - 초기화 실패, 워커 스레드 종료");
233 m_running = false;
234 return;
235 }
236
237 // 메인 루프: 윈도우 메시지 처리 + 요청 처리 + 이벤트 폴링
238 while (m_running.load())
239 {
240 // 0. 윈도우 메시지 처리 (DLL이 윈도우 메시지를 사용할 수 있음)
241 MSG msg;
242 while (PeekMessageW(&msg, nullptr, 0, 0, PM_REMOVE))
243 {
244 TranslateMessage(&msg);
245 DispatchMessageW(&msg);
246 }
247
248 // 1. 요청 큐에서 명령 꺼내기
249 Request req;
250 bool hasRequest = false;
251 {
252 std::scoped_lock lock(m_queueMutex);
253 if (!m_requestQueue.empty())
254 {
255 req = m_requestQueue.front();
256 m_requestQueue.pop_front();
257 hasRequest = true;
258 }
259 }
260
261 // 2. 요청이 있으면 전송
262 if (hasRequest)
263 {
264 wchar_t logBuf[256];
265 swprintf_s(logBuf, L"ED785Worker - 명령 전송: CMD=0x%02X GCD=0x%02X JCD=0x%02X",
266 req.cmd, req.gcd, req.jcd);
267 Logger::info(logBuf);
268
269 // 현재 기대 응답 설정 (응답 매칭용)
270 {
271 std::scoped_lock lock(m_currentMutex);
272 m_expectGcd = req.gcd;
273 m_expectJcd = req.jcd;
274 }
275
276 // KReqCmd 호출
277 byte sendData[8192] = {0};
278 byte errMsg[512] = {0};
279
280 // payload를 sendData에 복사 (최대 8192 바이트)
281 size_t copyLen = (req.payload.size() < sizeof(sendData)) ? req.payload.size() : sizeof(sendData);
282 if (copyLen > 0)
283 memcpy(sendData, req.payload.data(), copyLen);
284
285 int cmdResult = m_ed785->KReqCmd(req.cmd, req.gcd, req.jcd, sendData, errMsg);
286 if (cmdResult != 0)
287 {
288 wchar_t warnBuf[128];
289 swprintf_s(warnBuf, L"ED785Worker - KReqCmd 실패: %d", cmdResult);
290 Logger::warn(warnBuf);
291 // 실패 응답 콜백 호출
292 if (m_callback)
293 {
294 Response resp;
295 resp.cmd = req.cmd;
296 resp.gcd = req.gcd;
297 resp.jcd = req.jcd;
298 resp.rcd = 0xFF; // RC_FAILURE
299 resp.data.resize(512);
300 memcpy(resp.data.data(), errMsg, 512);
301 resp.dataLen = strlen(reinterpret_cast<char *>(errMsg));
302 resp.hexLen = 0;
303 m_callback(resp);
304 }
305
306 // 기대 응답 초기화
307 {
308 std::scoped_lock lock(m_currentMutex);
309 m_expectGcd = -1;
310 m_expectJcd = -1;
311 }
312 continue;
313 }
314
315 Logger::debug(L"ED785Worker - KReqCmd 전송 완료, 응답 대기 시작");
316 }
317
318 // 3. KGetEvent로 이벤트 폴링 (항상 수행)
319 int cmd = 0, gcd = 0, jcd = 0, rcd = 0;
320 byte rdata[8192] = {0};
321 byte hexdata[8192] = {0};
322
323 int eventResult = m_ed785->KGetEvent(cmd, gcd, jcd, rcd, rdata, hexdata);
324
325#pragma region TEST LINE
326
327 //==================TestLine========================
328
329 //// 단말기 상태 정보 (0xFB 0x14 0x09) 전용 로그
330 // if (gcd == 0x14 && jcd == 0x09)
331 //{
332 // std::string statusCode;
333 // if (rdata[0] != 0)
334 // {
335 // statusCode.assign(reinterpret_cast<const char *>(rdata), 2);
336 // }
337 // std::wstring wStatus(statusCode.begin(), statusCode.end());
338 // std::wstring desc = L"알수없음";
339 // if (statusCode == "01")
340 // desc = L"신용카드 투입";
341 // else if (statusCode == "02")
342 // desc = L"서버로 접속 시도";
343 // else if (statusCode == "03")
344 // desc = L"FALLBACK 상황 발생";
345 // else if (statusCode == "04")
346 // desc = L"승인 불가능한 카드 인입";
347
348 // wchar_t statusLog[256];
349 // swprintf_s(statusLog, L"ED785Worker - 상태 이벤트 (0x14/0x09): RC=0x%02X STATUS=%s (%s)",
350 // rcd, wStatus.c_str(), desc.c_str());
351 // Logger::info(statusLog);
352 //}
353
354 // wchar_t eventLogBuf[256];
355 // swprintf_s(eventLogBuf, L"ED785Worker - 아무이벤트 수신: CMD=0x%02X GCD=0x%02X JCD=0x%02X RCD=0x%02X",
356 // cmd, gcd, jcd, rcd);
357 // Logger::debug(eventLogBuf);
358
359 //==================TestLineEnd========================
360
361#pragma endregion
362
363 // 디버깅: 폴링 상태 로그 (일부만)
364 static int pollCount = 0;
365 if (++pollCount % 50 == 0) // 10초마다 (50 * 200ms)
366 {
367 wchar_t pollLogBuf[128];
368 swprintf_s(pollLogBuf, L"ED785Worker - KGetEvent 폴링 중 (결과: %d)", eventResult);
369 // Logger::debug(pollLogBuf);
370 }
371
372 if (eventResult != -1)
373 {
374 // 이벤트 수신 성공
375 wchar_t eventLogBuf[256];
376 swprintf_s(eventLogBuf, L"ED785Worker - 이벤트 수신: CMD=0x%02X GCD=0x%02X JCD=0x%02X RCD=0x%02X",
377 cmd, gcd, jcd, rcd);
378 Logger::debug(eventLogBuf);
379
380 // 응답 구성
381 Response resp;
382 resp.cmd = cmd;
383 resp.gcd = gcd;
384 resp.jcd = jcd;
385 resp.rcd = rcd;
386
387 // RDATA 복사 (유효 길이 계산)
388 resp.data.resize(8192);
389 memcpy(resp.data.data(), rdata, 8192);
390 resp.dataLen = strlen(reinterpret_cast<char *>(rdata));
391
392 // HEXDATA 복사 (바이너리이므로 전체 복사, 유효 길이는 별도 처리 필요)
393 resp.hex.resize(8192);
394 memcpy(resp.hex.data(), hexdata, 8192);
395
396 // HEXDATA 유효 길이 계산 (일단 간단히 0이 아닌 마지막 바이트까지)
397 resp.hexLen = 0;
398 for (int i = 8191; i >= 0; --i)
399 {
400 if (hexdata[i] != 0)
401 {
402 resp.hexLen = i + 1;
403 break;
404 }
405 }
406
407 // 콜백 호출
408 if (m_callback)
409 m_callback(resp);
410
411 // 기대 응답 초기화 (매칭 여부 무관하게)
412 {
413 std::scoped_lock lock(m_currentMutex);
414 m_expectGcd = -1;
415 m_expectJcd = -1;
416 }
417 }
418 else
419 {
420 // 이벤트 없음 - 폴링 간격 대기
421 std::this_thread::sleep_for(std::chrono::milliseconds(POLL_INTERVAL_MS));
422 }
423 }
424
425 // 정리
427 Logger::info(L"ED785Worker - 워커 스레드 종료");
428}
static constexpr uint32_t POLL_INTERVAL_MS
Definition ED785Worker.cpp:8
int m_expectJcd
Definition ED785Worker.h:87
int m_expectGcd
Definition ED785Worker.h:86
std::mutex m_currentMutex
Definition ED785Worker.h:85
bool initializeED785(int comPort, int baudRate)
Definition ED785Worker.cpp:145
void shutdownED785()
Definition ED785Worker.cpp:205
Definition ED785Worker.h:22

다음을 참조함 : ED785Worker::Request::cmd, ED785Worker::Response::cmd, ED785Worker::Response::data, ED785Worker::Response::dataLen, ED785Worker::Request::gcd, ED785Worker::Response::gcd, ED785Worker::Response::hex, ED785Worker::Response::hexLen, initializeED785(), ED785Worker::Request::jcd, ED785Worker::Response::jcd, m_baudRate, m_callback, m_comPort, m_currentMutex, m_ed785, m_expectGcd, m_expectJcd, m_queueMutex, m_requestQueue, m_running, ED785Worker::Request::payload, POLL_INTERVAL_MS, ED785Worker::Response::rcd, shutdownED785().

다음에 의해서 참조됨 : start().

이 함수 내부에서 호출하는 함수들에 대한 그래프입니다.:
이 함수를 호출하는 함수들에 대한 그래프입니다.:

멤버 데이터 문서화

◆ m_baudRate

int ED785Worker::m_baudRate
private

다음에 의해서 참조됨 : ED785Worker(), start(), workerThread().

◆ m_callback

ResponseCallback ED785Worker::m_callback
private

다음에 의해서 참조됨 : notifyInitializationFailure(), start(), workerThread().

◆ m_comPort

int ED785Worker::m_comPort
private

다음에 의해서 참조됨 : ED785Worker(), start(), workerThread().

◆ m_currentMutex

std::mutex ED785Worker::m_currentMutex
private

다음에 의해서 참조됨 : workerThread().

◆ m_ed785

std::unique_ptr<CED785> ED785Worker::m_ed785
private

다음에 의해서 참조됨 : initializeED785(), shutdownED785(), workerThread().

◆ m_expectGcd

int ED785Worker::m_expectGcd {-1}
private
86{-1};

다음에 의해서 참조됨 : workerThread().

◆ m_expectJcd

int ED785Worker::m_expectJcd {-1}
private
87{-1};

다음에 의해서 참조됨 : workerThread().

◆ m_hDummyWnd

HWND ED785Worker::m_hDummyWnd {nullptr}
private
90{nullptr};

다음에 의해서 참조됨 : createDummyWindow(), destroyDummyWindow(), initializeED785().

◆ m_queueMutex

std::mutex ED785Worker::m_queueMutex
private

다음에 의해서 참조됨 : enqueue(), workerThread().

◆ m_requestQueue

std::deque<Request> ED785Worker::m_requestQueue
private

다음에 의해서 참조됨 : enqueue(), workerThread().

◆ m_running

std::atomic<bool> ED785Worker::m_running {false}
private
69{false};

다음에 의해서 참조됨 : start(), stop(), workerThread().

◆ m_thread

std::thread ED785Worker::m_thread
private

다음에 의해서 참조됨 : start(), stop().

◆ ResponseCmdInternal

int ED785Worker::ResponseCmdInternal = 0xFFFF
staticconstexpr

◆ ResponseGcdInitializationFailure

int ED785Worker::ResponseGcdInitializationFailure = 0x0001
staticconstexpr

◆ ResponseJcdInitializationFailure

int ED785Worker::ResponseJcdInitializationFailure = 0x0001
staticconstexpr

이 클래스에 대한 문서화 페이지는 다음의 파일들로부터 생성되었습니다.: