/* * Copyright (C) 2016 mendhak * * This file is part of GPSLogger for Android. * * GPSLogger for Android is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 2 of the License, or * (at your option) any later version. * * GPSLogger for Android is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with GPSLogger for Android. If not, see <http://www.gnu.org/licenses/>. */ package com.mendhak.gpslogger.senders.opengts; import com.mendhak.gpslogger.common.*; import com.mendhak.gpslogger.common.events.UploadEvents; import com.mendhak.gpslogger.common.slf4j.Logs; import com.mendhak.gpslogger.loggers.customurl.CustomUrlJob; import com.mendhak.gpslogger.loggers.opengts.OpenGtsUdpJob; import com.mendhak.gpslogger.senders.FileSender; import com.mendhak.gpslogger.senders.GpxReader; import com.path.android.jobqueue.JobManager; import org.slf4j.Logger; import java.io.File; import java.text.DecimalFormat; import java.text.DecimalFormatSymbols; import java.text.SimpleDateFormat; import java.util.*; public class OpenGTSManager extends FileSender { private static final Logger LOG = Logs.of(OpenGTSManager.class); private PreferenceHelper preferenceHelper; public OpenGTSManager(PreferenceHelper preferenceHelper) { this.preferenceHelper = preferenceHelper; } @Override public void uploadFile(List<File> files) { // Use only gpx for (File f : files) { if (f.getName().endsWith(".gpx")) { List<SerializableLocation> locations = getLocationsFromGPX(f); LOG.debug(locations.size() + " points were read from " + f.getName()); sendLocations(locations.toArray(new SerializableLocation[locations.size()])); } } } public void sendLocations(SerializableLocation[] locations){ if (locations.length > 0) { String server = preferenceHelper.getOpenGTSServer(); int port = Integer.parseInt(preferenceHelper.getOpenGTSServerPort()); String path = preferenceHelper.getOpenGTSServerPath(); String deviceId = preferenceHelper.getOpenGTSDeviceId(); String accountName = preferenceHelper.getOpenGTSAccountName(); String communication = preferenceHelper.getOpenGTSServerCommunicationMethod(); if(communication.equalsIgnoreCase("udp")){ JobManager jobManager = AppSettings.getJobManager(); jobManager.addJobInBackground(new OpenGtsUdpJob(server, port, accountName, path, deviceId, communication, locations)); } else { sendByHttp(deviceId, accountName, locations, communication, path, server, port); } } } void sendByHttp(String deviceId, String accountName, SerializableLocation[] locations, String communication, String path, String server, int port) { for(SerializableLocation loc:locations){ String finalUrl = getUrl(deviceId, accountName, loc, communication, path, server, port ); JobManager jobManager = AppSettings.getJobManager(); jobManager.addJobInBackground(new CustomUrlJob(finalUrl,"","", new UploadEvents.OpenGTS())); } } /** * Encode a location as GPRMC string data. * <p/> * For details check org.opengts.util.Nmea0183#_parse_GPRMC(String) * (OpenGTS source) * * @param loc location * @return GPRMC data */ public static String gprmcEncode(SerializableLocation loc) { DecimalFormatSymbols dfs = new DecimalFormatSymbols(Locale.US); DecimalFormat f = new DecimalFormat("0.000000", dfs); String gprmc = String.format("%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,,", "$GPRMC", getNmeaGprmcTime(new Date(loc.getTime())), "A", getNmeaGprmcCoordinates(Math.abs(loc.getLatitude())), (loc.getLatitude() >= 0) ? "N" : "S", getNmeaGprmcCoordinates(Math.abs(loc.getLongitude())), (loc.getLongitude() >= 0) ? "E" : "W", f.format(Maths.mpsToKnots(loc.getSpeed())), f.format(loc.getBearing()), getNmeaGprmcDate(new Date(loc.getTime())) ); gprmc += "*" + getNmeaChecksum(gprmc); return gprmc; } public static String getNmeaGprmcTime(Date dateToFormat) { SimpleDateFormat sdf = new SimpleDateFormat("HHmmss"); sdf.setTimeZone(TimeZone.getTimeZone("UTC")); return sdf.format(dateToFormat); } public static String getNmeaGprmcDate(Date dateToFormat) { SimpleDateFormat sdf = new SimpleDateFormat("ddMMyy"); sdf.setTimeZone(TimeZone.getTimeZone("UTC")); return sdf.format(dateToFormat); } public static String getNmeaGprmcCoordinates(double coord) { // “DDDMM.MMMMM” int degrees = (int) coord; double minutes = (coord - degrees) * 60; DecimalFormat df = new DecimalFormat("00.00000", new DecimalFormatSymbols(Locale.US)); StringBuilder rCoord = new StringBuilder(); rCoord.append(degrees); rCoord.append(df.format(minutes)); return rCoord.toString(); } public static String getNmeaChecksum(String msg) { int chk = 0; for (int i = 1; i < msg.length(); i++) { chk ^= msg.charAt(i); } String chk_s = Integer.toHexString(chk).toUpperCase(); while (chk_s.length() < 2) { chk_s = "0" + chk_s; } return chk_s; } public static String getUrl(String id, String accountName, SerializableLocation loc, String communication, String path, String server, int port) { List<AbstractMap.SimpleEntry<String,String>> qparams = new ArrayList<>(); qparams.add(new AbstractMap.SimpleEntry<>("id", id)); qparams.add(new AbstractMap.SimpleEntry<>("dev", id)); if (!Strings.isNullOrEmpty(accountName)) { qparams.add(new AbstractMap.SimpleEntry<>("acct", accountName)); } else { qparams.add(new AbstractMap.SimpleEntry<>("acct", id)); } //OpenGTS 2.5.5 requires batt param or it throws exception... qparams.add(new AbstractMap.SimpleEntry<>("batt", "0")); qparams.add(new AbstractMap.SimpleEntry<>("code", "0xF020")); qparams.add(new AbstractMap.SimpleEntry<>("alt", String.valueOf(loc.getAltitude()))); qparams.add(new AbstractMap.SimpleEntry<>("gprmc", OpenGTSManager.gprmcEncode(loc))); if(path.startsWith("/")){ path = path.replaceFirst("/",""); } return String.format("%s://%s:%d/%s?%s",communication.toLowerCase(),server,port,path,getQuery(qparams)); } private static String getQuery(List<AbstractMap.SimpleEntry<String, String>> params) { StringBuilder result = new StringBuilder(); boolean first = true; for (AbstractMap.SimpleEntry<String, String> pair : params) { if (first) { first = false; } else { result.append("&"); } result.append(pair.getKey()); result.append("="); result.append(pair.getValue()); } return result.toString(); } @Override public boolean isAvailable() { return !Strings.isNullOrEmpty(preferenceHelper.getOpenGTSServer()) && !Strings.isNullOrEmpty(preferenceHelper.getOpenGTSServerPort()) && Strings.toInt(preferenceHelper.getOpenGTSServerPort(), 0) != 0 && !Strings.isNullOrEmpty(preferenceHelper.getOpenGTSServerCommunicationMethod()) && !Strings.isNullOrEmpty(preferenceHelper.getOpenGTSDeviceId()); } @Override public boolean hasUserAllowedAutoSending() { return preferenceHelper.isOpenGtsAutoSendEnabled(); } private List<SerializableLocation> getLocationsFromGPX(File f) { List<SerializableLocation> locations = Collections.emptyList(); try { locations = GpxReader.getPoints(f); } catch (Exception e) { LOG.error("OpenGTSManager.getLocationsFromGPX", e); } return locations; } @Override public boolean accept(File dir, String name) { return name.toLowerCase().contains(".gpx"); } }