The current issue that I'm getting is that the OnNmeaListener is not returning the correct data from the NMEA using the GpsStatus.Listener therefore I tried the GNSS Status for the peace of mind, it ended up returning gibberish data , so I had to revert back to GpsStatus Listener. I also prior to using OnNmeaListener tried GpsStatus.NmeaListner and when used tried to add it to the GpsStatus Listener it would show up as an error and suggested that i typecast it to OnNmeaListener, when this is done and the app is built and all and then executed from the app, it would crash and then not work at all, and this is why i shifted to OnNmeaListener in the first place. Now to its credit the OnNmeaListener works just fine and doesn't crash at all, but the data it gives out is not at all accurate, I thought maybe this might have to be some sort of fault/error on the device side, I then proceeded to test it on two devices with different API levels of 25 and 28, On the the 25 Level device it just did not give half of the data whereas on the 28 level device the data is full but not accurate and correct.
This is the method that I'm currently using:
OnNmeaMessageListener nmeaMessageListener = new OnNmeaMessageListener () {
#Override
public void onNmeaMessage(String nmea , long timestamp) {
if (trackStarted == true && trackPaused == false) {
if (nmea.startsWith ( "$GPGGA" ) || nmea.startsWith ( "$GPRMC" )) {
//Log.d("TrackManagerService","NMEA:" + nmea);
try {
// out.write(nmea.getBytes());
if (continuesMode) {
dataOut.write ( nmea.getBytes () );
bufferedNMEALines++;
if (bufferedNMEALines >= 10) {
flushContinuesTrack ();
//dataOut.reset();
bufferedNMEALines = 0;
}
} else {
outCompressed.write ( nmea.getBytes () );
}
// Log.d("TrackManagerService","NMEA:" + nmea);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace ();
}
if (nmea.startsWith ( "$GPGGA" )) {
String[] nmeaSplit = nmea.split ( "," );
if (nmeaSplit.length > 10) {
if (nmeaSplit[9].length () > 0) {
try {
mslAltitude = Float.parseFloat ( nmeaSplit[9] );
} catch (NumberFormatException ex) {
mslAltitude = 0;
}
} else {
mslAltitude = 0.0f;
}
}
}
}
//if (markStarted && hasFix() && nmea.startsWith("$GPGGA")) {
if (markStarted && hasFix () && nmea.startsWith ( "$GPRMC" )) {
markProgress++;
trackListener.onMarkProgress ( markProgress );
if (markProgress >= markMax) {
stopMark ();
}
}
}
}
};
And this is the output it gives when called:
$Start,082719,260220;
$GPGGA,082721.42,2654.2979,N,08056.6065,E,0,100.000,0.000,M,M,0,*44
$GPRMC,082721.42,V,2654.2979,N,08056.6065,E,0.000,0.000,260220,E,N*01
$GPGGA,082722.41,2654.2979,N,08056.6065,E,0,100.000,0.000,M,M,0,*44
$GPRMC,082722.41,V,2654.2979,N,08056.6065,E,0.000,0.000,260220,E,N*01
$End,082802,260220;
$Start,082804,260220;
$GPGGA,082837.42,2654.2979,N,08056.6065,E,0,100.000,0.000,M,M,0,*4C
$GPRMC,082837.42,V,2654.2979,N,08056.6065,E,0.000,0.000,260220,E,N*09
$GPGGA,082838.42,2654.2979,N,08056.6065,E,0,100.000,0.000,M,M,0,*43
$GPGGA,082840.42,2654.2979,N,08056.6065,E,0,100.000,0.000,M,M,0,*4C
$End,082841,260220;
$Start,082921,260220;
$GPGGA,082923.40,2654.2982,N,08056.6059,E,0,100.000,0.000,M,M,0,*41
$GPRMC,082923.40,V,2654.2982,N,08056.6059,E,0.000,0.000,260220,E,N*04
$GPGGA,082924.40,2654.2982,N,08056.6059,E,0,100.000,0.000,M,M,0,*46
$GPRMC,082945.40,V,2654.2982,N,08056.6059,E,0.000,0.000,260220,E,N*04
$End,082945,260220;
And this is the output when called using GNSS listener:
$Start,080450,260220;������������������������������������������������������������������������������������������������������������������������������������������������������������������
Any Sort of way to make this works?
[EDIT]
This is the response from an iOS device, which was accepted by the sever:
$Start,150403,250220;
$GPGGA,150403.69,2654.29986954,N,8056.60312653,E,1,00,0.0,0.0,0,0.0,0,0.0,0000*42;
$GPRMC,150743.99,A,2654.29986954,N,8056.60260391,E,0.0,0.0,250220,0.0,E,A*5;
$GPRMC,150844.26,A,2654.29986954,N,8056.60260391,E,0.0,0.0,250220,0.0,E,A*9;
$GPRMC,150937.91,A,2654.30012894,N,8056.60312653,E,0.0,0.0,250220,0.0,E,A*e;
$GPGGA,150945.04,2654.30429840,N,8056.60781097,E,1,00,0.0,0.0,0,0.0,0000*42;
$GPRMC,150952.01,A,2654.29921722,N,8056.60364532,E,0.0,0.0,250220,0.0,E,A*2;
$End,150953,250220;
$GPGGA,150953.00,2654.29921722,N,8056.60364532,E,1,00,0.0,0.0,0,0.0,0000*42;
$GPRMC,150953.00,A,2654.29921722,N,8056.60364532,E,0.0,0.0,250220,0.0,E,A*2;
Now, I DO NOT have the faintest idea how this works on an iOS device,(a Senior of mine worked on that and gave me this data) but somehow it worked on that and when the same logic was implemented on Android and the data was uploaded to the server it wouldn't accept it, whereas when the iOS data was manipulated in any sort of way ( removing lines, addlines, removing semi-colons, commas,etc.) it would somehow still work.
I have a Serial-to-USB device with a similarly named device driver in the Windows device manager. The devices do not always grab the same COM port on system boot, so my program needs to identify it on start up.
I've tried using RXTX to enumerate the COM ports on the system, but this didn't work because CommPortIdentifier.getName() simply returns the COM name (eg. COM1, COM2, etc.) I need to acquire either the driver manufacturer name, or the driver name as it appears in the device manager, and associate it with the COM name.
Can this easily be done in Java? (I'd be interested in any 3rd party Java libraries that support this.) Otherwise, how I could begin to accomplish this via the win32 API?
I achieved what I wanted by using the WinRegistry class provided by David in this SO question to obtain the FriendlyName from registry key associated with my USB device. I then parse out the COM number from the friendly name.
Some things to consider:
USB devices are located at HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Enum\USB\ in the registry (tested on WinXP, Win7.)
I required the device VID + PID to identify the correct device key (eg. VID_xxxx&PID_xxxx.) Since VID and PID are device specific, this key should be reliable across multiple systems.
The VID_xxxx&PID_xxxx key contains another sub-key with device values. I had some trouble enumerating the sub-keys with WinRegistry, so I hard-coded the sub-key name as a quick hack during development. A much safer solution would search sub-keys to find the correct name.
The device keys exist in the registry regardless of whether the device is currently connected. This code makes the assumption that Windows will update FriendlyName if the device is reconnected to a different COM port. I haven't verified this, but things looked good during use-testing.
Example
String keyPath = "SYSTEM\\CurrentControlSet\\Enum\\USB\\Vid_067b&Pid_2303\\";
String device1 = "5&75451e6&0&1";
System.out.println("First COM device: " + getComNumber(keyPath + device1));
Code
import java.util.regex.Pattern;
import java.util.regex.Matcher;
// Given a registry key, attempts to get the 'FriendlyName' value
// Returns null on failure.
//
public static String getFriendlyName(String registryKey) {
if (registryKey == null || registryKey.isEmpty()) {
throw new IllegalArgumentException("'registryKey' null or empty");
}
try {
int hkey = WinRegistry.HKEY_LOCAL_MACHINE;
return WinRegistry.readString(hkey, registryKey, "FriendlyName");
} catch (Exception ex) { // catch-all:
// readString() throws IllegalArg, IllegalAccess, InvocationTarget
System.err.println(ex.getMessage());
return null;
}
}
// Given a registry key, attempts to parse out the integer after
// substring "COM" in the 'FriendlyName' value; returns -1 on failure.
//
public static int getComNumber(String registryKey) {
String friendlyName = getFriendlyName(registryKey);
if (friendlyName != null && friendlyName.indexOf("COM") >= 0) {
String substr = friendlyName.substring(friendlyName.indexOf("COM"));
Matcher matchInt = Pattern.compile("\\d+").matcher(substr);
if (matchInt.find()) {
return Integer.parseInt(matchInt.group());
}
}
return -1;
}
#robjb Your code does not allow for more than one device to be connected. How will the user know the device name? I added to your code thus to return a list of com ports:
ArrayList<String> subKeys = WinRegistry.readStringSubKeys(WinRegistry.HKEY_LOCAL_MACHINE, keyPath);
ArrayList<Integer> comPorts = new ArrayList<Integer>();
for (String subKey : subKeys) {
String friendlyName = getFriendlyName(keyPath + subKey);
if (friendlyName != null && friendlyName.contains("MyDriverName") && friendlyName.contains("COM")) {
int beginIndex = friendlyName.indexOf("COM") + 3 /*length of 'COM'*/;
int endIndex = friendlyName.indexOf(")");
comPorts.add(Integer.parseInt(friendlyName.substring(beginIndex, endIndex)));
}
}
Update: I don't think these are solutions. Why? This information is statically stored in the registry - even when the device is not connected.
Great example, using JNA, here.
The author (Geir Arne Ruud) has released it under Public Domain License.
My example code
public static String getFriendlyName(GoGPSModel model, String name)
{
if(model.getSystem().getOSType() != OSType.Windows32
&& model.getSystem().getOSType() != OSType.Windows64) {
return name;
}
for (DeviceInformation devInfo : infoObjects) {
System.out.println(devInfo.toString());
String friendlyName = devInfo.getFriendlyName();
if(friendlyName != null && !friendlyName.equals("") && friendlyName.contains(name)) {
return devInfo.getManufacturer() + ": " + friendlyName;
}
}
return name;
}