Ntrip协议(基于HTTP的应用层RTCM网络传输的协议)实际是在TCP/IP协议上进行封装的,依然使用Socket进行数据通信,项目中我们直接将获取到的差分数据封装进了设备的BluetoothSocket因此在获取数据前需要先开始蓝牙连接设备并建立BluetoothSocket。接下来简述过程和部分代码。
BluetoothAdapter.getDefaultAdapter().getBondedDevices();
btSocket = btDevice.createRfcommSocketToServiceRecord(uuid);
btSocket.connect();
NetWorkServiceNtrip netWorkService=new NetWorkServiceNtrip (
this,
ip,
port,
account,
pwd,
mountedId,
btSocket
);
netWorkService.getDifferentialData();
NetWorkService源码如下 public class NetWorkServiceNtrip {
private static final String CMD_HEAD = "$FCMDB,";
private static final String CMD_END = ",*FF\r\n";
//差分服务器IP地址
private String mIP;
//差分服务器端口
private String mPort;
//用户名
private String mUserID;
//密码
private String mPwd;
//挂载点
private String mMountedpoint;
//与差分服务器的Socket
private Socket mSocket;
//Android设备蓝牙通信Socket
private BluetoothSocket bluetoothSocket;
// 与差分服务器的Socket 的数据输出流
private DataOutputStream dos;
//蓝牙通信的输出流
private OutputStream btDos;
// 与差分服务器的Socket 的数据输入流
private DataInputStream dis;
//获取挂载点线程
private NetWorkServiceNtrip.UpdateSourceTableThread mUpdateSourceTableThread;
private NetWorkServiceNtrip.ReportGGA2Service mReportGGA2Service = null;
//获取差分数据线程
private NetWorkServiceNtrip.AcquireDataThread mAcquireDataThread;
//获取挂载点
private ArrayList mountedPoints = null;
private String feedBackState = null;
//获取连接状态
public String getFeedBackState() { return this.feedBackState; }
public ArrayList getMountedPoints() { return this.mountedPoints; }
private Context mContext;
//构造函数
public NetWorkServiceNtrip(Context context,String ipAddress, String port, String userID, String password, String mountedPoint, BluetoothSocket bluetoothSocket) {
this.mContext=context;
this.mIP = ipAddress;
this.mPort = port;
this.mUserID = userID;
this.mPwd = password;
this.mMountedpoint = mountedPoint;
this.bluetoothSocket=bluetoothSocket;
}
//连接差分服务器并获取挂载点列表
public synchronized void connect2Server() {
if(this.mUpdateSourceTableThread != null) {
this.mUpdateSourceTableThread.release();
this.mUpdateSourceTableThread = null;
}
this.mUpdateSourceTableThread = new NetWorkServiceNtrip.UpdateSourceTableThread((NetWorkServiceNtrip.UpdateSourceTableThread)null);
this.mUpdateSourceTableThread.start();
}
//连接差分服务器获取差分数据
public synchronized void getDifferentialData() {
if(this.mAcquireDataThread != null) {
this.mAcquireDataThread.cancle();
this.mAcquireDataThread = null;
}
this.mAcquireDataThread = new NetWorkServiceNtrip.AcquireDataThread((NetWorkServiceNtrip.AcquireDataThread)null);
this.mAcquireDataThread.start();
}
//连接差分服务器
private void getCorsServiceSocket(String ip, String port) {
try {
if(this.mSocket == null) {
InetAddress e = Inet4Address.getByName(ip);
this.mSocket = new Socket(e, Integer.parseInt(port));
}
if(this.dos == null) {
this.dos = new DataOutputStream(this.mSocket.getOutputStream());
}
if(this.dis == null) {
this.dis = new DataInputStream(this.mSocket.getInputStream());
}
if(this.bluetoothSocket != null) {
this.btDos = this.bluetoothSocket.getOutputStream();
}
Log.d("getCorsServiceSocket","Successful");
} catch (UnknownHostException var4) {
var4.printStackTrace();
} catch (NumberFormatException var5) {
var5.printStackTrace();
} catch (IOException var6) {
var6.printStackTrace();
}
}
//获取差分数据线程
private class AcquireDataThread extends Thread {
private boolean _run;
private byte[] buffer;
private AcquireDataThread(AcquireDataThread acquireDataThread) {
this._run = true;
this.buffer = new byte[256];
}
public void run() {
if(NetWorkServiceNtrip.this.mSocket != null) {
NetWorkServiceNtrip.this.mSocket = null;
}
try {
NetWorkServiceNtrip.this.getCorsServiceSocket(NetWorkServiceNtrip.this.mIP, NetWorkServiceNtrip.this.mPort);
if(NetWorkServiceNtrip.this.dos!=null){
//这里将发送的请求参数封装成Ntrip协议格式
NetWorkServiceNtrip.this.dos.write(UtilNtrip.CreateHttpRequsets(NetWorkServiceNtrip.this.mMountedpoint,NetWorkServiceNtrip.this.mUserID,NetWorkServiceNtrip.this.mPwd).getBytes());
}
boolean e = true;
while(this._run) {
if(NetUtils.isConnected(mContext)){
int e1 = NetWorkServiceNtrip.this.dis.read(this.buffer, 0, this.buffer.length);
//自己的业务逻辑中将差分数据大小存入了SharePreference中
UserPreferences.getInstance(mContext).setChaFenDataSize(e1);
if(e1 >= 1) {
String e1x = new String(this.buffer);
if(e1x.startsWith("ICY 200 OK")) {
if(NetWorkServiceNtrip.this.mReportGGA2Service == null) {
NetWorkServiceNtrip.this.mReportGGA2Service = NetWorkServiceNtrip.this.new ReportGGA2Service(NetWorkServiceNtrip.this.dos, (NetWorkServiceNtrip.ReportGGA2Service)null);
NetWorkServiceNtrip.this.mReportGGA2Service.start();
}
NetWorkServiceNtrip.this.feedBackState = "ICY 200 OK";
} else if(e1x.contains("401 Unauthorized")) {
NetWorkServiceNtrip.this.feedBackState = "401 UNAUTHORIZED";
} else {
NetWorkServiceNtrip.this.feedBackState = "SUCCESSFUL";
if(NetWorkServiceNtrip.this.btDos != null) {
//此处将差分服务器的数据直接写入了蓝牙的BluetoothSocket中发送出去
String head = "$FCMDB," + String.valueOf(e1 + 17) + ",";
NetWorkServiceNtrip.this.btDos.write(head.getBytes());
NetWorkServiceNtrip.this.btDos.write(this.buffer, 0, e1);
Log.d("buffer",UtilNtrip.bytesToHexString(this.buffer));
NetWorkServiceNtrip.this.btDos.write(",*FF\r\n".getBytes());
}
}
}
}
}
} catch (UnknownHostException var5) {
var5.printStackTrace();
} catch (IOException var6) {
var6.printStackTrace();
try {
NetWorkServiceNtrip.this.dos.close();
NetWorkServiceNtrip.this.dis.close();
} catch (IOException var4) {
var4.printStackTrace();
}
}
}
public void cancle() {
try {
this._run = false;
NetWorkServiceNtrip.this.mSocket.close();
} catch (IOException var2) {
var2.printStackTrace();
}
}
}
private class ReportGGA2Service extends Thread {
private DataOutputStream dos;
private boolean _run;
private ReportGGA2Service(DataOutputStream dos, ReportGGA2Service reportGGA2Service) {
this.dos = null;
this._run = false;
this.dos = dos;
}
public void run() {
while(!this._run) {
try {
this.dos.write(Praser.getGGAMsg().getBytes());
Thread.sleep(180000L);
} catch (Exception var2) {
this.Cancle();
}
}
}
public void Cancle() {
try {
this._run = true;
} catch (Exception var2) {
}
}
}
private class UpdateSourceTableThread extends Thread {
private UpdateSourceTableThread(UpdateSourceTableThread updateSourceTableThread) {
}
public void run() {
try {
NetWorkServiceNtrip.this.getCorsServiceSocket(NetWorkServiceNtrip.this.mIP, NetWorkServiceNtrip.this.mPort);
if(NetWorkServiceNtrip.this.dos == null) {
NetWorkServiceNtrip.this.mSocket.setSoTimeout(5000);
NetWorkServiceNtrip.this.dos = (DataOutputStream)NetWorkServiceNtrip.this.mSocket.getOutputStream();
}
NetWorkServiceNtrip.this.dos.write(Util.Request2NtripServer().getBytes());
byte[] e = new byte[1024];
StringBuilder sb = new StringBuilder();
boolean len = true;
String sourceString;
int var14;
while((var14 = NetWorkServiceNtrip.this.dis.read(e, 0, e.length)) != -1) {
sourceString = new String(e, 0, var14);
sb.append(sourceString);
}
sourceString = sb.toString();
if(sourceString.startsWith("SOURCETABLE 200 OK")) {
ArrayList mountPoints = new ArrayList();
String[] linStrings = sourceString.split("\r\n");
String[] var10 = linStrings;
int var9 = linStrings.length;
for(int var8 = 0; var8 < var9; ++var8) {
String line = var10[var8];
if(line.startsWith("STR")) {
String[] dataStrings = line.trim().split(";");
mountPoints.add(dataStrings[1]);
}
}
NetWorkServiceNtrip.this.mountedPoints = mountPoints;
}
this.release();
NetWorkServiceNtrip.this.mUpdateSourceTableThread = null;
} catch (UnknownHostException var12) {
var12.printStackTrace();
} catch (IOException var13) {
var13.printStackTrace();
}
}
private void release() {
try {
if(NetWorkServiceNtrip.this.dos != null) {
NetWorkServiceNtrip.this.dos.close();
}
if(NetWorkServiceNtrip.this.dis != null) {
NetWorkServiceNtrip.this.dis.close();
}
if(NetWorkServiceNtrip.this.mSocket != null) {
NetWorkServiceNtrip.this.mSocket.close();
}
} catch (IOException var2) {
var2.printStackTrace();
}
}
}
}
UtilNtrip源码如下 public class UtilNtrip {
public static String CreateHttpRequsets(String mountPoint, String userId, String password) {
String msg = "GET /" + mountPoint + " HTTP/1.0\r\n";
msg = msg + "User-Agent: NTRIP GNSSInternetRadio/1.4.11\r\n";
msg = msg + "Accept: */*\r\n";
msg = msg + "Connection: close\r\n";
String tempString = userId + ":" + password;
byte[] buf = tempString.getBytes();
String code = Base64.encodeToString(buf, 2);
msg = msg + "Authorization: Basic " + code + "\r\n";
msg = msg + "\r\n";
return msg;
}
public static final String bytesToHexString(byte[] bArray) {
StringBuffer sb = new StringBuffer(bArray.length);
String sTemp;
for (int i = 0; i < bArray.length; i++) {
sTemp = Integer.toHexString(0xFF & bArray[i]);
if (sTemp.length() < 2)
sb.append(0);
sb.append(sTemp.toUpperCase());
}
return sb.toString();
}
}
try{
inputStream = btSocket.getInputStream();
if (inputStream != null) {
BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream, "ASCII"));
while ((line = reader.readLine()) != null) {
...
...
//绘制轨迹
drowRoute(double lng, double lat);
...
//封装并回传数据
sendTCPData(GGAUtils.cutString(msg, GROUP, DEVICE));
...
...
}
}catch(IOException e){
e.printStackTrace();
}
获取到数据后提取出经纬度信息调用Arcgis for Android的接口绘制运动轨迹,保存轨迹时调用接口将轨迹图形转换为Json格式存于本地或数据库中。 private void drawRoute(double lng, double lat) {
//自身的定位图层,不断刷新清除之前的定位点
locationLayer.removeAll();
//是否重新开始定位
if (isFristLoaction && lat != 0) {
isFristLoaction = !isFristLoaction;
//创建Arcgis的点
lastPoint = new Point(lng, lat);
//创建Arcgis线条
poly = new Polyline();
//创建Aicgis图形
polyGraphic = new Graphic(poly, sls);
//开始绘制线条的点
poly.startPath(lastPoint);
} else {
Point wsgpoint = new Point(lng, lat);
//投影坐标转换
Point mapPoint = (Point) GeometryEngine.project(wsgpoint, SpatialReference.create(4326), mapView.getSpatialReference());
if (MDistance(lastPoint.getX(), lastPoint.getY(), mapPoint.getX(), mapPoint.getY()) >= 0.05 && MDistance(lastPoint.getX(), lastPoint.getY(), mapPoint.getX(), mapPoint.getY()) <= 20) {
pathGraphlayer.removeAll();
//绘制轨迹线条
poly.lineTo(mapPoint);
lastPoint = mapPoint;
//将线条添加到轨迹图层上
pathGraphlayer.addGraphic(polyGraphic);
//有轨迹则显示保存路径按钮
if (polyGraphic != null) {
pathBtn.post(new Runnable() {
@Override
public void run() {
pathBtn.setVisibility(View.VISIBLE);
}
});
}
//这里跑的时候发现这个BUG,GraphicsLayer在addGraphic时有长度限制,不知道是版本原因还是什么
if (pathGraphlayer.getGraphicIDs().length > 8800) {
pathGraphlayer.removeAll();
}
}
locagraphic = new Graphic(mapPoint, locationMS);
locationTS = new TextSymbol(15, "latitude:" + lat + "\n" + "longitude:" + lng, Color.BLACK);
Graphic locaTSgra = new Graphic(mapPoint, locationTS);
locationLayer.addGraphic(locaTSgra);
locationLayer.addGraphic(locagraphic);
}
}
保存路径很简单的转化为Json格式保存在了本地 FileUtils.writeStrToFile(
new Date().getTime() + "",
GeometryEngine.geometryToJson(mapView.getSpatialReference(), polyGraphic.getGeometry()),
fileName);