2
2
* SerialPort_Windows.c
3
3
*
4
4
* Created on: Feb 25, 2012
5
- * Last Updated on: Apr 10 , 2024
5
+ * Last Updated on: Apr 11 , 2024
6
6
* Author: Will Hedgecock
7
7
*
8
8
* Copyright (C) 2012-2024 Fazecast, Inc.
@@ -55,6 +55,7 @@ jfieldID serialNumberField;
55
55
jfieldID manufacturerField ;
56
56
jfieldID eventListenerRunningField ;
57
57
jfieldID disableConfigField ;
58
+ jfieldID allowOpenForEnumerationField ;
58
59
jfieldID isDtrEnabledField ;
59
60
jfieldID isRtsEnabledField ;
60
61
jfieldID autoFlushIOBuffersField ;
@@ -78,6 +79,8 @@ jfieldID writeTimeoutField;
78
79
jfieldID eventFlagsField ;
79
80
80
81
// Runtime-loadable DLL functions
82
+ typedef int (__stdcall * FT_CloseFunction )(FT_HANDLE );
83
+ typedef int (__stdcall * FT_OpenFunction )(int , FT_HANDLE * );
81
84
typedef int (__stdcall * FT_CreateDeviceInfoListFunction )(LPDWORD );
82
85
typedef int (__stdcall * FT_GetDeviceInfoListFunction )(FT_DEVICE_LIST_INFO_NODE * , LPDWORD );
83
86
typedef int (__stdcall * FT_EEPROM_ReadFunction )(FT_HANDLE , void * , DWORD , char * , char * , char * , char * );
@@ -111,7 +114,7 @@ static inline jboolean checkJniError(JNIEnv *env, int lineNumber)
111
114
}
112
115
113
116
// Generalized port enumeration function
114
- static void enumeratePorts (void )
117
+ static void enumeratePorts (JNIEnv * env , jclass serialComm )
115
118
{
116
119
// Reset the enumerated flag on all non-open serial ports
117
120
for (int i = 0 ; i < serialPorts .length ; ++ i )
@@ -398,9 +401,12 @@ static void enumeratePorts(void)
398
401
HINSTANCE ftdiLibInstance = LoadLibrary (TEXT ("ftd2xx.dll" ));
399
402
if (ftdiLibInstance != NULL )
400
403
{
404
+ FT_OpenFunction FT_Open = (FT_OpenFunction )GetProcAddress (ftdiLibInstance , "FT_Open" );
405
+ FT_CloseFunction FT_Close = (FT_CloseFunction )GetProcAddress (ftdiLibInstance , "FT_Close" );
401
406
FT_CreateDeviceInfoListFunction FT_CreateDeviceInfoList = (FT_CreateDeviceInfoListFunction )GetProcAddress (ftdiLibInstance , "FT_CreateDeviceInfoList" );
402
407
FT_GetDeviceInfoListFunction FT_GetDeviceInfoList = (FT_GetDeviceInfoListFunction )GetProcAddress (ftdiLibInstance , "FT_GetDeviceInfoList" );
403
408
FT_EEPROM_ReadFunction FT_EEPROM_Read = (FT_EEPROM_ReadFunction )GetProcAddress (ftdiLibInstance , "FT_EEPROM_Read" );
409
+ unsigned char allowOpenForEnumeration = (* env )-> GetStaticBooleanField (env , serialComm , allowOpenForEnumerationField );
404
410
if (FT_CreateDeviceInfoList && FT_GetDeviceInfoList && FT_EEPROM_Read )
405
411
{
406
412
DWORD numDevs ;
@@ -433,25 +439,120 @@ static void enumeratePorts(void)
433
439
for (int j = 0 ; j < serialPorts .length ; ++ j )
434
440
if ((wcscmp (serialPorts .ports [j ]-> portPath + 4 , comPort ) == 0 ) && strlen (devInfo [i ].Description ))
435
441
{
436
- // Update the port description
437
- serialPorts .ports [j ]-> enumerated = 1 ;
438
- size_t descLength = 8 + strlen (devInfo [i ].Description );
439
- wchar_t * newMemory = (wchar_t * )realloc (serialPorts .ports [j ]-> portDescription , descLength * sizeof (wchar_t ));
440
- if (newMemory )
442
+ // Check whether we are allowed to open the port to complete enumeration
443
+ unsigned char successfullyEnumerated = 0 ;
444
+ if (allowOpenForEnumeration )
441
445
{
442
- serialPorts .ports [j ]-> portDescription = newMemory ;
443
- MultiByteToWideChar (CP_ACP , MB_PRECOMPOSED , devInfo [i ].Description , -1 , serialPorts .ports [j ]-> portDescription , descLength );
446
+ // Open the port and read its configuration from EEPROM
447
+ FT_HANDLE ftHandle ;
448
+ FT_EEPROM_HEADER ftEepromHeader = { .deviceType = devInfo [i ].Type };
449
+ char manufacturer [64 ], manufacturerId [64 ], description [64 ], serialNumber [64 ];
450
+ if (FT_Open (0 , & ftHandle ) == FT_OK )
451
+ {
452
+ switch (devInfo [i ].Type )
453
+ {
454
+ case FT_DEVICE_2232C :
455
+ {
456
+ FT_EEPROM_2232 ftDeviceHeader = { .common = ftEepromHeader };
457
+ successfullyEnumerated = (FT_EEPROM_Read (ftHandle , & ftDeviceHeader , sizeof (ftDeviceHeader ), manufacturer , manufacturerId , description , serialNumber ) == FT_OK );
458
+ break ;
459
+ }
460
+ case FT_DEVICE_232R :
461
+ {
462
+ FT_EEPROM_232R ftDeviceHeader = { .common = ftEepromHeader };
463
+ successfullyEnumerated = (FT_EEPROM_Read (ftHandle , & ftDeviceHeader , sizeof (ftDeviceHeader ), manufacturer , manufacturerId , description , serialNumber ) == FT_OK );
464
+ break ;
465
+ }
466
+ case FT_DEVICE_2232H :
467
+ {
468
+ FT_EEPROM_2232H ftDeviceHeader = { .common = ftEepromHeader };
469
+ successfullyEnumerated = (FT_EEPROM_Read (ftHandle , & ftDeviceHeader , sizeof (ftDeviceHeader ), manufacturer , manufacturerId , description , serialNumber ) == FT_OK );
470
+ break ;
471
+ }
472
+ case FT_DEVICE_4232H :
473
+ {
474
+ FT_EEPROM_4232H ftDeviceHeader = { .common = ftEepromHeader };
475
+ successfullyEnumerated = (FT_EEPROM_Read (ftHandle , & ftDeviceHeader , sizeof (ftDeviceHeader ), manufacturer , manufacturerId , description , serialNumber ) == FT_OK );
476
+ break ;
477
+ }
478
+ case FT_DEVICE_232H :
479
+ {
480
+ FT_EEPROM_232H ftDeviceHeader = { .common = ftEepromHeader };
481
+ successfullyEnumerated = (FT_EEPROM_Read (ftHandle , & ftDeviceHeader , sizeof (ftDeviceHeader ), manufacturer , manufacturerId , description , serialNumber ) == FT_OK );
482
+ break ;
483
+ }
484
+ case FT_DEVICE_X_SERIES :
485
+ {
486
+ FT_EEPROM_X_SERIES ftDeviceHeader = { .common = ftEepromHeader };
487
+ successfullyEnumerated = (FT_EEPROM_Read (ftHandle , & ftDeviceHeader , sizeof (ftDeviceHeader ), manufacturer , manufacturerId , description , serialNumber ) == FT_OK );
488
+ break ;
489
+ }
490
+ default :
491
+ {
492
+ FT_EEPROM_232B ftDeviceHeader = { .common = ftEepromHeader };
493
+ successfullyEnumerated = (FT_EEPROM_Read (ftHandle , & ftDeviceHeader , sizeof (ftDeviceHeader ), manufacturer , manufacturerId , description , serialNumber ) == FT_OK );
494
+ break ;
495
+ }
496
+ }
497
+ FT_Close (ftHandle );
498
+ }
499
+
500
+ // Update port details if enumeration was successful
501
+ if (successfullyEnumerated )
502
+ {
503
+ // Update the port description
504
+ serialPorts .ports [j ]-> enumerated = 1 ;
505
+ size_t descLength = 8 + strlen (description );
506
+ wchar_t * newMemory = (wchar_t * )realloc (serialPorts .ports [j ]-> portDescription , descLength * sizeof (wchar_t ));
507
+ if (newMemory )
508
+ {
509
+ serialPorts .ports [j ]-> portDescription = newMemory ;
510
+ MultiByteToWideChar (CP_ACP , MB_PRECOMPOSED , description , -1 , serialPorts .ports [j ]-> portDescription , descLength );
511
+ }
512
+
513
+ // Update the port serial number
514
+ size_t serialNumLength = 1 + strlen (serialNumber );
515
+ newMemory = (wchar_t * )realloc (serialPorts .ports [j ]-> serialNumber , serialNumLength * sizeof (wchar_t ));
516
+ if (newMemory )
517
+ {
518
+ serialPorts .ports [j ]-> serialNumber = newMemory ;
519
+ MultiByteToWideChar (CP_ACP , MB_PRECOMPOSED , serialNumber , -1 , serialPorts .ports [j ]-> serialNumber , serialNumLength );
520
+ }
521
+
522
+ // Update the port manufacturer
523
+ size_t manufacturerLength = 1 + strlen (manufacturer );
524
+ newMemory = (wchar_t * )realloc (serialPorts .ports [j ]-> manufacturer , manufacturerLength * sizeof (wchar_t ));
525
+ if (newMemory )
526
+ {
527
+ serialPorts .ports [j ]-> manufacturer = newMemory ;
528
+ MultiByteToWideChar (CP_ACP , MB_PRECOMPOSED , manufacturer , -1 , serialPorts .ports [j ]-> manufacturer , manufacturerLength );
529
+ }
530
+ }
444
531
}
445
532
446
- // Update the port serial number
447
- size_t serialNumLength = 1 + strlen (devInfo [i ].SerialNumber );
448
- newMemory = (wchar_t * )realloc (serialPorts .ports [j ]-> serialNumber , serialNumLength * sizeof (wchar_t ));
449
- if (newMemory )
533
+ // Take what we can get if unable to enumerate by opening the port
534
+ if (!successfullyEnumerated )
450
535
{
451
- serialPorts .ports [j ]-> serialNumber = newMemory ;
452
- MultiByteToWideChar (CP_ACP , MB_PRECOMPOSED , devInfo [i ].SerialNumber , -1 , serialPorts .ports [j ]-> serialNumber , serialNumLength );
536
+ // Update the port description
537
+ serialPorts .ports [j ]-> enumerated = 1 ;
538
+ size_t descLength = 8 + strlen (devInfo [i ].Description );
539
+ wchar_t * newMemory = (wchar_t * )realloc (serialPorts .ports [j ]-> portDescription , descLength * sizeof (wchar_t ));
540
+ if (newMemory )
541
+ {
542
+ serialPorts .ports [j ]-> portDescription = newMemory ;
543
+ MultiByteToWideChar (CP_ACP , MB_PRECOMPOSED , devInfo [i ].Description , -1 , serialPorts .ports [j ]-> portDescription , descLength );
544
+ }
545
+
546
+ // Update the port serial number
547
+ size_t serialNumLength = 1 + strlen (devInfo [i ].SerialNumber );
548
+ newMemory = (wchar_t * )realloc (serialPorts .ports [j ]-> serialNumber , serialNumLength * sizeof (wchar_t ));
549
+ if (newMemory )
550
+ {
551
+ serialPorts .ports [j ]-> serialNumber = newMemory ;
552
+ MultiByteToWideChar (CP_ACP , MB_PRECOMPOSED , devInfo [i ].SerialNumber , -1 , serialPorts .ports [j ]-> serialNumber , serialNumLength );
553
+ }
554
+ memcpy (serialPorts .ports [j ]-> ftdiSerialNumber , devInfo [i ].SerialNumber , sizeof (serialPorts .ports [j ]-> ftdiSerialNumber ));
453
555
}
454
- memcpy (serialPorts .ports [j ]-> ftdiSerialNumber , devInfo [i ].SerialNumber , sizeof (serialPorts .ports [j ]-> ftdiSerialNumber ));
455
556
}
456
557
}
457
558
if (comPort )
@@ -557,6 +658,8 @@ JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *jvm, void *reserved)
557
658
if (checkJniError (env , __LINE__ - 1 )) return JNI_ERR ;
558
659
disableConfigField = (* env )-> GetFieldID (env , serialCommClass , "disableConfig" , "Z" );
559
660
if (checkJniError (env , __LINE__ - 1 )) return JNI_ERR ;
661
+ allowOpenForEnumerationField = (* env )-> GetStaticFieldID (env , serialCommClass , "allowOpenForEnumeration" , "Z" );
662
+ if (checkJniError (env , __LINE__ - 1 )) return JNI_ERR ;
560
663
isDtrEnabledField = (* env )-> GetFieldID (env , serialCommClass , "isDtrEnabled" , "Z" );
561
664
if (checkJniError (env , __LINE__ - 1 )) return JNI_ERR ;
562
665
isRtsEnabledField = (* env )-> GetFieldID (env , serialCommClass , "isRtsEnabled" , "Z" );
@@ -651,7 +754,7 @@ JNIEXPORT jobjectArray JNICALL Java_com_fazecast_jSerialComm_SerialPort_getCommP
651
754
EnterCriticalSection (& criticalSection );
652
755
653
756
// Enumerate all ports on the current system
654
- enumeratePorts ();
757
+ enumeratePorts (env , serialComm );
655
758
656
759
// Get relevant SerialComm methods and fill in com port array
657
760
jobjectArray arrayObject = (* env )-> NewObjectArray (env , serialPorts .length , serialComm , 0 );
@@ -698,7 +801,10 @@ JNIEXPORT void JNICALL Java_com_fazecast_jSerialComm_SerialPort_retrievePortDeta
698
801
char continueRetrieval = 1 ;
699
802
EnterCriticalSection (& criticalSection );
700
803
if (!portsEnumerated )
701
- enumeratePorts ();
804
+ {
805
+ jclass serialComm = (* env )-> GetObjectClass (env , obj );
806
+ enumeratePorts (env , serialComm );
807
+ }
702
808
serialPort * port = fetchPort (& serialPorts , portName );
703
809
if (!port )
704
810
continueRetrieval = 0 ;
0 commit comments