You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

613 lines
17 KiB

5 years ago
  1. /*-------------------------------------------------------------------------
  2. | rxtx is a native interface to serial ports in java.
  3. | Copyright 2002-2004 Michal Hobot MichalHobot@netscape.net
  4. | Copyright 1997-2004 by Trent Jarvi taj@parcelfarce.linux.theplanet.co.uk
  5. |
  6. | This library is free software; you can redistribute it and/or
  7. | modify it under the terms of the GNU Library General Public
  8. | License as published by the Free Software Foundation; either
  9. | version 2 of the License, or (at your option) any later version.
  10. |
  11. | This library is distributed in the hope that it will be useful,
  12. | but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  14. | Library General Public License for more details.
  15. |
  16. | You should have received a copy of the GNU Library General Public
  17. | License along with this library; if not, write to the Free
  18. | Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  19. --------------------------------------------------------------------------*/
  20. #include "StdAfx.h"
  21. #include <stdio.h>
  22. #include <stdlib.h>
  23. #include "rxtxHelpers.h"
  24. /*----------------------------------------------------------
  25. get_java_int_var
  26. accept: env (keyhole to java)
  27. jobj (java RXTXPort object)
  28. return: the jint field from the java object, casted to long
  29. exceptions: none
  30. comments:
  31. ----------------------------------------------------------*/
  32. long get_java_int_var( JNIEnv *env, jobject jobj, char *id)
  33. {
  34. long result = 0;
  35. jclass jclazz = env->GetObjectClass(jobj);
  36. jfieldID jfd = env->GetFieldID(jclazz, id, "I");
  37. if( !jfd ) {
  38. IF_DEBUG
  39. (
  40. env->ExceptionDescribe();
  41. )
  42. env->ExceptionClear();
  43. env->DeleteLocalRef(jclazz);
  44. return result;
  45. }
  46. result = (long)( env->GetIntField(jobj, jfd) );
  47. env->DeleteLocalRef(jclazz);
  48. return result;
  49. }
  50. /*----------------------------------------------------------
  51. get_java_boolean_var
  52. accept: env (keyhole to java)
  53. jobj (java RXTXPort object)
  54. return: the jboolean field from the java object, converted to bool
  55. exceptions: none
  56. comments:
  57. ----------------------------------------------------------*/
  58. bool get_java_boolean_var( JNIEnv *env, jobject jobj, char *id)
  59. {
  60. bool result = FALSE;
  61. jclass jclazz = env->GetObjectClass(jobj);
  62. jfieldID jfd = env->GetFieldID(jclazz, id, "Z");
  63. if( !jfd ) {
  64. IF_DEBUG
  65. (
  66. env->ExceptionDescribe();
  67. )
  68. env->ExceptionClear();
  69. env->DeleteLocalRef(jclazz);
  70. return result;
  71. }
  72. result = (env->GetBooleanField(jobj, jfd)) != JNI_FALSE;
  73. env->DeleteLocalRef(jclazz);
  74. return result;
  75. }
  76. /*----------------------------------------------------------
  77. get_java_boolean_var2
  78. accept: env (keyhole to java)
  79. jobj (java RXTXPort object)
  80. jclazz (class of jobj)
  81. return: the jboolean field from the java object, converted to bool
  82. exceptions: none
  83. comments: can be faster for fetching many variables one by one
  84. ----------------------------------------------------------*/
  85. bool get_java_boolean_var2(JNIEnv *env, jobject jobj, jclass jclazz, char *id)
  86. {
  87. bool result = FALSE;
  88. jfieldID jfd = env->GetFieldID(jclazz, id, "Z");
  89. if( !jfd ) {
  90. IF_DEBUG
  91. (
  92. env->ExceptionDescribe();
  93. )
  94. env->ExceptionClear();
  95. env->DeleteLocalRef(jclazz);
  96. return result;
  97. }
  98. result = (env->GetBooleanField(jobj, jfd)) != JNI_FALSE;
  99. return result;
  100. }
  101. /*----------------------------------------------------------
  102. throw_java_exception
  103. accept: env (keyhole to java)
  104. *exc (exception class name)
  105. *foo (function name)
  106. *msg (error message)
  107. perform: Throw a new java exception
  108. return: none
  109. exceptions: haha!
  110. comments:
  111. ----------------------------------------------------------*/
  112. void throw_java_exception(JNIEnv *env, const char *exc, const char *foo, const char *msg)
  113. {
  114. char buf[250];
  115. jclass clazz = env->FindClass(exc);
  116. if( !clazz ) {
  117. IF_DEBUG
  118. (
  119. env->ExceptionDescribe();
  120. )
  121. env->ExceptionClear();
  122. return;
  123. }
  124. _snprintf(buf, 60, "%s: %s in %s", exc, msg, foo);
  125. env->ThrowNew(clazz, buf);
  126. env->DeleteLocalRef(clazz);
  127. }
  128. // Unicode version:
  129. void throw_java_exceptionW(JNIEnv *env, const char *exc, const wchar_t *foo, const wchar_t *msg)
  130. {
  131. wchar_t buf[500];
  132. char *lpcBuf;
  133. int msgLen;
  134. jclass clazz = env->FindClass(exc);
  135. if( !clazz ) {
  136. env->ExceptionDescribe();
  137. env->ExceptionClear();
  138. return;
  139. }
  140. msgLen = swprintf(buf, L"%S: %s in %s", exc, msg, foo);
  141. IF_DEBUG
  142. (
  143. printj(env, L"!!!!! Throwing %s\n", buf);
  144. //MessageBox(NULL, buf, L"throw_java_exceptionW"), MB_OK | MB_ICONEXCLAMATION | MB_SETFOREGROUND);
  145. )
  146. lpcBuf = (char *)malloc((msgLen+1)*sizeof(wchar_t)); // Will be ok - mbs not longer than wcs
  147. lpcBuf[msgLen] = '\0';
  148. wcstombs(lpcBuf, buf, msgLen);
  149. env->ThrowNew(clazz, lpcBuf);
  150. free(lpcBuf);
  151. env->DeleteLocalRef(clazz);
  152. }
  153. /*----------------------------------------------------------
  154. get_fd
  155. accept: env (keyhole to java)
  156. jobj (java RXTXPort object)
  157. return: "fd" field from the java object, as HANDLE
  158. exceptions: none
  159. comments:
  160. ----------------------------------------------------------*/
  161. HANDLE get_fd(JNIEnv *env, jobject jobj)
  162. {
  163. HANDLE fd = (HANDLE)get_java_int_var(env, jobj, "fd");
  164. return fd!=0?fd:INVALID_HANDLE_VALUE;
  165. }
  166. /*----------------------------------------------------------
  167. get_eis
  168. accept: env (keyhole to java)
  169. jobj (java RXTXPort object)
  170. return: "eis" field from the java object, as (EventInfoStruct *)
  171. exceptions: none
  172. comments:
  173. ----------------------------------------------------------*/
  174. EventInfoStruct *get_eis(JNIEnv *env, jobject jobj)
  175. {
  176. return (EventInfoStruct *)get_java_int_var(env, jobj, "eis");
  177. }
  178. /*----------------------------------------------------------
  179. printj
  180. accept: like vwprintf()
  181. return: number of jchars written or -1
  182. exceptions: none
  183. comments: prints data using System.out.print()
  184. ----------------------------------------------------------*/
  185. int printj(JNIEnv *env, wchar_t *fmt, ...)
  186. {
  187. wchar_t buf[1024];
  188. int retval;
  189. jstring jsBuf;
  190. jclass clsSystem, clsOut;
  191. jfieldID jfid;
  192. jobject objOut;
  193. jmethodID midPrint;
  194. va_list ap;
  195. va_start(ap, fmt);
  196. retval = _vsnwprintf(buf, 1024, fmt, ap);
  197. va_end(ap);
  198. buf[1023] = '\0';
  199. if((clsSystem = env->FindClass("java/lang/System")) == NULL)
  200. {
  201. IF_DEBUG
  202. (
  203. env->ExceptionDescribe();
  204. )
  205. env->ExceptionClear();
  206. return -1;
  207. }
  208. if((jfid = env->GetStaticFieldID(clsSystem, "out", "Ljava/io/PrintStream;")) == NULL)
  209. {
  210. IF_DEBUG
  211. (
  212. env->ExceptionDescribe();
  213. )
  214. env->ExceptionClear();
  215. env->DeleteLocalRef(clsSystem);
  216. return -1;
  217. }
  218. objOut = env->GetStaticObjectField(clsSystem, jfid);
  219. clsOut = env->GetObjectClass(objOut);
  220. if((midPrint = env->GetMethodID(clsOut, "print", "(Ljava/lang/String;)V")) == NULL)
  221. {
  222. IF_DEBUG
  223. (
  224. env->ExceptionDescribe();
  225. )
  226. env->ExceptionClear();
  227. env->DeleteLocalRef(clsOut);
  228. env->DeleteLocalRef(clsSystem);
  229. return -1;
  230. }
  231. jsBuf = env->NewString(buf, wcslen(buf));
  232. env->CallVoidMethod(objOut, midPrint, jsBuf);
  233. env->DeleteLocalRef(jsBuf);
  234. env->DeleteLocalRef(clsOut);
  235. env->DeleteLocalRef(clsSystem);
  236. return retval;
  237. }
  238. /*----------------------------------------------------------
  239. CommEventThread
  240. accept: communication structure ptr
  241. return: 0 - normal finish, other - error
  242. exceptions: none
  243. comments: runs as separate thread
  244. ----------------------------------------------------------*/
  245. DWORD __stdcall CommEventThread(LPVOID lpEventInfo)
  246. {
  247. DWORD dwErr;
  248. EventInfoStruct *EventInfo = (EventInfoStruct *)lpEventInfo;
  249. HANDLE hPort = EventInfo->fd;
  250. // Specify a set of events to be monitored for the port.
  251. if(!SetCommMask(hPort, EventInfo->ef))
  252. {
  253. dwErr = GetLastError();
  254. IF_DEBUG
  255. (
  256. LPCWSTR lpMsgBuf;
  257. CreateErrorMsg(dwErr, lpMsgBuf);
  258. MessageBoxW(NULL, lpMsgBuf, L"!!! CommEventThread - SetCommMask() error", MB_OK | MB_ICONEXCLAMATION | MB_SETFOREGROUND);
  259. ReleaseErrorMsg(lpMsgBuf);
  260. )
  261. return dwErr;
  262. }
  263. // Thread is ready to work
  264. EventInfo->eventThreadReady = true;
  265. do
  266. {
  267. // Wait for an event to occur for the port.
  268. if(!WaitCommEvent(hPort, &(EventInfo->event), NULL))
  269. {
  270. dwErr = GetLastError();
  271. if(dwErr == ERROR_INVALID_PARAMETER)
  272. { // Mask is empty - let's wait for a moment and continue
  273. MessageBeep(MB_ICONQUESTION);
  274. Sleep(200);
  275. continue;
  276. }
  277. if(dwErr == ERROR_INVALID_HANDLE)
  278. { // Port was closed
  279. //MessageBox(NULL, L"--- CommEventThread - Port closed", L"ERROR_INVALID_HANDLE", MB_OK | MB_ICONEXCLAMATION | MB_SETFOREGROUND);
  280. free(EventInfo);
  281. return 0;
  282. }
  283. IF_DEBUG
  284. (
  285. LPCWSTR lpMsgBuf;
  286. WCHAR MsgBuf2[1000];
  287. CreateErrorMsg(dwErr, lpMsgBuf);
  288. wsprintfW(MsgBuf2, L"%ld %s, CommMask==%ld", dwErr, lpMsgBuf, EventInfo->ef);
  289. MessageBoxW(NULL, MsgBuf2, L"!!! CommEventThread - WaitCommEvent() error", MB_OK | MB_ICONEXCLAMATION | MB_SETFOREGROUND);
  290. ReleaseErrorMsg(lpMsgBuf);
  291. )
  292. return dwErr;
  293. }
  294. IF_DEBUG
  295. (
  296. MessageBeep(MB_ICONEXCLAMATION);
  297. //MessageBoxW(NULL, L"--- RXTXPort.CommEventThread() - CommEvent", L"CommEventThread", MB_OK | MB_ICONEXCLAMATION | MB_SETFOREGROUND);
  298. )
  299. // Re-specify the set of events to be monitored for the port.
  300. if(!SetCommMask(hPort, EventInfo->ef))
  301. {
  302. dwErr = GetLastError();
  303. IF_DEBUG
  304. (
  305. LPCWSTR lpMsgBuf;
  306. CreateErrorMsg(dwErr, lpMsgBuf);
  307. MessageBoxW(NULL, lpMsgBuf, L"!!! CommEventThread - SetCommMask() error", MB_OK | MB_ICONEXCLAMATION | MB_SETFOREGROUND);
  308. ReleaseErrorMsg(lpMsgBuf);
  309. )
  310. return dwErr;
  311. }
  312. if(!SetEvent(EventInfo->eventHandle))
  313. {
  314. dwErr = GetLastError();
  315. if(dwErr == ERROR_INVALID_HANDLE) // Event was closed
  316. {
  317. //MessageBoxW(NULL, L"--- CommEventThread - Event closed", L"ERROR_INVALID_HANDLE", MB_OK | MB_ICONEXCLAMATION | MB_SETFOREGROUND);
  318. free(EventInfo);
  319. return 0;
  320. }
  321. IF_DEBUG
  322. (
  323. LPCWSTR lpMsgBuf;
  324. CreateErrorMsg(dwErr, lpMsgBuf);
  325. MessageBoxW(NULL, lpMsgBuf, L"!!! CommEventThread - SetEvent() error", MB_OK | MB_ICONEXCLAMATION | MB_SETFOREGROUND);
  326. ReleaseErrorMsg(lpMsgBuf);
  327. )
  328. return dwErr;
  329. }
  330. // Wait for receiving and clearing event
  331. while(EventInfo->event != 0)
  332. Sleep(0);
  333. } while(TRUE);
  334. }
  335. /*----------------------------------------------------------
  336. setEventFlags
  337. accept: EventFlag table
  338. return: none
  339. exceptions: none
  340. comments: sets EventFlag table according to Java
  341. MonitorThread fields
  342. ----------------------------------------------------------*/
  343. /*void setEventFlags(JNIEnv *env, jobject jobjPort, bool ef[])
  344. {
  345. jfieldID jfid;
  346. jclass cls;
  347. jobject jobj;
  348. jclass clsPort = env->GetObjectClass(jobjPort);
  349. if((jfid = env->GetFieldID(clsPort, "monThread", "Lgnu/io/RXTXPort$MonitorThread;")) == NULL)
  350. {
  351. IF_DEBUG
  352. (
  353. env->ExceptionDescribe();
  354. )
  355. env->ExceptionClear();
  356. env->DeleteLocalRef(clsPort);
  357. return;
  358. }
  359. jobj = env->GetObjectField(jobjPort, jfid);
  360. cls = env->GetObjectClass(jobj);
  361. ef[SPE_DATA_AVAILABLE] = get_java_boolean_var2(env, jobj, cls, "Data");
  362. ef[SPE_OUTPUT_BUFFER_EMPTY] = get_java_boolean_var2(env, jobj, cls, "Output");
  363. ef[SPE_CTS] = get_java_boolean_var2(env, jobj, cls, "CTS");
  364. ef[SPE_DSR] = get_java_boolean_var2(env, jobj, cls, "DSR");
  365. ef[SPE_RI] = get_java_boolean_var2(env, jobj, cls, "RI");
  366. ef[SPE_CD] = get_java_boolean_var2(env, jobj, cls, "CD");
  367. ef[SPE_OE] = get_java_boolean_var2(env, jobj, cls, "OE");
  368. ef[SPE_PE] = get_java_boolean_var2(env, jobj, cls, "PE");
  369. ef[SPE_FE] = get_java_boolean_var2(env, jobj, cls, "FE");
  370. ef[SPE_BI] = get_java_boolean_var2(env, jobj, cls, "BI");
  371. env->DeleteLocalRef(clsPort);
  372. env->DeleteLocalRef(cls);
  373. env->DeleteLocalRef(jobj);
  374. }
  375. */
  376. /*----------------------------------------------------------
  377. InitialiseEventInfoStruct
  378. accept: Port handle
  379. return: 0 - OK, other - error number
  380. exceptions: none
  381. comments: Structure for communication with thread
  382. ----------------------------------------------------------*/
  383. int InitialiseEventInfoStruct(HANDLE hPort, EventInfoStruct **EventInfoPtr)
  384. {
  385. DWORD dwErr;
  386. WCHAR wsEventName[MAX_PATH];
  387. (*EventInfoPtr) = (EventInfoStruct *)malloc(sizeof(EventInfoStruct));
  388. if(*EventInfoPtr == NULL)
  389. return ERROR_NOT_ENOUGH_MEMORY;
  390. memset(*EventInfoPtr, 0, sizeof(EventInfoStruct));
  391. (*EventInfoPtr)->fd = hPort;
  392. wsprintfW(wsEventName, L"rxtxPort.SerEvt%lx", hPort);
  393. (*EventInfoPtr)->eventHandle = CreateEventW(NULL, FALSE, FALSE, wsEventName);
  394. dwErr = GetLastError();
  395. if((*EventInfoPtr)->eventHandle == NULL || dwErr == ERROR_ALREADY_EXISTS)
  396. {
  397. IF_DEBUG
  398. (
  399. LPCWSTR lpMsgBuf;
  400. CreateErrorMsg(dwErr, lpMsgBuf);
  401. MessageBoxW(NULL, lpMsgBuf, L"!!! InitialiseEventInfoStruct - CreateEvent() error", MB_OK | MB_ICONEXCLAMATION | MB_SETFOREGROUND);
  402. ReleaseErrorMsg(lpMsgBuf);
  403. )
  404. free(*EventInfoPtr);
  405. return dwErr;
  406. }
  407. // Set initial event flags: It should be not empty, but unused here and relatively rare event
  408. (*EventInfoPtr)->ef = EV_POWER; //In WinNT you can use EV_EVENT2 instead
  409. return 0;
  410. }
  411. /*----------------------------------------------------------
  412. SendEvents
  413. accept:
  414. return:
  415. exceptions: none
  416. comments: Sends events needed
  417. ----------------------------------------------------------*/
  418. int SendEvents(JNIEnv *env, jobject jobj, DWORD dwEvent, EventInfoStruct *EventInfo, jmethodID jmSendEvent)
  419. {
  420. DWORD dwErrors;
  421. COMSTAT Stat;
  422. IF_DEBUG
  423. (
  424. printj(env, L"--- SendEvents(): event %#lx\n", dwEvent);
  425. )
  426. if(!ClearCommError(EventInfo->fd, &dwErrors, &Stat))
  427. {
  428. IF_DEBUG
  429. (
  430. LPCWSTR lpMsgBuf;
  431. CreateErrorMsg(GetLastError(), lpMsgBuf);
  432. printj(env, L"!!! SendEvents - ClearCommError() error: %s\n", lpMsgBuf);
  433. ReleaseErrorMsg(lpMsgBuf);
  434. )
  435. return -1;
  436. }
  437. // Ignore not subscribed events
  438. dwEvent &= EventInfo->ef;
  439. if(dwEvent & EV_RXCHAR)
  440. {
  441. IF_DEBUG
  442. (
  443. printj(env, L"--- SendEvents(): EV_RXCHAR\n");
  444. )
  445. if(env->CallBooleanMethod(jobj, jmSendEvent, SPE_DATA_AVAILABLE, JNI_TRUE) == JNI_TRUE)
  446. return SPE_DATA_AVAILABLE;
  447. }
  448. if(dwEvent & EV_TXEMPTY)
  449. {
  450. IF_DEBUG
  451. (
  452. printj(env, L"--- SendEvents(): EV_TXEMPTY\n");
  453. )
  454. if(env->CallBooleanMethod(jobj, jmSendEvent, SPE_OUTPUT_BUFFER_EMPTY, JNI_TRUE) == JNI_TRUE)
  455. return SPE_OUTPUT_BUFFER_EMPTY;
  456. }
  457. if(dwEvent & EV_CTS)
  458. {
  459. IF_DEBUG
  460. (
  461. printj(env, L"--- SendEvents(): EV_CTS\n");
  462. )
  463. if(env->CallBooleanMethod(jobj, jmSendEvent, SPE_CTS, Stat.fCtsHold?JNI_TRUE:JNI_TRUE) == JNI_TRUE)
  464. return SPE_CTS;
  465. }
  466. if(dwEvent & EV_DSR)
  467. {
  468. IF_DEBUG
  469. (
  470. printj(env, L"--- SendEvents(): EV_DSR\n");
  471. )
  472. if(env->CallBooleanMethod(jobj, jmSendEvent, SPE_DSR, Stat.fDsrHold?JNI_TRUE:JNI_TRUE) == JNI_TRUE)
  473. return SPE_DSR;
  474. }
  475. if(dwEvent & EV_RING)
  476. {
  477. IF_DEBUG
  478. (
  479. printj(env, L"--- SendEvents(): EV_RING\n");
  480. )
  481. if(env->CallBooleanMethod(jobj, jmSendEvent, SPE_RI, JNI_TRUE) == JNI_TRUE)
  482. return SPE_RI;
  483. }
  484. if(dwEvent & EV_RLSD)
  485. {
  486. IF_DEBUG
  487. (
  488. printj(env, L"--- SendEvents(): EV_RLSD\n");
  489. )
  490. if(env->CallBooleanMethod(jobj, jmSendEvent, SPE_CD, Stat.fRlsdHold?JNI_TRUE:JNI_TRUE) == JNI_TRUE)
  491. return SPE_CD;
  492. }
  493. if(dwEvent & EV_ERR)
  494. {
  495. if(dwErrors & CE_OVERRUN)
  496. {
  497. IF_DEBUG
  498. (
  499. printj(env, L"--- SendEvents(): CE_OVERRUN\n");
  500. )
  501. if(env->CallBooleanMethod(jobj, jmSendEvent, SPE_OE, JNI_TRUE) == JNI_TRUE)
  502. return SPE_OE;
  503. }
  504. if(dwErrors & CE_RXPARITY)
  505. {
  506. IF_DEBUG
  507. (
  508. printj(env, L"--- SendEvents(): CE_RXPARITY\n");
  509. )
  510. if(env->CallBooleanMethod(jobj, jmSendEvent, SPE_PE, JNI_TRUE) == JNI_TRUE)
  511. return SPE_PE;
  512. }
  513. if(dwErrors & CE_FRAME)
  514. {
  515. IF_DEBUG
  516. (
  517. printj(env, L"--- SendEvents(): CE_FRAME\n");
  518. )
  519. if(env->CallBooleanMethod(jobj, jmSendEvent, SPE_FE, JNI_TRUE) == JNI_TRUE)
  520. return SPE_FE;
  521. }
  522. }
  523. if(dwEvent & EV_BREAK)
  524. {
  525. IF_DEBUG
  526. (
  527. printj(env, L"--- SendEvents(): EV_BREAK\n");
  528. )
  529. if(env->CallBooleanMethod(jobj, jmSendEvent, SPE_BI, JNI_TRUE) == JNI_TRUE)
  530. return SPE_BI;
  531. }
  532. return 0;
  533. }