diff --git a/app/build.gradle b/app/build.gradle index 6550e05..bf4b23e 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -73,6 +73,9 @@ dependencies { implementation 'com.squareup.okio:okio:3.2.0' implementation 'com.google.code.gson:gson:2.10.1' implementation(files("libs/mobile-ffmpeg.aar")) +// implementation files("libs/org.eclipse.paho.mqttv5.client-1.2.5.jar") + + diff --git a/app/libs/org.eclipse.paho.mqttv5.client-1.2.5.jar b/app/libs/org.eclipse.paho.mqttv5.client-1.2.5.jar new file mode 100644 index 0000000..7c2deda Binary files /dev/null and b/app/libs/org.eclipse.paho.mqttv5.client-1.2.5.jar differ diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index f5c1a85..29fcf5a 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -25,6 +25,7 @@ android:roundIcon="@mipmap/logo" android:supportsRtl="true" android:theme="@style/Theme.LongYiGroundStation" + android:usesCleartextTraffic="true" tools:targetApi="31"> headersMap = new HashMap(); + headersMap.put("tenant-id", "1"); + headersMap.put("clientid", "Android"); + headersMap.put("Authorization", SharedPreferencesTool.getToken(activity)); + JSONObject jsonObject = new JSONObject(); + jsonObject.put("planeId", "LY266548TRE"); + httpUtil.postJson( + CREATE_FOR_ANDROID, + jsonObject.toString(), + headersMap, + new okhttp3.Callback() { + @Override + public void onFailure(@NonNull Call call, @NonNull IOException e) { + Log.d("Login", "onFailure: "+e); + } + + @Override + public void onResponse(@NonNull Call call, @NonNull Response response) throws IOException { + try { + String json = response.body().string(); + JSONObject jsonObject = new JSONObject(json); + Log.d("Login", jsonObject.getString("data")); +// Toast.makeText(activity, jsonObject.getString("data"), Toast.LENGTH_SHORT).show(); + } catch (Exception e) { + Log.d("Login", " err"); +// Toast.makeText(activity, "网络解析错误"+ response.body(), Toast.LENGTH_SHORT).show(); + } + +// activity.runOnUiThread(new Runnable() { +// @Override +// public void run() { +// +// } +// }); + } + }); + }catch (Exception e){ + + } + } + +} diff --git a/app/src/main/java/com/example/longyi_groundstation/Login/Activity/LoginActivity.java b/app/src/main/java/com/example/longyi_groundstation/Login/Activity/LoginActivity.java index 5b72078..3608afb 100644 --- a/app/src/main/java/com/example/longyi_groundstation/Login/Activity/LoginActivity.java +++ b/app/src/main/java/com/example/longyi_groundstation/Login/Activity/LoginActivity.java @@ -4,6 +4,7 @@ import android.annotation.SuppressLint; import android.content.Intent; import android.os.Bundle; import android.util.Log; +import android.widget.Toast; import androidx.activity.EdgeToEdge; import androidx.appcompat.app.AppCompatActivity; @@ -13,9 +14,11 @@ import androidx.core.view.WindowInsetsCompat; import com.example.longyi_groundstation.Funcation.Activity.FuncationActivity; import com.example.longyi_groundstation.Login.Void.AllView; +import com.example.longyi_groundstation.Login.Void.UrlVoid; import com.example.longyi_groundstation.Main.Activity.MainActivity; import com.example.longyi_groundstation.Main.Void.MyReceiver; import com.example.longyi_groundstation.R; +import com.example.longyi_groundstation.Util.Http.HttpUtil; import com.example.longyi_groundstation.Util.Tool; @@ -26,6 +29,7 @@ public class LoginActivity extends AppCompatActivity { private int type = 0;//0=串口 1=UDP private boolean isSelect = true; + private UrlVoid urlVoid = new UrlVoid(); @Override protected void onCreate(Bundle savedInstanceState) { @@ -74,17 +78,22 @@ public class LoginActivity extends AppCompatActivity { private void initOnClick() { allView.btn_login.setOnClickListener(v -> { - //todo 没有用 if (allView.et_username.getText().toString().equals("admin1")){ type = 1; } +// if (allView.et_username.getText().toString().length() > 0 && allView.et_password.getText().toString().length() > 0){ +// urlVoid.Login(LoginActivity.this, allView.et_username, allView.et_password); +// }else { +// Toast.makeText(LoginActivity.this, "请输入用户名和密码", Toast.LENGTH_SHORT).show(); +// } +// type = 1; Intent intent = new Intent(LoginActivity.this, FuncationActivity.class); intent.putExtra("type", type); if (type != 0){ intent.putExtra("port", "14551"); } startActivity(intent); - finish(); + }); //选择是否记住密码 diff --git a/app/src/main/java/com/example/longyi_groundstation/Login/Void/UrlVoid.java b/app/src/main/java/com/example/longyi_groundstation/Login/Void/UrlVoid.java index fa34b65..2ac26ff 100644 --- a/app/src/main/java/com/example/longyi_groundstation/Login/Void/UrlVoid.java +++ b/app/src/main/java/com/example/longyi_groundstation/Login/Void/UrlVoid.java @@ -5,59 +5,84 @@ import static com.example.longyi_groundstation.Util.Http.HttpUrl.LOGIN; import android.app.Activity; import android.content.Intent; +import android.util.Log; import android.widget.EditText; import android.widget.Toast; import androidx.annotation.NonNull; import com.example.longyi_groundstation.Funcation.Activity.FuncationActivity; +import com.example.longyi_groundstation.Login.Activity.LoginActivity; import com.example.longyi_groundstation.Util.Http.HttpUtil; import com.example.longyi_groundstation.Util.SharedPreferencesTool; import org.json.JSONObject; import java.io.IOException; +import java.util.HashMap; import okhttp3.Call; import okhttp3.Response; public class UrlVoid { - public static HttpUtil httpUtil = new HttpUtil(); + public void Login(Activity activity, EditText et_username, EditText et_password) { + try { + HttpUtil httpUtil = new HttpUtil(activity); +// Log.d("Login", "mobile=" + et_username.getText().toString() + +// "&password=" + et_password.getText().toString()); + HashMap headersMap = new HashMap(); + headersMap.put("tenant-id", "1"); + headersMap.put("clientid", "Android"); + JSONObject jsonObject = new JSONObject(); + jsonObject.put("username", et_username.getText().toString()); + jsonObject.put("password", et_password.getText().toString()); + httpUtil.postJson( + LOGIN, + jsonObject.toString(), + headersMap, + new okhttp3.Callback() { + @Override + public void onFailure(@NonNull Call call, @NonNull IOException e) { + Log.d("Login", "onFailure: " + e); + } - private void Login(Activity activity, EditText et_username, EditText et_password) { - httpUtil.postForm( - LOGIN, - "mobile=" + et_username.getText().toString() + - "&password=" + et_password.getText().toString(), - null, new okhttp3.Callback() { - @Override - public void onFailure(@NonNull Call call, @NonNull IOException e) { + @Override + public void onResponse(@NonNull Call call, @NonNull Response response) throws IOException { + try { + String json = response.body().string(); + JSONObject jsonObject = new JSONObject(json); + if (jsonObject.getInt("code") == 0) { + activity.runOnUiThread(new Runnable() { + @Override + public void run() { + Toast.makeText(activity, "ok", Toast.LENGTH_SHORT).show(); + } + }); - } + SharedPreferencesTool.saveLogin(activity, jsonObject.getJSONObject("data")); + Intent intent = new Intent(activity, FuncationActivity.class); + intent.putExtra("type", 1); + activity.startActivity(intent); + activity.overridePendingTransition(0, 0); + activity.finish(); - @Override - public void onResponse(@NonNull Call call, @NonNull Response response) throws IOException { - activity.runOnUiThread(new Runnable() { - @Override - public void run() { - try { - String json = response.body().string(); - JSONObject jsonObject = new JSONObject(json); - if (jsonObject.getInt("code") == 1) { - SharedPreferencesTool.saveLogin(activity, jsonObject.getJSONObject("data")); - activity.startActivity(new Intent(activity, FuncationActivity.class)); - activity.finish(); - } else { - Toast.makeText(activity, "账号密码错误", Toast.LENGTH_SHORT).show(); - } - } catch (Exception e) { - Toast.makeText(activity, "网络解析错误", Toast.LENGTH_SHORT).show(); + + } else { +// Toast.makeText(activity, jsonObject.getString("msg"), Toast.LENGTH_SHORT).show(); + Log.d("Login", "code: err"); } + } catch (Exception e) { + Log.d("Login", "网络解析错误" + e); + +// Toast.makeText(activity, "网络解析错误"+ response.body(), Toast.LENGTH_SHORT).show(); } - }); - } - }); + + } + }); + } catch (Exception e) { + + } } } diff --git a/app/src/main/java/com/example/longyi_groundstation/MAVLink/common/msg_statustext.java b/app/src/main/java/com/example/longyi_groundstation/MAVLink/common/msg_statustext.java index 75c7c37..25e9846 100644 --- a/app/src/main/java/com/example/longyi_groundstation/MAVLink/common/msg_statustext.java +++ b/app/src/main/java/com/example/longyi_groundstation/MAVLink/common/msg_statustext.java @@ -11,8 +11,6 @@ import com.example.longyi_groundstation.MAVLink.Messages.MAVLinkMessage; import com.example.longyi_groundstation.MAVLink.Messages.MAVLinkPayload; import com.example.longyi_groundstation.MAVLink.Messages.Units; import com.example.longyi_groundstation.MAVLink.Messages.Description; -import com.example.longyi_groundstation.Main.Void.MyTool; -import com.example.longyi_groundstation.Util.Tool; import org.json.JSONException; import org.json.JSONObject; diff --git a/app/src/main/java/com/example/longyi_groundstation/Main/Activity/MainActivity.java b/app/src/main/java/com/example/longyi_groundstation/Main/Activity/MainActivity.java index b5e549c..d615eca 100644 --- a/app/src/main/java/com/example/longyi_groundstation/Main/Activity/MainActivity.java +++ b/app/src/main/java/com/example/longyi_groundstation/Main/Activity/MainActivity.java @@ -2,23 +2,12 @@ package com.example.longyi_groundstation.Main.Activity; import static android.app.PendingIntent.getActivity; import static android.view.View.GONE; -import static android.view.View.INVISIBLE; import static android.view.View.VISIBLE; -import static com.example.longyi_groundstation.MAVLink.enums.MAV_CMD.MAV_CMD_NAV_LAND; -import static com.example.longyi_groundstation.MAVLink.enums.MAV_CMD.MAV_CMD_NAV_RETURN_TO_LAUNCH; -import static com.example.longyi_groundstation.MAVLink.enums.MAV_CMD.MAV_CMD_NAV_TAKEOFF; -import static com.example.longyi_groundstation.Main.Void.AllVoid.rtsp_push; -import static javax.xml.transform.OutputKeys.VERSION; - -import android.Manifest; -import android.animation.ObjectAnimator; import android.annotation.SuppressLint; -import android.app.AlertDialog; import android.content.ComponentName; import android.content.Context; import android.content.Intent; -import android.content.IntentFilter; import android.content.ServiceConnection; import android.graphics.Bitmap; import android.graphics.Color; @@ -26,44 +15,27 @@ import android.graphics.Outline; import android.os.Build; import android.os.Bundle; import android.os.IBinder; -import android.text.Editable; -import android.text.TextWatcher; import android.util.Log; -import android.view.MotionEvent; import android.view.View; import android.view.ViewOutlineProvider; -import android.view.WindowManager; -import android.widget.Button; -import android.widget.ImageView; -import android.widget.LinearLayout; import android.widget.TextView; import android.widget.Toast; import androidx.activity.EdgeToEdge; import androidx.annotation.RequiresApi; import androidx.appcompat.app.AppCompatActivity; -import androidx.core.app.ActivityCompat; import androidx.core.graphics.Insets; import androidx.core.view.ViewCompat; import androidx.core.view.WindowInsetsCompat; import androidx.recyclerview.widget.LinearLayoutManager; -import com.amap.api.location.AMapLocationClientOption; -import com.amap.api.maps.AMap; import com.amap.api.maps.CameraUpdateFactory; import com.amap.api.maps.model.BitmapDescriptorFactory; import com.amap.api.maps.model.LatLng; import com.amap.api.maps.model.Marker; import com.amap.api.maps.model.MarkerOptions; -import com.amap.api.maps.model.MyLocationStyle; import com.amap.api.maps.model.Polyline; import com.amap.api.maps.model.PolylineOptions; -import com.example.longyi_groundstation.MAVLink.common.msg_command_long; -import com.example.longyi_groundstation.MAVLink.common.msg_mission_clear_all; -import com.example.longyi_groundstation.MAVLink.common.msg_mission_count; -import com.example.longyi_groundstation.MAVLink.common.msg_mission_item; -import com.example.longyi_groundstation.MAVLink.enums.MAV_CMD; -import com.example.longyi_groundstation.MAVLink.enums.MAV_FRAME; import com.example.longyi_groundstation.Main.Adapter.AllLinkAdapter; import com.example.longyi_groundstation.Main.Adapter.CreateLinkAdapter; import com.example.longyi_groundstation.Main.Adapter.LogAdapter; @@ -73,31 +45,26 @@ import com.example.longyi_groundstation.Main.Base.LogItem; import com.example.longyi_groundstation.Main.Base.Msg; import com.example.longyi_groundstation.Main.Click.MainClick; import com.example.longyi_groundstation.Main.Service.MyBoundService; -import com.example.longyi_groundstation.Main.Setting.Activity.SettingActivity; import com.example.longyi_groundstation.Main.View.BombingDialog; -import com.example.longyi_groundstation.Main.View.DpadView; -import com.example.longyi_groundstation.Main.View.ErrorLogDialog; import com.example.longyi_groundstation.Main.View.FPV_Void; import com.example.longyi_groundstation.Main.View.LandDialog; import com.example.longyi_groundstation.Main.View.PointFlyDialog; import com.example.longyi_groundstation.Main.View.SaveLinkNameDialog; -import com.example.longyi_groundstation.Main.View.SlideToUnlockView; import com.example.longyi_groundstation.Main.View.StartExecuteDialog; import com.example.longyi_groundstation.Main.View.TakeOffDialog; import com.example.longyi_groundstation.Main.View.TurnBackDialog; import com.example.longyi_groundstation.Main.Void.AllView; import com.example.longyi_groundstation.Main.Void.AllVoid; -import com.example.longyi_groundstation.Main.Void.ContrastTool; -import com.example.longyi_groundstation.Main.Void.CoordinateConverter; -import com.example.longyi_groundstation.Main.Void.FlyVoid; -import com.example.longyi_groundstation.Main.Void.FpvGestureHandler; -import com.example.longyi_groundstation.Main.Void.KeDaTTS; -import com.example.longyi_groundstation.Main.Void.LidarDataParser; -import com.example.longyi_groundstation.Main.Void.MapVoid; -import com.example.longyi_groundstation.Main.Void.MyReceiver; -import com.example.longyi_groundstation.Main.Void.MyTool; -import com.example.longyi_groundstation.Main.Void.SQLClass; -import com.example.longyi_groundstation.Main.Void.XiangTuo.Protocol; +import com.example.longyi_groundstation.Main.Void.Fly.ContrastTool; +import com.example.longyi_groundstation.Main.Void.Fly.FlightDataMonitor; +import com.example.longyi_groundstation.Main.Void.Map.CoordinateConverter; +import com.example.longyi_groundstation.Main.Void.Fly.FlyVoid; +import com.example.longyi_groundstation.Main.Void.XiangTuo.FpvGestureHandler; +import com.example.longyi_groundstation.Main.Void.Fly.LidarDataParser; +import com.example.longyi_groundstation.Main.Void.Map.MapVoid; +import com.example.longyi_groundstation.Main.Void.Mqtt.MqttV5Util; +import com.example.longyi_groundstation.Main.Void.Tool.MyTool; +import com.example.longyi_groundstation.Main.Void.Sql.SQLClass; import com.example.longyi_groundstation.Main.Void.XiangTuo.TcpClientUtil; import com.example.longyi_groundstation.R; import com.example.longyi_groundstation.Util.Tool; @@ -109,8 +76,6 @@ import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Date; import java.util.List; -import java.util.Random; -import java.util.stream.Collectors; public class MainActivity extends AppCompatActivity { @@ -134,8 +99,9 @@ public class MainActivity extends AppCompatActivity { }; //地图方法 private MapVoid mapVoid; - //广播接收器 - private MyReceiver myReceiver_ATTITUDE, myReceiver_GPS_RAW_INT, myReceiver_GLOBAL_POSITION_INT, myReceiver_POWER_STATUS, myReceiver_SYS_STATUS, myReceiver_STATUSTEXT, myReceiver_HEARTBEAT, myReceiver_VFR_HUD, myReceiver_MISSION_REQUEST, myReceiver_MISSION_ACK, myReceiver_MISSION_CURRENT; + // 参数获取线程 + private FlightDataMonitor flightDataMonitor; + //所有组件 private AllView allView; private ArrayList typeList = new ArrayList<>(); @@ -197,19 +163,36 @@ public class MainActivity extends AppCompatActivity { // 关键初始化保留在主线程 initData(); initView(); - initReceiver(); - // 异步初始化非关键组件 new Thread(() -> { - LidarDataParser.startHeightUpdate(allView.tv_height); - mapVoid.startFlightTracking(); + try { + initXiangTuo(); + } catch (Exception e) { + Log.d(TAG, "翔拓初始化失败: " + e); + } + try { + initMQTT(); + }catch (Exception e){ + Log.d(TAG, "MQTT初始化失败: " + e); + } + try { + initReceiver(); + } catch (Exception e) { + Log.d(TAG, "初始化广播参数失败: " + e); + } + try { + initOnClick(); + } catch (Exception e) { + Log.d(TAG, "初始化点击事件失败: " + e); + } }).start(); - // 用户交互相关的初始化保留在主线程 - initOnClick(); + } + + /** * 方法:初始化数据 * @@ -220,114 +203,6 @@ public class MainActivity extends AppCompatActivity { private void initData() { // data = PrefsUtil.getUserObject(this, User.class); intent = getIntent(); - //定位权限 - ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.ACCESS_FINE_LOCATION, Manifest.permission.ACCESS_COARSE_LOCATION}, 1000); - AMapLocationClientOption option = new AMapLocationClientOption(); - option.setLocationMode(AMapLocationClientOption.AMapLocationMode.Hight_Accuracy); // 设置为高精度模式 - //开启广播监听-基础数据 - myReceiver_ATTITUDE = new MyReceiver(); - myReceiver_ATTITUDE.isReceiverRegistered = true; - IntentFilter filter1 = new IntentFilter("Broadcast_ATTITUDE"); - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { - registerReceiver(myReceiver_ATTITUDE, filter1, Context.RECEIVER_EXPORTED); - } else { - registerReceiver(myReceiver_ATTITUDE, filter1); - } - - //开启广播监听-GPS - myReceiver_GPS_RAW_INT = new MyReceiver(); - myReceiver_GPS_RAW_INT.isReceiverRegistered = true; - IntentFilter filter2 = new IntentFilter("Broadcast_GPS_RAW_INT"); - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { - registerReceiver(myReceiver_GPS_RAW_INT, filter2, Context.RECEIVER_EXPORTED); - } else { - registerReceiver(myReceiver_GPS_RAW_INT, filter2); - } - - //开启广播监听-位置 - myReceiver_GLOBAL_POSITION_INT = new MyReceiver(); - IntentFilter filter3 = new IntentFilter("Broadcast_GLOBAL_POSITION_INT"); - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { - registerReceiver(myReceiver_GLOBAL_POSITION_INT, filter3, Context.RECEIVER_EXPORTED); - } else { - registerReceiver(myReceiver_GLOBAL_POSITION_INT, filter3); - } - - //开启广播监听-电量 - myReceiver_POWER_STATUS = new MyReceiver(); - IntentFilter filter4 = new IntentFilter("Broadcast_POWER_STATUS"); - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { - registerReceiver(myReceiver_POWER_STATUS, filter4, Context.RECEIVER_EXPORTED); - } else { - registerReceiver(myReceiver_POWER_STATUS, filter4); - } - - - //开启广播监听-系统位置 - myReceiver_SYS_STATUS = new MyReceiver(); - IntentFilter filter5 = new IntentFilter("Broadcast_SYS_STATUS"); - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { - registerReceiver(myReceiver_SYS_STATUS, filter5, Context.RECEIVER_EXPORTED); - } else { - registerReceiver(myReceiver_SYS_STATUS, filter5); - } - - - //开启广播监听-告警 - myReceiver_STATUSTEXT = new MyReceiver(); - IntentFilter filter6 = new IntentFilter("Broadcast_STATUSTEXT"); - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { - registerReceiver(myReceiver_STATUSTEXT, filter6, Context.RECEIVER_EXPORTED); - } else { - registerReceiver(myReceiver_STATUSTEXT, filter6); - } - - - //开启广播监听-飞行模式 - myReceiver_HEARTBEAT = new MyReceiver(); - IntentFilter filter7 = new IntentFilter("Broadcast_HEARTBEAT"); - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { - registerReceiver(myReceiver_HEARTBEAT, filter7, Context.RECEIVER_EXPORTED); - } else { - registerReceiver(myReceiver_HEARTBEAT, filter7); - } - - //油门 - myReceiver_VFR_HUD = new MyReceiver(); - IntentFilter filter8 = new IntentFilter("Broadcast_VFR_HUD"); - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { - registerReceiver(myReceiver_VFR_HUD, filter8, Context.RECEIVER_EXPORTED); - } else { - registerReceiver(myReceiver_VFR_HUD, filter8); - } - - //航线上传-接收 - myReceiver_MISSION_REQUEST = new MyReceiver(); - IntentFilter filter9 = new IntentFilter("Broadcast_MISSION_REQUEST"); - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { - registerReceiver(myReceiver_MISSION_REQUEST, filter9, Context.RECEIVER_EXPORTED); - } else { - registerReceiver(myReceiver_MISSION_REQUEST, filter9); - } - - //航线上传-异常 - myReceiver_MISSION_ACK = new MyReceiver(); - IntentFilter filter10 = new IntentFilter("Broadcast_MISSION_ACK"); - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { - registerReceiver(myReceiver_MISSION_ACK, filter10, Context.RECEIVER_EXPORTED); - } else { - registerReceiver(myReceiver_MISSION_ACK, filter10); - } - - //目标航点 - myReceiver_MISSION_CURRENT = new MyReceiver(); - IntentFilter filter11 = new IntentFilter("Broadcast_MISSION_CURRENT"); - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { - registerReceiver(myReceiver_MISSION_CURRENT, filter11, Context.RECEIVER_EXPORTED); - } else { - registerReceiver(myReceiver_MISSION_CURRENT, filter11); - } - // 初始化数据源 typeList = new ArrayList<>(); @@ -339,14 +214,6 @@ public class MainActivity extends AppCompatActivity { typeList.add(new Msg("lat", "0", true)); typeList.add(new Msg("lon", "0", true)); - // 使用新的静态方法: - try { - tcpClient = new TcpClientUtil(); - AllVoid.connectToPTZWithRetry(tcpClient, "192.168.144.119", 2000, this, TAG); - } catch (Exception e) { - Toast.makeText(this, "云台控制初始化失败", Toast.LENGTH_SHORT).show(); - } - } /** @@ -355,6 +222,7 @@ public class MainActivity extends AppCompatActivity { * @cuijingzhou */ private void initView() { + //所有组件 allView = new AllView(this); //地图全局方法类 @@ -381,19 +249,7 @@ public class MainActivity extends AppCompatActivity { allView.rv_type_list.setAdapter(typeAdapter); // 延迟初始化FPV视频流 - allView.fpvWidget.post(() -> { - try { - fpvVoid.setupFpvWidget(allView.fpvWidget, "rtsp://192.168.144.119/live"); -// Thread.sleep(5000); -// Toast.makeText(this, "推送:" -// +rtsp_push.pushStreamToServer("rtsp://192.168.144.119/live", "rtmp://192.168.101.102:21935/live/stream_116?sign=hCuYagBHZQ"), Toast.LENGTH_SHORT).show(); - }catch (Exception e){ - - } - - - }); // 初始化FPV手势处理 //起飞弹窗 @@ -442,6 +298,31 @@ public class MainActivity extends AppCompatActivity { } + /** + * 方法:初始化翔拓云台 + * + * @cuijingzhou + */ + private void initXiangTuo(){ + // 初始化rtsp和云台控制 + try { + fpvVoid.setupFpvWidget(allView.fpvWidget, "rtsp://192.168.144.119/live"); + tcpClient = new TcpClientUtil(); + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { + AllVoid.connectToPTZWithRetry(tcpClient, "192.168.144.119", 2000, this, TAG); + } + } catch (Exception e) { + Toast.makeText(this, "云台控制初始化失败", Toast.LENGTH_SHORT).show(); + } + } + + private void initMQTT() { + MqttV5Util mqttV5Util = new MqttV5Util("ws://192.168.101.102:8083/mqtt", "app-"+new Date().getTime()); + if (mqttV5Util.connect("longyi", "LryP0e/wpr;G")) { +// mqttV5Util.publish() + } + } + /** * 方法:所有广播监听 * @@ -450,47 +331,72 @@ public class MainActivity extends AppCompatActivity { @SuppressLint({"NotifyDataSetChanged", "DefaultLocale"}) private void initReceiver() { + // 初始化飞行数据监听器 + flightDataMonitor = new FlightDataMonitor(); + + // 设置更新间隔(可以根据实际需求调整) + flightDataMonitor.setIntervals( + 30, // attitudeInterval + 500, // gpsInterval + 500, // globalPositionInterval + 1000, // powerStatusInterval + 1000, // sysStatusInterval + 500, // statusTextInterval + 500, // heartbeatInterval + 30, // vfrHudInterval + 1000, // missionAckInterval + 500 // missionCurrentInterval + ); + // 在 onCreate() 方法中添加 + flightDataMonitor.startMonitoring(); + //广播接收-ATTITUDE - myReceiver_ATTITUDE.setATTITUDEListener(data -> { + flightDataMonitor.setAttitudeListener(data -> { + // 这里可以更新 UI 或刷新数据 -// Log.d(TAG, "收到新数据ATTITUDE:" +MyReceiver.ATTITUDE_json.optDouble("yaw")); +// Log.d(TAG, "收到新数据ATTITUDE:" + data.optDouble("yaw")); // allView.tv_connect.setText("已连接"); // 示例:更新 typeList 数据并刷新 RecyclerView - if (data != null) { - flyVoid.setAttitude(getApplicationContext(), allView, MyReceiver.ATTITUDE_json.optDouble("roll"), MyReceiver.ATTITUDE_json.optDouble("pitch"), (int) Math.round(MyReceiver.ATTITUDE_json.optDouble("yaw") * 57.3)); - } + flyVoid.setAttitude( + getApplicationContext(), + allView, + data.optDouble("roll"), + data.optDouble("pitch"), + (int) Math.round(data.optDouble("yaw") * 57.3)); //地图上飞机的朝向 - mainMarker.setRotateAngle((int) Math.round(MyReceiver.ATTITUDE_json.optDouble("yaw") * 57.3) * -1); + mainMarker.setRotateAngle((int) Math.round(data.optDouble("yaw") * 57.3) * -1); - allView.tv_yaw.setText((int) Math.round(MyReceiver.ATTITUDE_json.optDouble("yaw") * 57.3) + "°"); + allView.tv_yaw.setText((int) Math.round(data.optDouble("yaw") * 57.3) + "°"); mainMarker.setVisible(true); + }); //广播接收-setGPSListener - myReceiver_GPS_RAW_INT.setGPSListener(data -> { + flightDataMonitor.setGpsListener(data -> { // 这里可以更新 UI 或刷新数据 // Log.d(TAG, "收到新数据GPS:" + data.toString()); - if (!MyReceiver.GPS_RAW_INT_json.optString("satellites_visible").equals("0")) { - allView.tv_satellite.setText(MyReceiver.GPS_RAW_INT_json.optString("satellites_visible")); + if (!data.optString("satellites_visible").equals("0")) { + allView.tv_satellite.setText(data.optString("satellites_visible")); } - allView.tv_vel.setText((MyReceiver.GPS_RAW_INT_json.optDouble("vel") / 100) + "m/s"); + allView.tv_vel.setText((data.optDouble("vel") / 100) + "m/s"); }); //广播接收-setGlobalPositionIntlistener - myReceiver_GLOBAL_POSITION_INT.setGlobalPositionIntlistener(data -> { + flightDataMonitor.setGlobalPositionListener(data -> { // 这里可以更新 UI 或刷新数据 // Log.d(TAG, "收到新数据GLOBAL:" + data.toString()); //要把经纬度转换成高德经纬度 - doubles = CoordinateConverter.wgs84ToGcj02((MyReceiver.GLOBAL_POSITION_INT_json.optDouble("lon", 0) / 10000000), (MyReceiver.GLOBAL_POSITION_INT_json.optDouble("lat", 0) / 10000000)); - - + doubles = CoordinateConverter. + wgs84ToGcj02( + (data.optDouble("lon", 0) / 10000000), + (data.optDouble("lat", 0) / 10000000)); if (doubles[1] != 0) { //获取到位置后移动视角到当前位置 if (islocation) { // 移动视图到Marker点 - mapVoid.aMap.moveCamera(CameraUpdateFactory.newLatLngZoom(new LatLng(MyReceiver.GLOBAL_POSITION_INT_json.optDouble("lat", 0) / 10000000, MyReceiver.GLOBAL_POSITION_INT_json.optDouble("lon", 0) / 10000000), 15)); // 15是缩放级别 + mapVoid.aMap.moveCamera(CameraUpdateFactory.newLatLngZoom(new LatLng(data.optDouble("lat", 0) / 10000000, data.optDouble("lon", 0) / 10000000), 15)); // 15是缩放级别 islocation = false; homeLatLng = new LatLng(doubles[1], doubles[0]); } @@ -501,9 +407,9 @@ public class MainActivity extends AppCompatActivity { // 示例:更新 typeList 数据并刷新 RecyclerView if (data != null) { // typeList.clear(); - typeList.set(0, new Msg("relative_alt", MyReceiver.GLOBAL_POSITION_INT_json.optString("relative_alt"), true)); - typeList.set(1, new Msg("alt", MyReceiver.GLOBAL_POSITION_INT_json.optString("alt"), true)); - typeList.set(3, new Msg("time_boot_ms", MyReceiver.GLOBAL_POSITION_INT_json.optString("time_boot_ms"), true)); + typeList.set(0, new Msg("relative_alt", data.optString("relative_alt"), true)); + typeList.set(1, new Msg("alt", data.optString("alt"), true)); + typeList.set(3, new Msg("time_boot_ms", data.optString("time_boot_ms"), true)); typeList.set(4, new Msg("home_distance", mapVoid.calculateDistance(homeLatLng, new LatLng(doubles[1], doubles[0])) + "m", true)); typeList.set(5, new Msg("lat", doubles[1] + "", true)); typeList.set(6, new Msg("lon", doubles[0] + "", true)); @@ -511,46 +417,31 @@ public class MainActivity extends AppCompatActivity { // 添加更多字段... typeAdapter.notifyDataSetChanged(); } - - //如果有相同的点位就不添加到列表里面去 - if (doubles.length != 0) { - if (doubles[1] != mapVoid.latLngss.get(mapVoid.latLngss.size() - 1).latitude) { - mapVoid.latLngss.add(new LatLng(doubles[1], doubles[0])); - } - - } - - //实时更新飞机的线路,如果线路长度超过10个点,则删除最后一个点位 - if (mapVoid.latLngss.size() > 10) { - mapVoid.latLngss.remove(0); - String coordinates = mapVoid.latLngss.stream().map(latLng -> "(" + latLng.latitude + "," + latLng.longitude + ")").collect(Collectors.joining(", ")); - Log.d("没用", coordinates); - } - - + //获取到数据开始执行 + mapVoid.startFlightTracking(); }); -// //广播接收-setPowrStatuslistener -// myReceiver_POWER_STATUS.setPowrStatuslistener(data -> { -// // 这里可以更新 UI 或刷新数据 -//// Log.d(TAG, "收到新数据POWER_STATUS:" + data.toString()); -//// allView.tv_power.setText( -//// MyReceiver.POWER_STATUS_json.optDouble("Vcc") / 100 -//// + " V"); -// }); + //广播接收-setPowrStatuslistener + flightDataMonitor.setPowerStatusListener(data -> { + // 这里可以更新 UI 或刷新数据 +// Log.d(TAG, "收到新数据POWER_STATUS:" + data.toString()); + allView.tv_power.setText( + data.optDouble("Vcc") / 100 + + " V"); + }); //广播接收-setSysStatuslistener - myReceiver_SYS_STATUS.setSysStatuslistener(data -> { + flightDataMonitor.setSysStatusListener(data -> { // 这里可以更新 UI 或刷新数据 // Log.d(TAG, "收到新数据SYS_STATUS:" + data.toString()); - allView.tv_power.setText(String.format("%.1f", MyReceiver.SYS_STATUS_json.optDouble("voltage_battery") / 1000) + "V"); + allView.tv_power.setText(String.format("%.1f", data.optDouble("voltage_battery") / 1000) + "V"); }); //广播接收-setStatustextlistener - myReceiver_STATUSTEXT.setStatustextlistener(data -> { + flightDataMonitor.setStatusTextListener(data -> { // 这里可以更新 UI 或刷新数据 - if (MyReceiver.STATUSTEXT_json.optInt("severity") <= 5) { - LogItemList.add(0, new LogItem(MyReceiver.STATUSTEXT_json.optString("text"), ContrastTool.findMostSimilarMatch(MyReceiver.STATUSTEXT_json.optString("text")), new Date(), MyReceiver.STATUSTEXT_json.optInt("severity"))); + if (data.optInt("severity") <= 5) { + LogItemList.add(0, new LogItem(data.optString("text"), ContrastTool.findMostSimilarMatch(data.optString("text")), new Date(), data.optInt("severity"))); adapter.setList(LogItemList); allView.iv_error.setVisibility(VISIBLE); } @@ -559,14 +450,14 @@ public class MainActivity extends AppCompatActivity { }); //广播接收-setHeartbeatlistener - myReceiver_HEARTBEAT.setHeartbeatlistener(data -> { + flightDataMonitor.setHeartbeatListener(data -> { - isUnlock = Tool.getDecToFirstBin(MyReceiver.HEARTBEAT_json.optString("base_mode")).equals("1"); + isUnlock = Tool.getDecToFirstBin(data.optString("base_mode")).equals("1"); if (allView.ll_link_start.getVisibility() == VISIBLE) { // Log.d(TAG, "myReceiver_HEARTBEAT: " + data.toString()); //判断飞控是否解锁 - if (Tool.getDecToFirstBin(MyReceiver.HEARTBEAT_json.optString("base_mode")).equals("1")) { + if (Tool.getDecToFirstBin(data.optString("base_mode")).equals("1")) { //已解锁 // allView.rl_unlock.setVisibility(View.GONE); // allView.ll_link_start_fun2.setVisibility(VISIBLE); @@ -582,7 +473,7 @@ public class MainActivity extends AppCompatActivity { // 这里可以更新 UI 或刷新数据 - switch (MyReceiver.HEARTBEAT_json.optInt("custom_mode")) { + switch (data.optInt("custom_mode")) { case 0: allView.tv_connect.setText("姿态模式"); break; @@ -623,7 +514,7 @@ public class MainActivity extends AppCompatActivity { }); //广播接收-setAttitudeTargetlistener - myReceiver_VFR_HUD.setVfrHudlistener(data -> { + flightDataMonitor.setVfrHudListener(data -> { // Log.d(TAG, "myReceiver_VFR_HUD: "+ FlyVoid.paramList.get("MOT_SPIN_MIN").getParam_value()+"-"+ // Double.parseDouble(FlyVoid.paramList.get("MOT_SPIN_MAX").getParam_value())+"-"+ // Double.parseDouble(FlyVoid.paramList.get("MOT_THST_EXPO").getParam_value())+"-"+ @@ -637,7 +528,10 @@ public class MainActivity extends AppCompatActivity { // 1 // ))); if (data.optDouble("throttle") > 0) { - typeList.set(2, new Msg("throttle", String.format("%.1f", MyTool.getThrottle(Double.parseDouble(FlyVoid.paramList.get("MOT_SPIN_MIN").getParam_value()), Double.parseDouble(FlyVoid.paramList.get("MOT_SPIN_MAX").getParam_value()), Double.parseDouble(FlyVoid.paramList.get("MOT_THST_EXPO").getParam_value()), data.optDouble("throttle") / 100, 1) * 100) + "%", true)); + typeList.set(2, new Msg("throttle", + String.format( + "%.1f", + MyTool.getThrottle(Double.parseDouble(FlyVoid.paramList.get("MOT_SPIN_MIN").getParam_value()), Double.parseDouble(FlyVoid.paramList.get("MOT_SPIN_MAX").getParam_value()), Double.parseDouble(FlyVoid.paramList.get("MOT_THST_EXPO").getParam_value()), data.optDouble("throttle") / 100, 1) * 100) + "%", true)); } else { typeList.set(2, new Msg("throttle", "0%", true)); } @@ -647,14 +541,13 @@ public class MainActivity extends AppCompatActivity { // myReceiver_MISSION_REQUEST.setMissionRequestlistener(data -> { //// Log.d(TAG, "myReceiver_MISSION_REQUEST: "+data.toString()); // }); -// + //广播接收-setMissionAcklistener -// myReceiver_MISSION_ACK.setMissionAcklistener(data -> { -// Log.d(TAG, "myReceiver_MISSION_ACK: " + data.toString()); -// }); -// + flightDataMonitor.setMissionAckListener(data -> { + Log.d(TAG, "myReceiver_MISSION_ACK: " + data.toString()); + }); //广播接收-setMissionAcklistener - myReceiver_MISSION_CURRENT.setMissionCurrentlistener(data -> { + flightDataMonitor.setMissionCurrentListener(data -> { // Log.d(TAG, "myReceiver_MISSION_CURRENT: " + data.toString()); allView.tv_test1.setText(data.optInt("seq") + ""); }); @@ -1038,51 +931,9 @@ public class MainActivity extends AppCompatActivity { // 在需要停止服务的地方(如按钮点击事件) isBound = false; } - //注销广播接收器(避免内存泄漏) - if (myReceiver_ATTITUDE.isReceiverRegistered) { - unregisterReceiver(myReceiver_ATTITUDE); - myReceiver_ATTITUDE.isReceiverRegistered = false; - } - //注销广播接收器(避免内存泄漏) - if (myReceiver_GPS_RAW_INT.isReceiverRegistered) { - unregisterReceiver(myReceiver_GPS_RAW_INT); - myReceiver_GPS_RAW_INT.isReceiverRegistered = false; - } - //注销广播接收器(避免内存泄漏) - if (myReceiver_GLOBAL_POSITION_INT.isReceiverRegistered) { - unregisterReceiver(myReceiver_GLOBAL_POSITION_INT); - myReceiver_GLOBAL_POSITION_INT.isReceiverRegistered = false; - } - //注销广播接收器(避免内存泄漏) - if (myReceiver_POWER_STATUS.isReceiverRegistered) { - unregisterReceiver(myReceiver_POWER_STATUS); - myReceiver_POWER_STATUS.isReceiverRegistered = false; - } - //注销广播接收器(避免内存泄漏) - if (myReceiver_SYS_STATUS.isReceiverRegistered) { - unregisterReceiver(myReceiver_SYS_STATUS); - myReceiver_SYS_STATUS.isReceiverRegistered = false; - } - //注销广播接收器(避免内存泄漏)· - if (myReceiver_STATUSTEXT.isReceiverRegistered) { - unregisterReceiver(myReceiver_STATUSTEXT); - myReceiver_STATUSTEXT.isReceiverRegistered = false; - } - //注销广播接收器(避免内存泄漏) - if (myReceiver_HEARTBEAT.isReceiverRegistered) { - unregisterReceiver(myReceiver_HEARTBEAT); - myReceiver_HEARTBEAT.isReceiverRegistered = false; - } - - //注销广播接收器(避免内存泄漏) - if (myReceiver_VFR_HUD.isReceiverRegistered) { - unregisterReceiver(myReceiver_VFR_HUD); - myReceiver_VFR_HUD.isReceiverRegistered = false; - } - //注销广播接收器(避免内存泄漏) - if (myReceiver_MISSION_REQUEST.isReceiverRegistered) { - unregisterReceiver(myReceiver_MISSION_REQUEST); - myReceiver_MISSION_REQUEST.isReceiverRegistered = false; + // 停止飞行数据监听器 + if (flightDataMonitor != null) { + flightDataMonitor.stopMonitoring(); } fpvVoid.Fstop(allView.fpvWidget); diff --git a/app/src/main/java/com/example/longyi_groundstation/Main/Activity/PlayBackActivity.java b/app/src/main/java/com/example/longyi_groundstation/Main/Activity/PlayBackActivity.java index b2d4671..f1d851f 100644 --- a/app/src/main/java/com/example/longyi_groundstation/Main/Activity/PlayBackActivity.java +++ b/app/src/main/java/com/example/longyi_groundstation/Main/Activity/PlayBackActivity.java @@ -10,7 +10,7 @@ import androidx.core.view.ViewCompat; import androidx.core.view.WindowInsetsCompat; import com.example.longyi_groundstation.Main.View.CustomSeekBar; -import com.example.longyi_groundstation.Main.Void.MyTool; +import com.example.longyi_groundstation.Main.Void.Tool.MyTool; import com.example.longyi_groundstation.R; import java.math.BigDecimal; diff --git a/app/src/main/java/com/example/longyi_groundstation/Main/Adapter/AllLinkAdapter.java b/app/src/main/java/com/example/longyi_groundstation/Main/Adapter/AllLinkAdapter.java index 6f0599b..91dc604 100644 --- a/app/src/main/java/com/example/longyi_groundstation/Main/Adapter/AllLinkAdapter.java +++ b/app/src/main/java/com/example/longyi_groundstation/Main/Adapter/AllLinkAdapter.java @@ -5,7 +5,6 @@ import android.util.Log; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; -import android.widget.Button; import android.widget.LinearLayout; import android.widget.TextView; import android.widget.Toast; @@ -14,7 +13,7 @@ import androidx.annotation.NonNull; import androidx.recyclerview.widget.RecyclerView; import com.example.longyi_groundstation.Main.Base.CreateLink; -import com.example.longyi_groundstation.Main.Void.SQLClass; +import com.example.longyi_groundstation.Main.Void.Sql.SQLClass; import com.example.longyi_groundstation.R; import java.text.SimpleDateFormat; diff --git a/app/src/main/java/com/example/longyi_groundstation/Main/Click/MainClick.java b/app/src/main/java/com/example/longyi_groundstation/Main/Click/MainClick.java index ae56890..42979d8 100644 --- a/app/src/main/java/com/example/longyi_groundstation/Main/Click/MainClick.java +++ b/app/src/main/java/com/example/longyi_groundstation/Main/Click/MainClick.java @@ -1,9 +1,6 @@ package com.example.longyi_groundstation.Main.Click; -import android.Manifest; -import android.annotation.SuppressLint; import android.app.AlertDialog; -import android.content.Context; import android.content.Intent; import android.graphics.Bitmap; import android.graphics.Color; @@ -20,7 +17,6 @@ import com.amap.api.maps.model.BitmapDescriptorFactory; import com.amap.api.maps.model.LatLng; import com.amap.api.maps.model.Marker; import com.amap.api.maps.model.MarkerOptions; -import com.amap.api.maps.model.PolylineOptions; import com.example.longyi_groundstation.Main.Activity.MainActivity; import com.example.longyi_groundstation.Main.Adapter.AllLinkAdapter; import com.example.longyi_groundstation.Main.Adapter.CreateLinkAdapter; @@ -28,31 +24,23 @@ import com.example.longyi_groundstation.Main.Base.CreateLink; import com.example.longyi_groundstation.Main.Service.MyBoundService; import com.example.longyi_groundstation.Main.Setting.Activity.SettingActivity; import com.example.longyi_groundstation.Main.Void.AllView; -import com.example.longyi_groundstation.Main.Void.CoordinateConverter; -import com.example.longyi_groundstation.Main.Void.FlyVoid; -import com.example.longyi_groundstation.Main.Void.FpvGestureHandler; -import com.example.longyi_groundstation.Main.Void.KeDaTTS; -import com.example.longyi_groundstation.Main.Void.LidarDataParser; -import com.example.longyi_groundstation.Main.Void.MapVoid; +import com.example.longyi_groundstation.Main.Void.Fly.FlyVoid; +import com.example.longyi_groundstation.Main.Void.XiangTuo.FpvGestureHandler; +import com.example.longyi_groundstation.Main.Void.Map.MapVoid; import com.example.longyi_groundstation.Main.Void.MyReceiver; -import com.example.longyi_groundstation.Main.Void.MyTool; -import com.example.longyi_groundstation.Main.Void.SQLClass; +import com.example.longyi_groundstation.Main.Void.Tool.MyTool; +import com.example.longyi_groundstation.Main.Void.Sql.SQLClass; import com.example.longyi_groundstation.Main.Void.XiangTuo.Protocol; import com.example.longyi_groundstation.Main.Void.XiangTuo.TcpClientUtil; import com.example.longyi_groundstation.R; -import com.example.longyi_groundstation.Util.Tool; import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Date; import java.util.List; -import java.util.stream.Collectors; import static android.view.View.GONE; import static android.view.View.VISIBLE; -import static com.example.longyi_groundstation.MAVLink.enums.MAV_CMD.MAV_CMD_NAV_LAND; -import static com.example.longyi_groundstation.MAVLink.enums.MAV_CMD.MAV_CMD_NAV_RETURN_TO_LAUNCH; -import static com.example.longyi_groundstation.MAVLink.enums.MAV_CMD.MAV_CMD_NAV_TAKEOFF; import static com.example.longyi_groundstation.Main.Activity.MainActivity.selectedLinkList; public class MainClick implements View.OnClickListener { diff --git a/app/src/main/java/com/example/longyi_groundstation/Main/Service/MyBoundService.java b/app/src/main/java/com/example/longyi_groundstation/Main/Service/MyBoundService.java index 31081b3..5024044 100644 --- a/app/src/main/java/com/example/longyi_groundstation/Main/Service/MyBoundService.java +++ b/app/src/main/java/com/example/longyi_groundstation/Main/Service/MyBoundService.java @@ -1,15 +1,12 @@ package com.example.longyi_groundstation.Main.Service; import static com.example.longyi_groundstation.MAVLink.common.msg_attitude.MAVLINK_MSG_ID_ATTITUDE; -import static com.example.longyi_groundstation.MAVLink.common.msg_attitude_target.MAVLINK_MSG_ID_ATTITUDE_TARGET; import static com.example.longyi_groundstation.MAVLink.common.msg_global_position_int.MAVLINK_MSG_ID_GLOBAL_POSITION_INT; import static com.example.longyi_groundstation.MAVLink.common.msg_gps_raw_int.MAVLINK_MSG_ID_GPS_RAW_INT; import static com.example.longyi_groundstation.MAVLink.common.msg_mission_ack.MAVLINK_MSG_ID_MISSION_ACK; import static com.example.longyi_groundstation.MAVLink.common.msg_mission_count.MAVLINK_MSG_ID_MISSION_COUNT; import static com.example.longyi_groundstation.MAVLink.common.msg_mission_current.MAVLINK_MSG_ID_MISSION_CURRENT; import static com.example.longyi_groundstation.MAVLink.common.msg_mission_request.MAVLINK_MSG_ID_MISSION_REQUEST; -import static com.example.longyi_groundstation.MAVLink.common.msg_param_request_list.MAVLINK_MSG_ID_PARAM_REQUEST_LIST; -import static com.example.longyi_groundstation.MAVLink.common.msg_param_request_read.MAVLINK_MSG_ID_PARAM_REQUEST_READ; import static com.example.longyi_groundstation.MAVLink.common.msg_param_value.MAVLINK_MSG_ID_PARAM_VALUE; import static com.example.longyi_groundstation.MAVLink.common.msg_power_status.MAVLINK_MSG_ID_POWER_STATUS; import static com.example.longyi_groundstation.MAVLink.common.msg_rc_channels.MAVLINK_MSG_ID_RC_CHANNELS; @@ -19,8 +16,6 @@ import static com.example.longyi_groundstation.MAVLink.common.msg_sys_status.MAV import static com.example.longyi_groundstation.MAVLink.common.msg_vfr_hud.MAVLINK_MSG_ID_VFR_HUD; import static com.example.longyi_groundstation.MAVLink.enums.MAV_DATA_STREAM.MAV_DATA_STREAM_ALL; import static com.example.longyi_groundstation.MAVLink.minimal.msg_heartbeat.MAVLINK_MSG_ID_HEARTBEAT; -import static com.example.longyi_groundstation.Main.Void.SerialTool.bytesToHex; -import static com.example.longyi_groundstation.Main.Void.SerialTool.parseSerialData; import android.app.Service; import android.content.Intent; @@ -30,37 +25,25 @@ import android.os.IBinder; import android.os.Looper; import android.util.Log; import android.widget.TextView; -import android.widget.Toast; import com.example.longyi_groundstation.MAVLink.MAVLinkPacket; import com.example.longyi_groundstation.MAVLink.Messages.MAVLinkMessage; import com.example.longyi_groundstation.MAVLink.Parser; import com.example.longyi_groundstation.MAVLink.common.msg_param_request_list; -import com.example.longyi_groundstation.MAVLink.common.msg_param_request_read; import com.example.longyi_groundstation.MAVLink.common.msg_request_data_stream; -import com.example.longyi_groundstation.Main.Base.MLData; +import com.example.longyi_groundstation.Main.Service.Void.HeartBeat; import com.example.longyi_groundstation.Main.Setting.Base.Param; -import com.example.longyi_groundstation.Main.Void.FlyVoid; -import com.example.longyi_groundstation.Main.Void.HeartbeatManager; -import com.example.longyi_groundstation.Main.Void.LidarDataParser; -import com.example.longyi_groundstation.Main.Void.LogCat.LogUtil; -import com.example.longyi_groundstation.Main.Void.MyTool; +import com.example.longyi_groundstation.Main.Void.Fly.FlyVoid; +import com.example.longyi_groundstation.Main.Void.Fly.LidarDataParser; import com.example.longyi_groundstation.Util.BroadcastUtil; -import com.example.longyi_groundstation.Util.Tool; import com.google.gson.Gson; -import org.json.JSONException; -import org.json.JSONObject; - import java.io.IOException; import java.net.DatagramPacket; import java.net.DatagramSocket; import java.net.InetAddress; import java.net.SocketException; import java.util.ArrayList; -import java.util.HashMap; -import java.util.IllegalFormatCodePointException; -import java.util.Objects; import tp.xmaihh.serialport.SerialHelper; import tp.xmaihh.serialport.bean.ComBean; @@ -77,7 +60,7 @@ public class MyBoundService extends Service { public static DatagramSocket serverSocket2; private boolean isRunning = false; - private String serverPort = "14551"; // 服务端监听端口 + private String serverPort = "13551"; // 服务端监听端口 // 定义一个 Binder 子类,用于返回本地服务实例 @@ -122,7 +105,7 @@ public class MyBoundService extends Service { private boolean isAttitudeDataRequested = false; private boolean isParamReadListRequested = false; // 在成员变量区域添加 - private HeartbeatManager heartbeatManager; + private HeartBeat heartBeat ; @@ -133,8 +116,8 @@ public class MyBoundService extends Service { // serialPortFinder = new SerialPortFinder(); //判断打开方式0:串口 1:UDP if (type == 0) { -// serialHelper = new SerialHelper("/dev/ttyHS0", 115200) { - serialHelper = new SerialHelper("/dev/ttyHS0", 57600) { + serialHelper = new SerialHelper("/dev/ttyHS0", 115200) { +// serialHelper = new SerialHelper("/dev/ttyHS0", 57600) { @Override protected void onDataReceived(final ComBean comBean) { // Log.d("cuijingzhou", Tool.bytesToHex(comBean.bRec)); @@ -143,6 +126,8 @@ public class MyBoundService extends Service { dataWork(receivedData, receivedData.length); } }; + // 初始化 HeartBeat + heartBeat = new HeartBeat(type, serialHelper,null); try { serialHelper.open(); } catch (IOException e) { @@ -155,6 +140,8 @@ public class MyBoundService extends Service { new Thread(() -> { try { serverSocket = new DatagramSocket(Integer.parseInt(serverPort)); + // 初始化 HeartBeat + heartBeat = new HeartBeat(type, null, serverSocket); byte[] buffer = new byte[512]; while (isRunning) { try { @@ -174,7 +161,7 @@ public class MyBoundService extends Service { } } - } catch (SocketException e) { + } catch (Exception e) { Log.e(TAG, "启动服务端失败: " + e.getMessage()); } finally { @@ -193,6 +180,8 @@ public class MyBoundService extends Service { requestParamReadList(); // 请求姿态数据(只执行一次) requestAttitudeData(); + // 启动心跳 只执行一次 + heartBeat.startHeartbeat(); } @@ -274,9 +263,9 @@ public class MyBoundService extends Service { request.req_message_rate = 5; // 10Hz频率 request.start_stop = 1; // 1=开启 + request.isMavlink2 = true; // 编码为MAVLinkPacket MAVLinkPacket packet = request.pack(); - // 发送数据(根据连接方式选择) if (type == 0) { // 串口发送 @@ -287,7 +276,7 @@ public class MyBoundService extends Service { // UDP发送(需指定目标IP和端口) try { InetAddress targetAddress = InetAddress.getByName("127.0.0.1"); - int targetPort = 14553; // 默认MAVLink端口 + int targetPort = 14552; // 默认MAVLink端口 DatagramPacket udpPacket = new DatagramPacket( packet.encodePacket(), packet.encodePacket().length, @@ -316,6 +305,7 @@ public class MyBoundService extends Service { request.target_system = 1; // 飞控系统ID request.target_component = 1; // 飞控组件ID + request.isMavlink2 = true; // 编码为MAVLinkPacket MAVLinkPacket packet = request.pack(); @@ -329,7 +319,7 @@ public class MyBoundService extends Service { // UDP发送(需指定目标IP和端口) try { InetAddress targetAddress = InetAddress.getByName("127.0.0.1"); - int targetPort = 14553; // 默认MAVLink端口 + int targetPort = 14552; // 默认MAVLink端口 DatagramPacket udpPacket = new DatagramPacket( packet.encodePacket(), packet.encodePacket().length, @@ -457,12 +447,14 @@ public class MyBoundService extends Service { } } catch (Exception e) { - Log.e("cuijingzhou", e.toString()); +// Log.e("cuijingzhou", e.toString()); } }).start(); } + + private long lastParamReceiveTime = 0; // 最后一次收到参数的时间 private static final long PARAM_TIMEOUT = 2000; // 超时时间(毫秒) private boolean isAllParamsReceived = false; // 是否已接收完毕 @@ -504,10 +496,10 @@ public class MyBoundService extends Service { BroadcastUtil.Broadcast_MISSION_REQUEST(getApplication(), MsgList.get(MAVLINK_MSG_ID_MISSION_REQUEST)); } -// case MAVLINK_MSG_ID_MISSION_ACK: -// if (MsgList.get(MAVLINK_MSG_ID_MISSION_ACK) != null) { -// BroadcastUtil.Broadcast_MISSION_ACK(getApplication(), MsgList.get(MAVLINK_MSG_ID_MISSION_ACK)); -// } + case MAVLINK_MSG_ID_MISSION_ACK: + if (MsgList.get(MAVLINK_MSG_ID_MISSION_ACK) != null) { + BroadcastUtil.Broadcast_MISSION_ACK(getApplication(), MsgList.get(MAVLINK_MSG_ID_MISSION_ACK)); + } default: // Log.d("cuijigzhou_msg_all_id", "不做处理:"+msg.msgid); @@ -565,6 +557,11 @@ public class MyBoundService extends Service { stopUdpServer(); paramTimeoutHandler.removeCallbacks(paramTimeoutRunnable); + // 停止心跳 + if (heartBeat != null) { + heartBeat.stopHeartbeat(); + } + } diff --git a/app/src/main/java/com/example/longyi_groundstation/Main/Service/Void/HeartBeat.java b/app/src/main/java/com/example/longyi_groundstation/Main/Service/Void/HeartBeat.java new file mode 100644 index 0000000..67cd1f3 --- /dev/null +++ b/app/src/main/java/com/example/longyi_groundstation/Main/Service/Void/HeartBeat.java @@ -0,0 +1,115 @@ +// HeartBeat.java +package com.example.longyi_groundstation.Main.Service.Void; + +import android.os.Handler; +import android.os.Looper; +import android.util.Log; + +import com.example.longyi_groundstation.MAVLink.MAVLinkPacket; +import com.example.longyi_groundstation.MAVLink.Messages.MAVLinkMessage; +import com.example.longyi_groundstation.MAVLink.enums.MAV_AUTOPILOT; +import com.example.longyi_groundstation.MAVLink.enums.MAV_STATE; +import com.example.longyi_groundstation.MAVLink.enums.MAV_TYPE; +import com.example.longyi_groundstation.MAVLink.minimal.msg_heartbeat; + +import java.net.DatagramPacket; +import java.net.InetAddress; + +import tp.xmaihh.serialport.SerialHelper; + +public class HeartBeat { + private static final String TAG = "HeartBeat"; + private Handler heartbeatHandler = new Handler(Looper.getMainLooper()); + private Runnable heartbeatRunnable; + private int type; // 0: 串口, 1: UDP + private SerialHelper serialHelper; + private java.net.DatagramSocket serverSocket; + + public HeartBeat(int connectionType, SerialHelper serialHelper, java.net.DatagramSocket serverSocket) { + this.type = connectionType; + this.serialHelper = serialHelper; + this.serverSocket = serverSocket; + } + + /** + * 方法:发送心跳包 (HEARTBEAT) + */ + private void sendHeartbeat() { + try { + // 创建MAVLink心跳消息 + msg_heartbeat heartbeat = new msg_heartbeat(); + heartbeat.type = MAV_TYPE.MAV_TYPE_GCS; // 发送方类型:地面站 + heartbeat.autopilot = MAV_AUTOPILOT.MAV_AUTOPILOT_INVALID; // 自动驾驶仪类型 + heartbeat.base_mode = 0; // 基本模式 + heartbeat.custom_mode = 0; // 自定义模式 + heartbeat.system_status = MAV_STATE.MAV_STATE_ACTIVE; // 系统状态:活跃 + // MAVLink2 特有字段 + heartbeat.mavlink_version = 3; +// heartbeat.isMavlink2 = true;// MAVLink版本号(MAVLink2为3) + // 发送MAVLink消息 + sendMavlinkMessage(heartbeat); +// Log.d(TAG, "sendHeartbeat: ok -"+heartbeat.pack().len); + } catch (Exception e) { + Log.e(TAG, "发送心跳包失败: " + e.getMessage()); + } + } + + /** + * 通用MAVLink消息发送方法 + */ + private void sendMavlinkMessage(MAVLinkMessage msg) { + MAVLinkPacket packet = msg.pack(); + + if (type == 0) { // 串口 + if (serialHelper != null) { + serialHelper.send(packet.encodePacket()); + } + } else { // UDP + // 将网络操作放到后台线程执行 + new Thread(() -> { + try { + InetAddress targetAddress = InetAddress.getByName("127.0.0.1"); // 改为飞控IP + DatagramPacket udpPacket = new DatagramPacket( + packet.encodePacket(), + packet.encodePacket().length, + targetAddress, + 14552 // MAVLink标准端口 + ); + if (serverSocket != null && !serverSocket.isClosed()) { + serverSocket.send(udpPacket); + } + } catch (Exception e) { + Log.e(TAG, "发送失败: " + e); + } + }).start(); + } + } + + + /** + * 方法:启动心跳包发送定时器 + */ + public void startHeartbeat() { + if (heartbeatRunnable == null) { + heartbeatRunnable = new Runnable() { + @Override + public void run() { + sendHeartbeat(); +// Log.d(TAG, "run: 11"); + heartbeatHandler.postDelayed(this, 1000); // 每1秒发送一次 + } + }; + heartbeatHandler.post(heartbeatRunnable); // 立即发送第一次心跳 + } + } + + /** + * 方法:停止心跳包发送定时器 + */ + public void stopHeartbeat() { + if (heartbeatRunnable != null) { + heartbeatHandler.removeCallbacks(heartbeatRunnable); + heartbeatRunnable = null; + } + } +} diff --git a/app/src/main/java/com/example/longyi_groundstation/Main/Setting/Activity/SettingActivity.java b/app/src/main/java/com/example/longyi_groundstation/Main/Setting/Activity/SettingActivity.java index 56ea1b8..8c6068f 100644 --- a/app/src/main/java/com/example/longyi_groundstation/Main/Setting/Activity/SettingActivity.java +++ b/app/src/main/java/com/example/longyi_groundstation/Main/Setting/Activity/SettingActivity.java @@ -25,7 +25,7 @@ import com.example.longyi_groundstation.Main.Setting.Fragment.SecureFragment; import com.example.longyi_groundstation.Main.Setting.Fragment.SensorFragment; import com.example.longyi_groundstation.Main.Setting.Fragment.SettingsFragment; import com.example.longyi_groundstation.Main.Setting.Void.AllView; -import com.example.longyi_groundstation.Main.Void.FlyVoid; +import com.example.longyi_groundstation.Main.Void.Fly.FlyVoid; import com.example.longyi_groundstation.R; public class SettingActivity extends AppCompatActivity { diff --git a/app/src/main/java/com/example/longyi_groundstation/Main/Setting/Fragment/ControlFragment.java b/app/src/main/java/com/example/longyi_groundstation/Main/Setting/Fragment/ControlFragment.java index 41181a9..b86767e 100644 --- a/app/src/main/java/com/example/longyi_groundstation/Main/Setting/Fragment/ControlFragment.java +++ b/app/src/main/java/com/example/longyi_groundstation/Main/Setting/Fragment/ControlFragment.java @@ -16,7 +16,7 @@ import androidx.recyclerview.widget.GridLayoutManager; import androidx.recyclerview.widget.RecyclerView; import com.example.longyi_groundstation.Main.Setting.Adapter.ParamGridAdapter; -import com.example.longyi_groundstation.Main.Void.FlyVoid; +import com.example.longyi_groundstation.Main.Void.Fly.FlyVoid; import com.example.longyi_groundstation.Main.Void.MyReceiver; import com.example.longyi_groundstation.R; @@ -125,7 +125,7 @@ public class ControlFragment extends Fragment { getList(); adapter.notifyDataSetChanged(); } catch (Exception e) { - Log.d("cuijingzhou", "没事"); +// Log.d("cuijingzhou", "没事"); } } diff --git a/app/src/main/java/com/example/longyi_groundstation/Main/Setting/Fragment/FlyFragment.java b/app/src/main/java/com/example/longyi_groundstation/Main/Setting/Fragment/FlyFragment.java index 211e7c5..aaa61e8 100644 --- a/app/src/main/java/com/example/longyi_groundstation/Main/Setting/Fragment/FlyFragment.java +++ b/app/src/main/java/com/example/longyi_groundstation/Main/Setting/Fragment/FlyFragment.java @@ -10,7 +10,7 @@ import android.widget.Toast; import androidx.fragment.app.Fragment; -import com.example.longyi_groundstation.Main.Void.FlyVoid; +import com.example.longyi_groundstation.Main.Void.Fly.FlyVoid; import com.example.longyi_groundstation.R; diff --git a/app/src/main/java/com/example/longyi_groundstation/Main/Setting/Fragment/FoundationFragment.java b/app/src/main/java/com/example/longyi_groundstation/Main/Setting/Fragment/FoundationFragment.java index e064a05..6c64c90 100644 --- a/app/src/main/java/com/example/longyi_groundstation/Main/Setting/Fragment/FoundationFragment.java +++ b/app/src/main/java/com/example/longyi_groundstation/Main/Setting/Fragment/FoundationFragment.java @@ -14,16 +14,11 @@ import android.widget.TextView; import android.widget.Toast; import androidx.fragment.app.Fragment; -import androidx.viewpager2.widget.ViewPager2; -import com.example.longyi_groundstation.Main.Setting.Adapter.SecurePagerAdapter; -import com.example.longyi_groundstation.Main.Setting.Base.ChannelItem; import com.example.longyi_groundstation.Main.Setting.Base.ModeItem; -import com.example.longyi_groundstation.Main.Void.FlyVoid; +import com.example.longyi_groundstation.Main.Void.Fly.FlyVoid; import com.example.longyi_groundstation.R; -import com.google.android.material.tabs.TabLayout; import com.google.android.material.tabs.TabLayoutMediator; -import com.example.longyi_groundstation.Main.Setting.Adapter.FoundationPagerAdapter; import java.util.ArrayList; import java.util.List; diff --git a/app/src/main/java/com/example/longyi_groundstation/Main/Setting/Fragment/LoadFragment.java b/app/src/main/java/com/example/longyi_groundstation/Main/Setting/Fragment/LoadFragment.java index 5b83bb6..57905d0 100644 --- a/app/src/main/java/com/example/longyi_groundstation/Main/Setting/Fragment/LoadFragment.java +++ b/app/src/main/java/com/example/longyi_groundstation/Main/Setting/Fragment/LoadFragment.java @@ -21,7 +21,7 @@ import androidx.annotation.Nullable; import androidx.fragment.app.Fragment; import com.example.longyi_groundstation.Main.Setting.Base.ChannelItem; -import com.example.longyi_groundstation.Main.Void.FlyVoid; +import com.example.longyi_groundstation.Main.Void.Fly.FlyVoid; import com.example.longyi_groundstation.R; import java.util.ArrayList; diff --git a/app/src/main/java/com/example/longyi_groundstation/Main/Setting/Fragment/MotorFragment.java b/app/src/main/java/com/example/longyi_groundstation/Main/Setting/Fragment/MotorFragment.java index c3c5883..ece771e 100644 --- a/app/src/main/java/com/example/longyi_groundstation/Main/Setting/Fragment/MotorFragment.java +++ b/app/src/main/java/com/example/longyi_groundstation/Main/Setting/Fragment/MotorFragment.java @@ -15,7 +15,7 @@ import androidx.recyclerview.widget.RecyclerView; import com.example.longyi_groundstation.Main.Setting.Adapter.MultiSelectAdapter; import com.example.longyi_groundstation.Main.Setting.Base.Motor; -import com.example.longyi_groundstation.Main.Void.FlyVoid; +import com.example.longyi_groundstation.Main.Void.Fly.FlyVoid; import com.example.longyi_groundstation.R; import java.util.ArrayList; diff --git a/app/src/main/java/com/example/longyi_groundstation/Main/Setting/Fragment/SecureFragment.java b/app/src/main/java/com/example/longyi_groundstation/Main/Setting/Fragment/SecureFragment.java index 8770af9..9f60cda 100644 --- a/app/src/main/java/com/example/longyi_groundstation/Main/Setting/Fragment/SecureFragment.java +++ b/app/src/main/java/com/example/longyi_groundstation/Main/Setting/Fragment/SecureFragment.java @@ -14,7 +14,6 @@ import android.widget.TextView; import androidx.fragment.app.Fragment; -import com.example.longyi_groundstation.Main.Void.MyTool; import com.example.longyi_groundstation.R; diff --git a/app/src/main/java/com/example/longyi_groundstation/Main/Setting/Fragment/SensorFragment.java b/app/src/main/java/com/example/longyi_groundstation/Main/Setting/Fragment/SensorFragment.java index 7e00b4d..de3071c 100644 --- a/app/src/main/java/com/example/longyi_groundstation/Main/Setting/Fragment/SensorFragment.java +++ b/app/src/main/java/com/example/longyi_groundstation/Main/Setting/Fragment/SensorFragment.java @@ -5,14 +5,12 @@ import android.util.Log; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; -import android.widget.EditText; -import android.widget.TextView; import androidx.fragment.app.Fragment; import com.example.longyi_groundstation.Main.Setting.Void.MyTool; import com.example.longyi_groundstation.Main.Setting.Void.SensorAllView; -import com.example.longyi_groundstation.Main.Void.FlyVoid; +import com.example.longyi_groundstation.Main.Void.Fly.FlyVoid; import com.example.longyi_groundstation.R; diff --git a/app/src/main/java/com/example/longyi_groundstation/Main/Setting/Fragment/SettingsFragment.java b/app/src/main/java/com/example/longyi_groundstation/Main/Setting/Fragment/SettingsFragment.java index 537bd19..83a18a0 100644 --- a/app/src/main/java/com/example/longyi_groundstation/Main/Setting/Fragment/SettingsFragment.java +++ b/app/src/main/java/com/example/longyi_groundstation/Main/Setting/Fragment/SettingsFragment.java @@ -1,51 +1,35 @@ package com.example.longyi_groundstation.Main.Setting.Fragment; import android.annotation.SuppressLint; -import android.content.Context; -import android.content.IntentFilter; -import android.os.Build; import android.os.Bundle; import android.os.Handler; import android.text.Editable; import android.text.TextWatcher; -import android.util.Log; import android.view.KeyEvent; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.view.inputmethod.EditorInfo; -import android.widget.Button; import android.widget.EditText; -import android.widget.PopupMenu; import android.widget.RelativeLayout; import android.widget.TextView; import android.widget.Toast; -import androidx.core.content.ContextCompat; import androidx.fragment.app.Fragment; import androidx.recyclerview.widget.LinearLayoutManager; import androidx.recyclerview.widget.RecyclerView; -import com.example.longyi_groundstation.MAVLink.MAVLinkPacket; -import com.example.longyi_groundstation.MAVLink.common.msg_param_request_list; -import com.example.longyi_groundstation.MAVLink.common.msg_param_set; -import com.example.longyi_groundstation.Main.Service.MyBoundService; import com.example.longyi_groundstation.Main.Setting.Adapter.ParamGroupAdapter; import com.example.longyi_groundstation.Main.Setting.Base.Param; import com.example.longyi_groundstation.Main.Setting.Base.ParamGroup; import com.example.longyi_groundstation.Main.Setting.Adapter.ParamAdapter; import com.example.longyi_groundstation.Main.Setting.Void.ProgressDialogUtil; import com.example.longyi_groundstation.Main.Setting.Void.ViewTool; -import com.example.longyi_groundstation.Main.Void.FlyVoid; -import com.example.longyi_groundstation.Main.Void.MyReceiver; -import com.example.longyi_groundstation.Main.Void.MyTool; +import com.example.longyi_groundstation.Main.Void.Fly.FlyVoid; import com.example.longyi_groundstation.R; -import com.google.gson.Gson; import java.util.ArrayList; -import java.util.Comparator; import java.util.HashMap; -import java.util.List; public class SettingsFragment extends Fragment { private View view; diff --git a/app/src/main/java/com/example/longyi_groundstation/Main/View/BombingDialog.java b/app/src/main/java/com/example/longyi_groundstation/Main/View/BombingDialog.java index def6e10..7d94772 100644 --- a/app/src/main/java/com/example/longyi_groundstation/Main/View/BombingDialog.java +++ b/app/src/main/java/com/example/longyi_groundstation/Main/View/BombingDialog.java @@ -1,7 +1,5 @@ package com.example.longyi_groundstation.Main.View; -import static com.example.longyi_groundstation.MAVLink.enums.MAV_CMD.MAV_CMD_NAV_TAKEOFF; - import android.annotation.SuppressLint; import android.app.Activity; import android.app.AlertDialog; @@ -14,10 +12,8 @@ import android.widget.EditText; import android.widget.TextView; import android.widget.Toast; -import com.example.longyi_groundstation.MAVLink.common.msg_command_long; -import com.example.longyi_groundstation.Main.Service.MyBoundService; -import com.example.longyi_groundstation.Main.Void.FlyVoid; -import com.example.longyi_groundstation.Main.Void.MyTool; +import com.example.longyi_groundstation.Main.Void.Fly.FlyVoid; +import com.example.longyi_groundstation.Main.Void.Tool.MyTool; import com.example.longyi_groundstation.R; public class BombingDialog { diff --git a/app/src/main/java/com/example/longyi_groundstation/Main/View/ErrorLogDialog.java b/app/src/main/java/com/example/longyi_groundstation/Main/View/ErrorLogDialog.java index 009d42a..6906c7f 100644 --- a/app/src/main/java/com/example/longyi_groundstation/Main/View/ErrorLogDialog.java +++ b/app/src/main/java/com/example/longyi_groundstation/Main/View/ErrorLogDialog.java @@ -14,7 +14,7 @@ import androidx.recyclerview.widget.LinearLayoutManager; import androidx.recyclerview.widget.RecyclerView; import com.example.longyi_groundstation.Main.Adapter.LogAdapter; -import com.example.longyi_groundstation.Main.Void.MyTool; +import com.example.longyi_groundstation.Main.Void.Tool.MyTool; import com.example.longyi_groundstation.R; public class ErrorLogDialog { diff --git a/app/src/main/java/com/example/longyi_groundstation/Main/View/LandDialog.java b/app/src/main/java/com/example/longyi_groundstation/Main/View/LandDialog.java index 1bb2289..1bf2d28 100644 --- a/app/src/main/java/com/example/longyi_groundstation/Main/View/LandDialog.java +++ b/app/src/main/java/com/example/longyi_groundstation/Main/View/LandDialog.java @@ -3,18 +3,16 @@ package com.example.longyi_groundstation.Main.View; import android.annotation.SuppressLint; import android.app.Activity; import android.app.AlertDialog; -import android.content.Context; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.view.Window; import android.view.WindowManager; -import android.widget.EditText; import android.widget.TextView; import android.widget.Toast; -import com.example.longyi_groundstation.Main.Void.FlyVoid; -import com.example.longyi_groundstation.Main.Void.MyTool; +import com.example.longyi_groundstation.Main.Void.Fly.FlyVoid; +import com.example.longyi_groundstation.Main.Void.Tool.MyTool; import com.example.longyi_groundstation.R; public class LandDialog { diff --git a/app/src/main/java/com/example/longyi_groundstation/Main/View/PointFlyDialog.java b/app/src/main/java/com/example/longyi_groundstation/Main/View/PointFlyDialog.java index 011d6cf..6454e1b 100644 --- a/app/src/main/java/com/example/longyi_groundstation/Main/View/PointFlyDialog.java +++ b/app/src/main/java/com/example/longyi_groundstation/Main/View/PointFlyDialog.java @@ -13,8 +13,8 @@ import android.widget.TextView; import android.widget.Toast; import com.amap.api.maps.model.LatLng; -import com.example.longyi_groundstation.Main.Void.FlyVoid; -import com.example.longyi_groundstation.Main.Void.MyTool; +import com.example.longyi_groundstation.Main.Void.Fly.FlyVoid; +import com.example.longyi_groundstation.Main.Void.Tool.MyTool; import com.example.longyi_groundstation.R; public class PointFlyDialog { diff --git a/app/src/main/java/com/example/longyi_groundstation/Main/View/SaveLinkNameDialog.java b/app/src/main/java/com/example/longyi_groundstation/Main/View/SaveLinkNameDialog.java index e793b2e..b1b8dcf 100644 --- a/app/src/main/java/com/example/longyi_groundstation/Main/View/SaveLinkNameDialog.java +++ b/app/src/main/java/com/example/longyi_groundstation/Main/View/SaveLinkNameDialog.java @@ -1,7 +1,6 @@ package com.example.longyi_groundstation.Main.View; import android.annotation.SuppressLint; -import android.app.Activity; import android.app.AlertDialog; import android.view.LayoutInflater; import android.view.View; @@ -13,8 +12,8 @@ import android.widget.TextView; import android.widget.Toast; import com.example.longyi_groundstation.Main.Activity.MainActivity; -import com.example.longyi_groundstation.Main.Void.FlyVoid; -import com.example.longyi_groundstation.Main.Void.MyTool; +import com.example.longyi_groundstation.Main.Void.Fly.FlyVoid; +import com.example.longyi_groundstation.Main.Void.Tool.MyTool; import com.example.longyi_groundstation.R; public class SaveLinkNameDialog { diff --git a/app/src/main/java/com/example/longyi_groundstation/Main/View/StartExecuteDialog.java b/app/src/main/java/com/example/longyi_groundstation/Main/View/StartExecuteDialog.java index ba44397..472a9f0 100644 --- a/app/src/main/java/com/example/longyi_groundstation/Main/View/StartExecuteDialog.java +++ b/app/src/main/java/com/example/longyi_groundstation/Main/View/StartExecuteDialog.java @@ -11,14 +11,13 @@ import android.view.Window; import android.view.WindowManager; import android.widget.AdapterView; import android.widget.ArrayAdapter; -import android.widget.EditText; import android.widget.Spinner; import android.widget.TextView; import android.widget.Toast; import com.example.longyi_groundstation.Main.Activity.MainActivity; -import com.example.longyi_groundstation.Main.Void.FlyVoid; -import com.example.longyi_groundstation.Main.Void.MyTool; +import com.example.longyi_groundstation.Main.Void.Fly.FlyVoid; +import com.example.longyi_groundstation.Main.Void.Tool.MyTool; import com.example.longyi_groundstation.R; public class StartExecuteDialog { diff --git a/app/src/main/java/com/example/longyi_groundstation/Main/View/TakeOffDialog.java b/app/src/main/java/com/example/longyi_groundstation/Main/View/TakeOffDialog.java index bcd7fc3..66b8556 100644 --- a/app/src/main/java/com/example/longyi_groundstation/Main/View/TakeOffDialog.java +++ b/app/src/main/java/com/example/longyi_groundstation/Main/View/TakeOffDialog.java @@ -1,11 +1,8 @@ package com.example.longyi_groundstation.Main.View; -import static com.example.longyi_groundstation.MAVLink.enums.MAV_CMD.MAV_CMD_NAV_TAKEOFF; - import android.annotation.SuppressLint; import android.app.Activity; import android.app.AlertDialog; -import android.content.Context; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; @@ -15,14 +12,8 @@ import android.widget.EditText; import android.widget.TextView; import android.widget.Toast; -import androidx.recyclerview.widget.LinearLayoutManager; -import androidx.recyclerview.widget.RecyclerView; - -import com.example.longyi_groundstation.MAVLink.common.msg_command_long; -import com.example.longyi_groundstation.Main.Adapter.LogAdapter; -import com.example.longyi_groundstation.Main.Service.MyBoundService; -import com.example.longyi_groundstation.Main.Void.FlyVoid; -import com.example.longyi_groundstation.Main.Void.MyTool; +import com.example.longyi_groundstation.Main.Void.Fly.FlyVoid; +import com.example.longyi_groundstation.Main.Void.Tool.MyTool; import com.example.longyi_groundstation.R; public class TakeOffDialog { diff --git a/app/src/main/java/com/example/longyi_groundstation/Main/View/TurnBackDialog.java b/app/src/main/java/com/example/longyi_groundstation/Main/View/TurnBackDialog.java index 1b26174..58d5314 100644 --- a/app/src/main/java/com/example/longyi_groundstation/Main/View/TurnBackDialog.java +++ b/app/src/main/java/com/example/longyi_groundstation/Main/View/TurnBackDialog.java @@ -1,13 +1,8 @@ package com.example.longyi_groundstation.Main.View; -import static com.example.longyi_groundstation.MAVLink.enums.MAV_CMD.MAV_CMD_NAV_LAND; -import static com.example.longyi_groundstation.MAVLink.enums.MAV_CMD.MAV_CMD_NAV_RETURN_TO_LAUNCH; -import static com.example.longyi_groundstation.MAVLink.enums.MAV_CMD.MAV_CMD_NAV_TAKEOFF; - import android.annotation.SuppressLint; import android.app.Activity; import android.app.AlertDialog; -import android.content.Context; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; @@ -17,10 +12,8 @@ import android.widget.EditText; import android.widget.TextView; import android.widget.Toast; -import com.example.longyi_groundstation.MAVLink.common.msg_command_long; -import com.example.longyi_groundstation.Main.Service.MyBoundService; -import com.example.longyi_groundstation.Main.Void.FlyVoid; -import com.example.longyi_groundstation.Main.Void.MyTool; +import com.example.longyi_groundstation.Main.Void.Fly.FlyVoid; +import com.example.longyi_groundstation.Main.Void.Tool.MyTool; import com.example.longyi_groundstation.R; public class TurnBackDialog { diff --git a/app/src/main/java/com/example/longyi_groundstation/Main/Void/ContrastTool.java b/app/src/main/java/com/example/longyi_groundstation/Main/Void/Fly/ContrastTool.java similarity index 98% rename from app/src/main/java/com/example/longyi_groundstation/Main/Void/ContrastTool.java rename to app/src/main/java/com/example/longyi_groundstation/Main/Void/Fly/ContrastTool.java index f709805..718df0d 100644 --- a/app/src/main/java/com/example/longyi_groundstation/Main/Void/ContrastTool.java +++ b/app/src/main/java/com/example/longyi_groundstation/Main/Void/Fly/ContrastTool.java @@ -1,8 +1,6 @@ -package com.example.longyi_groundstation.Main.Void; +package com.example.longyi_groundstation.Main.Void.Fly; import java.util.HashMap; -import java.util.HashSet; -import java.util.Set; /** * 对比工具类 diff --git a/app/src/main/java/com/example/longyi_groundstation/Main/Void/Fly/FlightDataMonitor.java b/app/src/main/java/com/example/longyi_groundstation/Main/Void/Fly/FlightDataMonitor.java new file mode 100644 index 0000000..d844755 --- /dev/null +++ b/app/src/main/java/com/example/longyi_groundstation/Main/Void/Fly/FlightDataMonitor.java @@ -0,0 +1,406 @@ +package com.example.longyi_groundstation.Main.Void.Fly; + +import static com.example.longyi_groundstation.MAVLink.common.msg_attitude.MAVLINK_MSG_ID_ATTITUDE; +import static com.example.longyi_groundstation.MAVLink.common.msg_global_position_int.MAVLINK_MSG_ID_GLOBAL_POSITION_INT; +import static com.example.longyi_groundstation.MAVLink.common.msg_gps_raw_int.MAVLINK_MSG_ID_GPS_RAW_INT; +import static com.example.longyi_groundstation.MAVLink.common.msg_mission_ack.MAVLINK_MSG_ID_MISSION_ACK; +import static com.example.longyi_groundstation.MAVLink.common.msg_mission_current.MAVLINK_MSG_ID_MISSION_CURRENT; +import static com.example.longyi_groundstation.MAVLink.common.msg_power_status.MAVLINK_MSG_ID_POWER_STATUS; +import static com.example.longyi_groundstation.MAVLink.common.msg_statustext.MAVLINK_MSG_ID_STATUSTEXT; +import static com.example.longyi_groundstation.MAVLink.common.msg_sys_status.MAVLINK_MSG_ID_SYS_STATUS; +import static com.example.longyi_groundstation.MAVLink.common.msg_vfr_hud.MAVLINK_MSG_ID_VFR_HUD; +import static com.example.longyi_groundstation.MAVLink.minimal.msg_heartbeat.MAVLINK_MSG_ID_HEARTBEAT; +import static com.example.longyi_groundstation.Main.Service.MyBoundService.MsgList; + +import android.os.Handler; +import android.os.Looper; +import android.util.Log; + +import com.example.longyi_groundstation.Main.Void.MyReceiver; + +import org.json.JSONObject; + +/** + * 飞行数据监听工具类,替代原有的广播接收器方式 + * + * @author cuijingzhou + */ +public class FlightDataMonitor { + + private static final String TAG = "FlightDataMonitor"; + + // 主线程Handler,用于切换到UI线程更新界面 + private Handler mainHandler = new Handler(Looper.getMainLooper()); + + // 监听器接口定义 + public interface AttitudeListener { + void onAttitudeUpdate(JSONObject data); + } + + public interface GpsListener { + void onGpsUpdate(JSONObject data); + } + + public interface GlobalPositionListener { + void onGlobalPositionUpdate(JSONObject data); + } + + public interface PowerStatusListener { + void onPowerStatusUpdate(JSONObject data); + } + + public interface SysStatusListener { + void onSysStatusUpdate(JSONObject data); + } + + public interface StatusTextListener { + void onStatusTextUpdate(JSONObject data); + } + + public interface HeartbeatListener { + void onHeartbeatUpdate(JSONObject data); + } + + public interface VfrHudListener { + void onVfrHudUpdate(JSONObject data); + } + + public interface MissionAckListener { + void onMissionAckUpdate(JSONObject data); + } + + public interface MissionCurrentListener { + void onMissionCurrentUpdate(JSONObject data); + } + + // 监听器实例 + private AttitudeListener attitudeListener; + private GpsListener gpsListener; + private GlobalPositionListener globalPositionListener; + private PowerStatusListener powerStatusListener; + private SysStatusListener sysStatusListener; + private StatusTextListener statusTextListener; + private HeartbeatListener heartbeatListener; + private VfrHudListener vfrHudListener; + private MissionAckListener missionAckListener; + private MissionCurrentListener missionCurrentListener; + + // 控制线程运行状态 + private volatile boolean isRunning = false; + private Thread monitorThread; + + // 各数据类型的更新间隔(毫秒) + private long attitudeInterval = 30; // 姿态数据更新间隔 + private long gpsInterval = 500; // GPS数据更新间隔 + private long globalPositionInterval = 200; // 全局位置更新间隔 + private long powerStatusInterval = 1000; // 电源状态更新间隔 + private long sysStatusInterval = 1000; // 系统状态更新间隔 + private long statusTextInterval = 200; // 状态文本更新间隔 + private long heartbeatInterval = 1000; // 心跳包更新间隔 + private long vfrHudInterval = 30; // 油门数据更新间隔 + private long missionAckInterval = 1000; // 任务确认更新间隔 + private long missionCurrentInterval = 1000; // 当前任务更新间隔 + + // 上次更新时间记录 + private long lastAttitudeTime = 0; + private long lastGpsTime = 0; + private long lastGlobalPositionTime = 0; + private long lastPowerStatusTime = 0; + private long lastSysStatusTime = 0; + private long lastStatusTextTime = 0; + private long lastHeartbeatTime = 0; + private long lastVfrHudTime = 0; + private long lastMissionAckTime = 0; + private long lastMissionCurrentTime = 0; + + public FlightDataMonitor() { + } + + /** + * 设置各数据类型的更新间隔 + */ + public void setIntervals(long attitude, long gps, long globalPosition, long powerStatus, + long sysStatus, long statusText, long heartbeat, long vfrHud, + long missionAck, long missionCurrent) { + this.attitudeInterval = attitude; + this.gpsInterval = gps; + this.globalPositionInterval = globalPosition; + this.powerStatusInterval = powerStatus; + this.sysStatusInterval = sysStatus; + this.statusTextInterval = statusText; + this.heartbeatInterval = heartbeat; + this.vfrHudInterval = vfrHud; + this.missionAckInterval = missionAck; + this.missionCurrentInterval = missionCurrent; + } + + /** + * 设置监听器 + */ + public void setAttitudeListener(AttitudeListener listener) { + this.attitudeListener = listener; + } + + public void setGpsListener(GpsListener listener) { + this.gpsListener = listener; + } + + public void setGlobalPositionListener(GlobalPositionListener listener) { + this.globalPositionListener = listener; + } + + public void setPowerStatusListener(PowerStatusListener listener) { + this.powerStatusListener = listener; + } + + public void setSysStatusListener(SysStatusListener listener) { + this.sysStatusListener = listener; + } + + public void setStatusTextListener(StatusTextListener listener) { + this.statusTextListener = listener; + } + + public void setHeartbeatListener(HeartbeatListener listener) { + this.heartbeatListener = listener; + } + + public void setVfrHudListener(VfrHudListener listener) { + this.vfrHudListener = listener; + } + + public void setMissionAckListener(MissionAckListener listener) { + this.missionAckListener = listener; + } + + public void setMissionCurrentListener(MissionCurrentListener listener) { + this.missionCurrentListener = listener; + } + + /** + * 开始监听 + */ + public void startMonitoring() { + if (isRunning) { + return; + } + + isRunning = true; + monitorThread = new Thread(() -> { + while (isRunning) { + long currentTime = System.currentTimeMillis(); + + // 检查并更新各类数据 + checkAndUpdateAttitude(currentTime); + checkAndUpdateGps(currentTime); + checkAndUpdateGlobalPosition(currentTime); + checkAndUpdatePowerStatus(currentTime); + checkAndUpdateSysStatus(currentTime); + checkAndUpdateStatusText(currentTime); + checkAndUpdateHeartbeat(currentTime); + checkAndUpdateVfrHud(currentTime); + checkAndUpdateMissionAck(currentTime); + checkAndUpdateMissionCurrent(currentTime); + + try { + Thread.sleep(30); // 每50ms检查一次 + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + break; + } + } + }); + monitorThread.setName("FlightDataMonitor"); + monitorThread.start(); + } + + /** + * 停止监听 + */ + public void stopMonitoring() { + isRunning = false; + if (monitorThread != null) { + monitorThread.interrupt(); + } + } + + private void checkAndUpdateAttitude(long currentTime) { + if (attitudeListener != null && (currentTime - lastAttitudeTime) >= attitudeInterval) { + try { + if (MsgList.get(MAVLINK_MSG_ID_ATTITUDE) == null){ + return; + } + JSONObject data = new JSONObject(MsgList.get(MAVLINK_MSG_ID_ATTITUDE)); + if (data != null) { + // 切换到主线程执行回调,避免在子线程中更新UI + mainHandler.post(() -> attitudeListener.onAttitudeUpdate(data)); + } + lastAttitudeTime = currentTime; + } catch (Exception e) { + Log.e(TAG, "Error updating attitude data", e); + } + } + } + + private void checkAndUpdateGps(long currentTime) { + if (gpsListener != null && (currentTime - lastGpsTime) >= gpsInterval) { + try { + if (MsgList.get(MAVLINK_MSG_ID_GPS_RAW_INT) == null){ + return; + } + JSONObject data = new JSONObject(MsgList.get(MAVLINK_MSG_ID_GPS_RAW_INT)); + if (data != null) { + // 切换到主线程执行回调,避免在子线程中更新UI + mainHandler.post(() -> gpsListener.onGpsUpdate(data)); + } + lastGpsTime = currentTime; + } catch (Exception e) { + Log.e(TAG, "Error updating GPS data", e); + } + } + } + + private void checkAndUpdateGlobalPosition(long currentTime) { + if (globalPositionListener != null && (currentTime - lastGlobalPositionTime) >= globalPositionInterval ) { + try { + if (MsgList.get(MAVLINK_MSG_ID_GLOBAL_POSITION_INT) == null){ + return; + } + JSONObject data = new JSONObject(MsgList.get(MAVLINK_MSG_ID_GLOBAL_POSITION_INT)); + if (data != null) { + // 切换到主线程执行回调,避免在子线程中更新UI + mainHandler.post(() -> globalPositionListener.onGlobalPositionUpdate(data)); + } + lastGlobalPositionTime = currentTime; + } catch (Exception e) { + Log.e(TAG, "Error updating global position data", e); + } + } + } + + private void checkAndUpdatePowerStatus(long currentTime) { + if (powerStatusListener != null && (currentTime - lastPowerStatusTime) >= powerStatusInterval ) { + try { + if (MsgList.get(MAVLINK_MSG_ID_POWER_STATUS) == null){ + return; + } + JSONObject data = new JSONObject(MsgList.get(MAVLINK_MSG_ID_POWER_STATUS)); + if (data != null) { + // 切换到主线程执行回调,避免在子线程中更新UI + mainHandler.post(() -> powerStatusListener.onPowerStatusUpdate(data)); + } + lastPowerStatusTime = currentTime; + } catch (Exception e) { + Log.e(TAG, "Error updating power status data", e); + } + } + } + + private void checkAndUpdateSysStatus(long currentTime) { + if (sysStatusListener != null && (currentTime - lastSysStatusTime) >= sysStatusInterval ) { + try { + if (MsgList.get(MAVLINK_MSG_ID_SYS_STATUS) == null){ + return; + } + JSONObject data = new JSONObject(MsgList.get(MAVLINK_MSG_ID_SYS_STATUS)); + if (data != null) { + // 切换到主线程执行回调,避免在子线程中更新UI + mainHandler.post(() -> sysStatusListener.onSysStatusUpdate(data)); + } + lastSysStatusTime = currentTime; + } catch (Exception e) { + Log.e(TAG, "Error updating sys status data", e); + } + } + } + + private void checkAndUpdateStatusText(long currentTime) { + if (statusTextListener != null && (currentTime - lastStatusTextTime) >= statusTextInterval ) { + try { + if (MsgList.get(MAVLINK_MSG_ID_STATUSTEXT) == null){ + return; + } + JSONObject data = new JSONObject(MsgList.get(MAVLINK_MSG_ID_STATUSTEXT)); + if (data != null) { + // 切换到主线程执行回调,避免在子线程中更新UI + mainHandler.post(() -> statusTextListener.onStatusTextUpdate(data)); + } + lastStatusTextTime = currentTime; + } catch (Exception e) { + Log.e(TAG, "Error updating status text data", e); + } + } + } + + private void checkAndUpdateHeartbeat(long currentTime) { + if (heartbeatListener != null && (currentTime - lastHeartbeatTime) >= heartbeatInterval ) { + try { + if (MsgList.get(MAVLINK_MSG_ID_HEARTBEAT) == null){ + return; + } + JSONObject data = new JSONObject(MsgList.get(MAVLINK_MSG_ID_HEARTBEAT)); + if (data != null) { + // 切换到主线程执行回调,避免在子线程中更新UI + mainHandler.post(() -> heartbeatListener.onHeartbeatUpdate(data)); + } + lastHeartbeatTime = currentTime; + } catch (Exception e) { + Log.e(TAG, "Error updating heartbeat data", e); + } + } + } + + private void checkAndUpdateVfrHud(long currentTime) { + if (vfrHudListener != null && (currentTime - lastVfrHudTime) >= vfrHudInterval ) { + try { + if (MsgList.get(MAVLINK_MSG_ID_VFR_HUD) == null){ + return; + } + JSONObject data = new JSONObject(MsgList.get(MAVLINK_MSG_ID_VFR_HUD)); + if (data != null) { + // 切换到主线程执行回调,避免在子线程中更新UI + mainHandler.post(() -> vfrHudListener.onVfrHudUpdate(data)); + } + lastVfrHudTime = currentTime; + } catch (Exception e) { + Log.e(TAG, "Error updating VFR HUD data", e); + } + } + } + + private void checkAndUpdateMissionAck(long currentTime) { + if (missionAckListener != null && (currentTime - lastMissionAckTime) >= missionAckInterval ) { + try { + if (MsgList.get(MAVLINK_MSG_ID_MISSION_ACK) == null){ + return; + } + JSONObject data = new JSONObject(MsgList.get(MAVLINK_MSG_ID_MISSION_ACK)); + if (data != null) { + // 切换到主线程执行回调,避免在子线程中更新UI + mainHandler.post(() -> missionAckListener.onMissionAckUpdate(data)); + } + lastMissionAckTime = currentTime; + } catch (Exception e) { + Log.e(TAG, "Error updating mission ACK data", e); + } + } + } + + private void checkAndUpdateMissionCurrent(long currentTime) { + if (missionCurrentListener != null && (currentTime - lastMissionCurrentTime) >= missionCurrentInterval ) { + try { + if (MsgList.get(MAVLINK_MSG_ID_MISSION_CURRENT) == null){ + return; + } + JSONObject data = new JSONObject(MsgList.get(MAVLINK_MSG_ID_MISSION_CURRENT)); + if (data != null) { + // 切换到主线程执行回调,避免在子线程中更新UI + mainHandler.post(() -> missionCurrentListener.onMissionCurrentUpdate(data)); + } + lastMissionCurrentTime = currentTime; + } catch (Exception e) { + Log.e(TAG, "Error updating mission current data", e); + } + } + } +} diff --git a/app/src/main/java/com/example/longyi_groundstation/Main/Void/FlyVoid.java b/app/src/main/java/com/example/longyi_groundstation/Main/Void/Fly/FlyVoid.java similarity index 96% rename from app/src/main/java/com/example/longyi_groundstation/Main/Void/FlyVoid.java rename to app/src/main/java/com/example/longyi_groundstation/Main/Void/Fly/FlyVoid.java index c3ae162..dc3f707 100644 --- a/app/src/main/java/com/example/longyi_groundstation/Main/Void/FlyVoid.java +++ b/app/src/main/java/com/example/longyi_groundstation/Main/Void/Fly/FlyVoid.java @@ -1,14 +1,11 @@ -package com.example.longyi_groundstation.Main.Void; +package com.example.longyi_groundstation.Main.Void.Fly; -import static com.example.longyi_groundstation.MAVLink.common.msg_mission_ack.MAVLINK_MSG_ID_MISSION_ACK; import static com.example.longyi_groundstation.MAVLink.common.msg_mission_count.MAVLINK_MSG_ID_MISSION_COUNT; import static com.example.longyi_groundstation.MAVLink.common.msg_mission_item_int.MAVLINK_MSG_ID_MISSION_ITEM_INT; import static com.example.longyi_groundstation.MAVLink.common.msg_mission_request.MAVLINK_MSG_ID_MISSION_REQUEST; -import static com.example.longyi_groundstation.MAVLink.common.msg_mission_request_int.MAVLINK_MSG_ID_MISSION_REQUEST_INT; import static com.example.longyi_groundstation.MAVLink.enums.MAV_CMD.MAV_CMD_NAV_LAND; import static com.example.longyi_groundstation.MAVLink.enums.MAV_CMD.MAV_CMD_NAV_RETURN_TO_LAUNCH; import static com.example.longyi_groundstation.MAVLink.enums.MAV_CMD.MAV_CMD_NAV_TAKEOFF; -import static com.example.longyi_groundstation.Main.Activity.MainActivity.startExecuteDialog; import static com.example.longyi_groundstation.Main.Service.MyBoundService.MsgList; import static com.example.longyi_groundstation.Main.Service.MyBoundService.type; @@ -22,13 +19,10 @@ import android.widget.TextView; import android.widget.Toast; import com.amap.api.maps.model.LatLng; -import com.amap.api.services.auto.ListData; import com.example.longyi_groundstation.MAVLink.MAVLinkPacket; import com.example.longyi_groundstation.MAVLink.Messages.MAVLinkMessage; import com.example.longyi_groundstation.MAVLink.common.msg_command_long; -import com.example.longyi_groundstation.MAVLink.common.msg_mission_clear_all; import com.example.longyi_groundstation.MAVLink.common.msg_mission_count; -import com.example.longyi_groundstation.MAVLink.common.msg_mission_item; import com.example.longyi_groundstation.MAVLink.common.msg_mission_item_int; import com.example.longyi_groundstation.MAVLink.common.msg_mission_request_int; import com.example.longyi_groundstation.MAVLink.common.msg_mission_request_list; @@ -36,19 +30,19 @@ import com.example.longyi_groundstation.MAVLink.common.msg_param_request_read; import com.example.longyi_groundstation.MAVLink.common.msg_param_set; import com.example.longyi_groundstation.MAVLink.common.msg_set_position_target_global_int; import com.example.longyi_groundstation.MAVLink.enums.MAV_CMD; -import com.example.longyi_groundstation.MAVLink.enums.MAV_COMPONENT; import com.example.longyi_groundstation.MAVLink.enums.MAV_FRAME; import com.example.longyi_groundstation.MAVLink.enums.MAV_MISSION_TYPE; import com.example.longyi_groundstation.Main.Activity.MainActivity; import com.example.longyi_groundstation.Main.Base.CreateLink; import com.example.longyi_groundstation.Main.Service.MyBoundService; import com.example.longyi_groundstation.Main.Setting.Base.Param; -import com.example.longyi_groundstation.Main.Setting.Base.ParamGroup; +import com.example.longyi_groundstation.Main.Void.AllView; +import com.example.longyi_groundstation.Main.Void.Map.CoordinateConverter; +import com.example.longyi_groundstation.Main.Void.Tool.MyTool; +import com.example.longyi_groundstation.Main.Void.Tool.SerialTool; -import org.json.JSONException; import org.json.JSONObject; -import java.math.BigDecimal; import java.net.DatagramPacket; import java.net.InetAddress; import java.util.ArrayList; @@ -275,10 +269,14 @@ public class FlyVoid { } + /** + * 通用MAVLink消息发送方法-串口1 mavlink通道 + */ /** * 通用MAVLink消息发送方法-串口1 mavlink通道 */ public void sendMavlinkMessage(int type, MAVLinkMessage msg) { + msg.isMavlink2 = true; MAVLinkPacket packet = msg.pack(); if (type == 0) { // 串口 @@ -287,17 +285,25 @@ public class FlyVoid { MyBoundService.serialHelper.send(packet.encodePacket()); } } else { // UDP - try { - InetAddress targetAddress = InetAddress.getByName("127.0.0.1"); // 改为飞控IP - DatagramPacket udpPacket = new DatagramPacket(packet.encodePacket(), packet.encodePacket().length, targetAddress, 14553 // MAVLink标准端口 - ); - MyBoundService.serverSocket.send(udpPacket); - } catch (Exception e) { - Log.e("cuijinggzhou-发送", "发送失败: " + e.getMessage()); - } + // 将网络操作放到后台线程执行 + new Thread(() -> { + try { + InetAddress targetAddress = InetAddress.getByName("127.0.0.1"); // 改为飞控IP + DatagramPacket udpPacket = new DatagramPacket( + packet.encodePacket(), + packet.encodePacket().length, + targetAddress, + 14552 // MAVLink标准端口 + ); + MyBoundService.serverSocket.send(udpPacket); + } catch (Exception e) { + Log.e("cuijinggzhou-发送", "发送失败: " + e.getMessage()); + } + }).start(); } } + /** * 通用MAVLink消息发送方法-串口2 其它硬件通道 */ @@ -522,14 +528,14 @@ public class FlyVoid { speedChange.z = Float.parseFloat("10"); list1.add(speedChange); //第一个点特殊处理 - if ( i-1 == -1){ + if ( i-1 == -1 && link.getStop_time() > 0){ msg_mission_item_int command = new msg_mission_item_int(); command.target_system = 1; command.target_component = 1; command.seq = list1.size(); // 序号 command.frame = MAV_FRAME.MAV_FRAME_GLOBAL_RELATIVE_ALT; command.command = MAV_CMD.MAV_CMD_CONDITION_YAW; -// 设置偏航参数 + // 设置偏航参数 command.param1 = getYaw( MainActivity.homeLatLng.latitude, MainActivity.homeLatLng.longitude, @@ -548,7 +554,7 @@ public class FlyVoid { command.seq = list1.size(); // 序号 command.frame = MAV_FRAME.MAV_FRAME_GLOBAL_RELATIVE_ALT; command.command = MAV_CMD.MAV_CMD_CONDITION_YAW; -// 设置偏航参数 + // 设置偏航参数 command.param1 = getYaw( createLinkList.get(i-1).getLatLng().latitude, createLinkList.get(i-1).getLatLng().longitude, diff --git a/app/src/main/java/com/example/longyi_groundstation/Main/Void/LidarDataParser.java b/app/src/main/java/com/example/longyi_groundstation/Main/Void/Fly/LidarDataParser.java similarity index 98% rename from app/src/main/java/com/example/longyi_groundstation/Main/Void/LidarDataParser.java rename to app/src/main/java/com/example/longyi_groundstation/Main/Void/Fly/LidarDataParser.java index 7c44f09..c083dcc 100644 --- a/app/src/main/java/com/example/longyi_groundstation/Main/Void/LidarDataParser.java +++ b/app/src/main/java/com/example/longyi_groundstation/Main/Void/Fly/LidarDataParser.java @@ -1,8 +1,7 @@ -package com.example.longyi_groundstation.Main.Void; +package com.example.longyi_groundstation.Main.Void.Fly; import android.os.Handler; import android.os.Looper; -import android.util.Log; import android.widget.TextView; /** diff --git a/app/src/main/java/com/example/longyi_groundstation/Main/Void/MavlinkErrorTranslator.java b/app/src/main/java/com/example/longyi_groundstation/Main/Void/Fly/MavlinkErrorTranslator.java similarity index 99% rename from app/src/main/java/com/example/longyi_groundstation/Main/Void/MavlinkErrorTranslator.java rename to app/src/main/java/com/example/longyi_groundstation/Main/Void/Fly/MavlinkErrorTranslator.java index 43d04e9..59ad01b 100644 --- a/app/src/main/java/com/example/longyi_groundstation/Main/Void/MavlinkErrorTranslator.java +++ b/app/src/main/java/com/example/longyi_groundstation/Main/Void/Fly/MavlinkErrorTranslator.java @@ -1,4 +1,4 @@ -package com.example.longyi_groundstation.Main.Void; +package com.example.longyi_groundstation.Main.Void.Fly; import com.example.longyi_groundstation.MAVLink.enums.MAV_SEVERITY; import java.util.HashMap; diff --git a/app/src/main/java/com/example/longyi_groundstation/Main/Void/HeartbeatManager.java b/app/src/main/java/com/example/longyi_groundstation/Main/Void/HeartbeatManager.java deleted file mode 100644 index e459632..0000000 --- a/app/src/main/java/com/example/longyi_groundstation/Main/Void/HeartbeatManager.java +++ /dev/null @@ -1,140 +0,0 @@ -// 新建文件 HeartbeatManager.java -package com.example.longyi_groundstation.Main.Void; - -import android.os.Handler; -import android.os.Looper; -import android.util.Log; - -import com.example.longyi_groundstation.MAVLink.MAVLinkPacket; -import com.example.longyi_groundstation.MAVLink.minimal.msg_heartbeat; - -import java.net.DatagramPacket; -import java.net.InetAddress; - -import tp.xmaihh.serialport.SerialHelper; - -/** - * 心跳管理器类,用于管理与飞控的心跳通信 - */ -public class HeartbeatManager { - private static final String TAG = "HeartbeatManager"; - private static final long HEARTBEAT_INTERVAL = 1000; // 心跳间隔1秒 - - private Handler heartbeatHandler; - private Runnable heartbeatRunnable; - private boolean isHeartbeatRunning = false; - private int connectionType; // 0: 串口, 1: UDP - private SerialHelper serialHelper; - private java.net.DatagramSocket serverSocket; - - public HeartbeatManager(int type, SerialHelper serialHelper, java.net.DatagramSocket serverSocket) { - this.connectionType = type; - this.serialHelper = serialHelper; - this.serverSocket = serverSocket; - this.heartbeatHandler = new Handler(Looper.getMainLooper()); - } - - /** - * 方法:启动心跳包发送 - */ - public void startHeartbeat() { - if (!isHeartbeatRunning) { - isHeartbeatRunning = true; - heartbeatRunnable = new Runnable() { - @Override - public void run() { - if (isHeartbeatRunning) { - sendHeartbeat(); - heartbeatHandler.postDelayed(this, HEARTBEAT_INTERVAL); - } - } - }; - heartbeatHandler.post(heartbeatRunnable); - } - } - - /** - * 方法:停止心跳包发送 - */ - public void stopHeartbeat() { - isHeartbeatRunning = false; - if (heartbeatHandler != null && heartbeatRunnable != null) { - heartbeatHandler.removeCallbacks(heartbeatRunnable); - } - } - - /** - * 方法:发送心跳包到飞控 - */ - private void sendHeartbeat() { - try { - // 创建心跳消息 - msg_heartbeat heartbeat = new msg_heartbeat(); - - // 设置心跳参数 - heartbeat.type = 6; // GCS类型 - heartbeat.autopilot = 8; // MAV_AUTOPILOT_INVALID - heartbeat.base_mode = 0; - heartbeat.custom_mode = 0; - heartbeat.system_status = 0; // MAV_STATE_UNINIT - - // 编码为MAVLinkPacket - MAVLinkPacket packet = heartbeat.pack(); - - // 发送数据(根据连接方式选择) - if (connectionType == 0) { - // 串口发送 - if (serialHelper != null) { - serialHelper.send(packet.encodePacket()); - } - } else { - // UDP发送 - try { - if (serverSocket != null && !serverSocket.isClosed()) { - InetAddress targetAddress = InetAddress.getByName("127.0.0.1"); - int targetPort = 14553; // 默认MAVLink端口 - DatagramPacket udpPacket = new DatagramPacket( - packet.encodePacket(), - packet.encodePacket().length, - targetAddress, - targetPort - ); - serverSocket.send(udpPacket); - } - } catch (Exception e) { - Log.e(TAG, "发送心跳包失败: " + e.getMessage()); - } - } - } catch (Exception e) { - Log.e(TAG, "构建心跳包失败: " + e.getMessage()); - } - } - - /** - * 方法:设置连接类型 - */ - public void setConnectionType(int type) { - this.connectionType = type; - } - - /** - * 方法:设置串口助手 - */ - public void setSerialHelper(SerialHelper serialHelper) { - this.serialHelper = serialHelper; - } - - /** - * 方法:设置UDP套接字 - */ - public void setServerSocket(java.net.DatagramSocket serverSocket) { - this.serverSocket = serverSocket; - } - - /** - * 方法:检查心跳是否正在运行 - */ - public boolean isRunning() { - return isHeartbeatRunning; - } -} diff --git a/app/src/main/java/com/example/longyi_groundstation/Main/Void/CoordinateConverter.java b/app/src/main/java/com/example/longyi_groundstation/Main/Void/Map/CoordinateConverter.java similarity index 98% rename from app/src/main/java/com/example/longyi_groundstation/Main/Void/CoordinateConverter.java rename to app/src/main/java/com/example/longyi_groundstation/Main/Void/Map/CoordinateConverter.java index 93e789d..8c9f875 100644 --- a/app/src/main/java/com/example/longyi_groundstation/Main/Void/CoordinateConverter.java +++ b/app/src/main/java/com/example/longyi_groundstation/Main/Void/Map/CoordinateConverter.java @@ -1,4 +1,4 @@ -package com.example.longyi_groundstation.Main.Void; +package com.example.longyi_groundstation.Main.Void.Map; /** diff --git a/app/src/main/java/com/example/longyi_groundstation/Main/Void/MapVoid.java b/app/src/main/java/com/example/longyi_groundstation/Main/Void/Map/MapVoid.java similarity index 90% rename from app/src/main/java/com/example/longyi_groundstation/Main/Void/MapVoid.java rename to app/src/main/java/com/example/longyi_groundstation/Main/Void/Map/MapVoid.java index d1a237e..c18280b 100644 --- a/app/src/main/java/com/example/longyi_groundstation/Main/Void/MapVoid.java +++ b/app/src/main/java/com/example/longyi_groundstation/Main/Void/Map/MapVoid.java @@ -1,33 +1,26 @@ -package com.example.longyi_groundstation.Main.Void; +package com.example.longyi_groundstation.Main.Void.Map; + +import static com.example.longyi_groundstation.Main.Activity.MainActivity.doubles; import android.app.Activity; -import android.graphics.Bitmap; -import android.graphics.Canvas; import android.graphics.Color; -import android.graphics.Paint; -import android.graphics.Rect; import android.location.Location; import android.os.Bundle; import android.os.Handler; import android.os.Looper; import android.util.Log; -import android.view.View; -import android.widget.TextView; import com.amap.api.maps.AMap; import com.amap.api.maps.AMapUtils; -import com.amap.api.maps.MapView; import com.amap.api.maps.MapsInitializer; -import com.amap.api.maps.model.BitmapDescriptorFactory; import com.amap.api.maps.model.LatLng; import com.amap.api.maps.model.Marker; -import com.amap.api.maps.model.MarkerOptions; import com.amap.api.maps.model.MyLocationStyle; import com.amap.api.maps.model.Polyline; import com.amap.api.maps.model.PolylineOptions; -import com.example.longyi_groundstation.MAVLink.Messages.MAVLinkPayload; -import com.example.longyi_groundstation.Main.Activity.MainActivity; -import com.example.longyi_groundstation.R; +import com.example.longyi_groundstation.Main.Service.MyBoundService; +import com.example.longyi_groundstation.Main.Void.AllView; +import com.example.longyi_groundstation.Main.Void.MyReceiver; import java.util.ArrayList; import java.util.List; @@ -42,11 +35,8 @@ public class MapVoid { private Bundle savedInstanceState; //初始化地图控制器对象 public AMap aMap = null; - //初始化地图控制器对象 //画线 - - //画线 - public List latLngss; + public List latLngss = new ArrayList<>(); public List waypointMarkers = new ArrayList<>(); public List waypointPositions = new ArrayList<>(); @@ -141,8 +131,12 @@ public class MapVoid { try { if (isTracking) { // 获取当前飞机位置 - double lat = MyReceiver.GLOBAL_POSITION_INT_json.optDouble("lat", 0) / 10000000; - double lon = MyReceiver.GLOBAL_POSITION_INT_json.optDouble("lon", 0) / 10000000; + if (doubles == null){ + // 2秒后再次执行 + flightTrackHandler.postDelayed(this, 600); + } + double lat = doubles[1]; + double lon = doubles[0]; // 检查坐标有效性 if (lat != 0 && lon != 0) { @@ -158,13 +152,13 @@ public class MapVoid { updateFlightTrack(); } } - // 0.3秒后再次执行 + // 0.6秒后再次执行 flightTrackHandler.postDelayed(this, 600); } } catch (Exception e) { // e.printStackTrace(); Log.d("cui_error", "error: "+e); - // 2秒后再次执行 + // 0.6秒后再次执行 flightTrackHandler.postDelayed(this, 600); } diff --git a/app/src/main/java/com/example/longyi_groundstation/Main/Void/Mqtt/MqttV5Util.java b/app/src/main/java/com/example/longyi_groundstation/Main/Void/Mqtt/MqttV5Util.java new file mode 100644 index 0000000..3dd2835 --- /dev/null +++ b/app/src/main/java/com/example/longyi_groundstation/Main/Void/Mqtt/MqttV5Util.java @@ -0,0 +1,195 @@ +package com.example.longyi_groundstation.Main.Void.Mqtt; + +import org.eclipse.paho.mqttv5.client.IMqttToken; +import org.eclipse.paho.mqttv5.client.MqttClient; +import org.eclipse.paho.mqttv5.client.MqttConnectionOptions; +import org.eclipse.paho.mqttv5.client.MqttDisconnectResponse; +import org.eclipse.paho.mqttv5.client.persist.MemoryPersistence; +import org.eclipse.paho.mqttv5.common.MqttException; +import org.eclipse.paho.mqttv5.common.MqttMessage; +import org.eclipse.paho.mqttv5.common.packet.MqttProperties; +import org.eclipse.paho.mqttv5.client.MqttCallback; + +import android.util.Log; + +import com.example.longyi_groundstation.Main.Void.Tool.MyTool; + +/** + * MQTT v5 工具类 + */ +public class MqttV5Util { + private static final String TAG = "MqttV5Util"; + private MqttClient client; + private String brokerUrl; + private String clientId; + + public MqttV5Util(String brokerUrl, String clientId) { + this.brokerUrl = brokerUrl; + this.clientId = clientId; + } + + /** + * 连接MQTT v5服务器 + * @param username 用户名 + * @param password 密码 + * @return 是否连接成功 + */ + public boolean connect(String username, String password) { + try { + // 使用内存持久化避免文件权限问题 + client = new MqttClient(brokerUrl, clientId, new MemoryPersistence()); + + // 设置连接参数 + MqttConnectionOptions options = new MqttConnectionOptions(); + options.setCleanStart(true); + options.setConnectionTimeout(30); + options.setKeepAliveInterval(60); + options.setAutomaticReconnect(true); + // 只有当用户名和密码非空时才设置 + if (username != null && !username.isEmpty()) { + options.setUserName(username); + } + if (password != null && !password.isEmpty()) { + options.setPassword(password.getBytes()); + } + + // 设置回调 + client.setCallback(new MqttCallback() { + @Override + public void disconnected(MqttDisconnectResponse disconnectResponse) { + Log.d(TAG, "MQTT v5连接已断开: " + disconnectResponse.getReasonString()); + + } + + @Override + public void mqttErrorOccurred(MqttException exception) { + Log.e(TAG, "MQTT v5错误发生: " + exception.getMessage(), exception); + } + + @Override + public void messageArrived(String topic, MqttMessage message) throws Exception { + + Log.d(TAG, "收到消息 - Topic: " + topic + ", Message: " + MyTool.bytesToHex(message.getPayload(),message.getPayload().length)); + } + + @Override + public void deliveryComplete(IMqttToken token) { + Log.d(TAG, "消息发送完成"); + } + + @Override + public void connectComplete(boolean reconnect, String serverURI) { + Log.d(TAG, "MQTT v5连接完成 - Reconnect: " + reconnect + ", ServerURI: " + serverURI); + subscribe("/ee", 1); + + } + + @Override + public void authPacketArrived(int reasonCode, MqttProperties properties) { + Log.d(TAG, "认证包到达 - ReasonCode: " + reasonCode); + } + }); + + // 连接服务器 + Log.d(TAG, "尝试连接到MQTT服务器: " + brokerUrl); + client.connect(options); + Log.d(TAG, "MQTT v5连接成功"); + return true; + + } catch (MqttException e) { + Log.e(TAG, "MQTT v5连接失败: " + e.getMessage() + " - 错误码: " + e.getReasonCode(), e); + return false; + } catch (Exception e) { + Log.e(TAG, "MQTT v5连接发生未知错误: " + e.getMessage(), e); + return false; + } + } + + /** + * 断开MQTT v5连接 + */ + public void disconnect() { + try { + if (client != null && client.isConnected()) { + client.disconnect(); + Log.d(TAG, "MQTT v5连接已断开"); + } + } catch (MqttException e) { + Log.e(TAG, "断开MQTT v5连接时出错: " + e.getMessage(), e); + } + } + + /** + * 发布消息 + * @param topic 主题 + * @param message 消息内容 + * @param qos 服务质量等级 + * @return 是否发布成功 + */ + public boolean publish(String topic, byte[] message, int qos) { + try { + if (client != null && client.isConnected()) { + MqttMessage mqttMessage = new MqttMessage(message); + mqttMessage.setQos(qos); + client.publish(topic, mqttMessage); + return true; + } + } catch (MqttException e) { + Log.e(TAG, "发布消息失败: " + e.getMessage(), e); + } + return false; + } + + /** + * 订阅主题 + * @param topic 主题 + * @param qos 服务质量等级 + * @return 是否订阅成功 + */ + public boolean subscribe(String topic, int qos) { + try { + if (client != null && client.isConnected()) { + client.subscribe(topic, qos); + Log.d(TAG, "订阅主题成功: " + topic); + return true; + } + } catch (MqttException e) { + Log.e(TAG, "订阅主题失败: " + e.getMessage(), e); + } + return false; + } + + /** + * 取消订阅主题 + * @param topic 主题 + * @return 是否取消订阅成功 + */ + public boolean unsubscribe(String topic) { + try { + if (client != null && client.isConnected()) { + client.unsubscribe(topic); + Log.d(TAG, "取消订阅主题成功: " + topic); + return true; + } + } catch (MqttException e) { + Log.e(TAG, "取消订阅主题失败: " + e.getMessage(), e); + } + return false; + } + + /** + * 检查是否已连接 + * @return 是否已连接 + */ + public boolean isConnected() { + return client != null && client.isConnected(); + } + + /** + * 获取客户端实例 + * @return MqttClient实例 + */ + public MqttClient getClient() { + return client; + } +} diff --git a/app/src/main/java/com/example/longyi_groundstation/Main/Void/Mqtt/SerialProtocolV2Packer.java b/app/src/main/java/com/example/longyi_groundstation/Main/Void/Mqtt/SerialProtocolV2Packer.java new file mode 100644 index 0000000..cb3e200 --- /dev/null +++ b/app/src/main/java/com/example/longyi_groundstation/Main/Void/Mqtt/SerialProtocolV2Packer.java @@ -0,0 +1,315 @@ +package com.example.longyi_groundstation.Main.Void.Mqtt; + +import java.nio.ByteBuffer; +import java.nio.ByteOrder; + +/** + * 串口协议V2消息打包工具(根据新的字段定义) + * 帧格式:帧头(2) + 源地址(1) + 目的地址(1) + 功能码(1) + 序号(1) + 长度(1) + 负载(N) + CRC16(2) + * 负载长度固定为33字节。 + */ +public class SerialProtocolV2Packer { + + private static final byte STX1 = (byte) 0xFE; + private static final byte STX2 = (byte) 0xEF; + private static final int PAYLOAD_LENGTH = 33; + + public static class FrameInfo { + private byte srcAddr; + private byte dstAddr; + private byte functionCode; + private byte sequence; + private byte length; + private MessagePayload payload; + private boolean crcValid; + + public byte getSrcAddr() { return srcAddr; } + public byte getDstAddr() { return dstAddr; } + public byte getFunctionCode() { return functionCode; } + public byte getSequence() { return sequence; } + public byte getLength() { return length; } + public MessagePayload getPayload() { return payload; } + public boolean isCrcValid() { return crcValid; } + + void setSrcAddr(byte srcAddr) { this.srcAddr = srcAddr; } + void setDstAddr(byte dstAddr) { this.dstAddr = dstAddr; } + void setFunctionCode(byte functionCode) { this.functionCode = functionCode; } + void setSequence(byte sequence) { this.sequence = sequence; } + void setLength(byte length) { this.length = length; } + void setPayload(MessagePayload payload) { this.payload = payload; } + void setCrcValid(boolean crcValid) { this.crcValid = crcValid; } + } + + /** + * 新协议负载 + */ + public static class MessagePayload { + private int longitude; // int32_t, *1e7 + private int latitude; // int32_t, *1e7 + private int altitude; // int32_t, *1e3 + private short speed; // int16_t, *1e2 + private int satelliteCount; // uint8_t + private int voltage; // uint16_t, *1e2 + private int reserved; // uint16_t + private short roll; // int16_t, *1e2 + private short pitch; // int16_t, *1e2 + private short yaw; // int16_t, *1e2 + private int unlockStatus; // uint8_t + private int rtkHeadingStatus; // uint8_t + private int flightMode; // uint8_t + private long flightTime; // uint32_t, 秒 + private int throttle; // uint8_t 0-100 + + public int getLongitude() { return longitude; } + public void setLongitude(int longitude) { this.longitude = longitude; } + + public int getLatitude() { return latitude; } + public void setLatitude(int latitude) { this.latitude = latitude; } + + public int getAltitude() { return altitude; } + public void setAltitude(int altitude) { this.altitude = altitude; } + + public short getSpeed() { return speed; } + public void setSpeed(short speed) { this.speed = speed; } + + public int getSatelliteCount() { return satelliteCount; } + public void setSatelliteCount(int satelliteCount) { + this.satelliteCount = satelliteCount & 0xFF; + } + + public int getVoltage() { return voltage; } + public void setVoltage(int voltage) { this.voltage = voltage & 0xFFFF; } + + public int getReserved() { return reserved; } + public void setReserved(int reserved) { this.reserved = reserved & 0xFFFF; } + + public short getRoll() { return roll; } + public void setRoll(short roll) { this.roll = roll; } + + public short getPitch() { return pitch; } + public void setPitch(short pitch) { this.pitch = pitch; } + + public short getYaw() { return yaw; } + public void setYaw(short yaw) { this.yaw = yaw; } + + public int getUnlockStatus() { return unlockStatus; } + public void setUnlockStatus(int unlockStatus) { + this.unlockStatus = unlockStatus & 0xFF; + } + + public int getRtkHeadingStatus() { return rtkHeadingStatus; } + public void setRtkHeadingStatus(int rtkHeadingStatus) { + this.rtkHeadingStatus = rtkHeadingStatus & 0xFF; + } + + public int getFlightMode() { return flightMode; } + public void setFlightMode(int flightMode) { + this.flightMode = flightMode & 0xFF; + } + + public long getFlightTime() { return flightTime; } + public void setFlightTime(long flightTime) { + this.flightTime = flightTime & 0xFFFFFFFFL; + } + + public int getThrottle() { return throttle; } + public void setThrottle(int throttle) { + this.throttle = throttle & 0xFF; + } + + @Override + public String toString() { + return String.format( + "MessagePayload{lon=%d, lat=%d, alt=%d, speed=%d, sat=%d, volt=%d, reserved=%d, " + + "roll=%d, pitch=%d, yaw=%d, unlock=%d, rtkHeading=%d, flightMode=%d, " + + "flightTime=%d, throttle=%d}", + longitude, latitude, altitude, speed, satelliteCount, voltage, reserved, + roll, pitch, yaw, unlockStatus, rtkHeadingStatus, flightMode, flightTime, throttle + ); + } + } + + public static int crc16Xmodem(byte[] data, int offset, int length) { + int crc = 0x0000; + int polynomial = 0x1021; + for (int i = offset; i < offset + length; i++) { + crc ^= (data[i] & 0xFF) << 8; + for (int j = 0; j < 8; j++) { + if ((crc & 0x8000) != 0) { + crc = (crc << 1) ^ polynomial; + } else { + crc <<= 1; + } + crc &= 0xFFFF; + } + } + return crc; + } + + private static byte[] packPayload(MessagePayload payload) { + ByteBuffer buffer = ByteBuffer.allocate(PAYLOAD_LENGTH); + buffer.order(ByteOrder.LITTLE_ENDIAN); + + buffer.putInt(payload.getLongitude()); // +0 + buffer.putInt(payload.getLatitude()); // +4 + buffer.putInt(payload.getAltitude()); // +8 + buffer.putShort(payload.getSpeed()); // +12 + buffer.put((byte) (payload.getSatelliteCount() & 0xFF)); // +14 + buffer.putShort((short) (payload.getVoltage() & 0xFFFF)); // +15 + buffer.putShort((short) (payload.getReserved() & 0xFFFF)); // +17 + buffer.putShort(payload.getRoll()); // +19 + buffer.putShort(payload.getPitch()); // +21 + buffer.putShort(payload.getYaw()); // +23 + buffer.put((byte) (payload.getUnlockStatus() & 0xFF)); // +25 + buffer.put((byte) (payload.getRtkHeadingStatus() & 0xFF)); // +26 + buffer.put((byte) (payload.getFlightMode() & 0xFF)); // +27 + buffer.putInt((int) (payload.getFlightTime() & 0xFFFFFFFFL)); // +28 + buffer.put((byte) (payload.getThrottle() & 0xFF)); // +32 + + return buffer.array(); + } + + private static MessagePayload unpackPayload(byte[] data, int offset) { + if (data.length < offset + PAYLOAD_LENGTH) { + throw new IllegalArgumentException("数据长度不足,无法解析V2负载"); + } + + ByteBuffer buffer = ByteBuffer.wrap(data, offset, PAYLOAD_LENGTH); + buffer.order(ByteOrder.LITTLE_ENDIAN); + + MessagePayload payload = new MessagePayload(); + payload.setLongitude(buffer.getInt()); + payload.setLatitude(buffer.getInt()); + payload.setAltitude(buffer.getInt()); + payload.setSpeed(buffer.getShort()); + payload.setSatelliteCount(buffer.get() & 0xFF); + payload.setVoltage(buffer.getShort() & 0xFFFF); + payload.setReserved(buffer.getShort() & 0xFFFF); + payload.setRoll(buffer.getShort()); + payload.setPitch(buffer.getShort()); + payload.setYaw(buffer.getShort()); + payload.setUnlockStatus(buffer.get() & 0xFF); + payload.setRtkHeadingStatus(buffer.get() & 0xFF); + payload.setFlightMode(buffer.get() & 0xFF); + payload.setFlightTime(buffer.getInt() & 0xFFFFFFFFL); + payload.setThrottle(buffer.get() & 0xFF); + return payload; + } + + public static byte[] packFrame(byte srcAddr, byte dstAddr, byte functionCode, + byte sequence, MessagePayload payload) { + byte[] payloadBytes = packPayload(payload); + int frameLength = 2 + 1 + 1 + 1 + 1 + 1 + payloadBytes.length + 2; + ByteBuffer frame = ByteBuffer.allocate(frameLength); + frame.order(ByteOrder.LITTLE_ENDIAN); + + frame.put(STX1); + frame.put(STX2); + frame.put(srcAddr); + frame.put(dstAddr); + frame.put(functionCode); + frame.put(sequence); + frame.put((byte) payloadBytes.length); + frame.put(payloadBytes); + + byte[] frameData = frame.array(); + int crcStartOffset = 0; + int crcLength = frameLength - 2; + int crc16 = crc16Xmodem(frameData, crcStartOffset, crcLength); + frame.put((byte) (crc16 & 0xFF)); + frame.put((byte) ((crc16 >> 8) & 0xFF)); + return frame.array(); + } + + public static FrameInfo unpackFrame(byte[] frameData) { + if (frameData == null || frameData.length < 9) { + throw new IllegalArgumentException("帧数据长度不足,最小长度为9字节"); + } + + if (frameData[0] != STX1 || frameData[1] != STX2) { + throw new IllegalArgumentException("帧头错误,无法解析V2帧"); + } + + FrameInfo frameInfo = new FrameInfo(); + frameInfo.setSrcAddr(frameData[2]); + frameInfo.setDstAddr(frameData[3]); + frameInfo.setFunctionCode(frameData[4]); + frameInfo.setSequence(frameData[5]); + frameInfo.setLength(frameData[6]); + + int payloadLength = frameInfo.getLength() & 0xFF; + int expectedFrameLength = 2 + 1 + 1 + 1 + 1 + 1 + payloadLength + 2; + if (frameData.length < expectedFrameLength) { + throw new IllegalArgumentException("帧数据长度不足,无法解析完整V2帧"); + } + + int crcStartOffset = 0; + int crcLength = expectedFrameLength - 2; + int calculatedCrc = crc16Xmodem(frameData, crcStartOffset, crcLength); + int frameCrc = (frameData[expectedFrameLength - 2] & 0xFF) | + ((frameData[expectedFrameLength - 1] & 0xFF) << 8); + frameInfo.setCrcValid(calculatedCrc == frameCrc); + + int payloadOffset = 7; + MessagePayload payload = unpackPayload(frameData, payloadOffset); + frameInfo.setPayload(payload); + return frameInfo; + } + + public static FrameInfo findAndUnpackFrame(byte[] data, int offset) { + if (data == null || data.length < offset + 9) { + return null; + } + + for (int i = offset; i <= data.length - 9; i++) { + if (data[i] == STX1 && data[i + 1] == STX2) { + try { + int payloadLength = data[i + 6] & 0xFF; + int frameLength = 2 + 1 + 1 + 1 + 1 + 1 + payloadLength + 2; + if (i + frameLength <= data.length) { + byte[] frameData = new byte[frameLength]; + System.arraycopy(data, i, frameData, 0, frameLength); + return unpackFrame(frameData); + } + } catch (IllegalArgumentException ignored) { + // continue searching next frame head + } + } + } + return null; + } + + public static byte[] getBytes(String[] args) { + MessagePayload payload = new MessagePayload(); + payload.setLongitude(1163974210); + payload.setLatitude(399062310); + payload.setAltitude(123450); // 123.450 m => *1e3 + payload.setSpeed((short) 250); // 2.50 m/s => *1e2 + payload.setSatelliteCount(15); + payload.setVoltage(3780); // 37.80 V => *1e2 + payload.setReserved(0); + payload.setRoll((short) -500); // -5.00 deg => *1e2 + payload.setPitch((short) 300); // 3.00 deg + payload.setYaw((short) -1700); // -17.00 deg + payload.setUnlockStatus(1); + payload.setRtkHeadingStatus(255); + payload.setFlightMode(255); + payload.setFlightTime(3600); // 1 hour + payload.setThrottle(80); // 80% + + byte[] frame = packFrame((byte) 0x01, (byte) 0x02, (byte) 0x20, (byte) 0x11, payload); + return frame; +// System.out.println("=== V2 Frame ==="); +// System.out.println("Length: " + frame.length + " bytes"); +// StringBuilder sb = new StringBuilder(); +// for (byte b : frame) { +// sb.append(String.format("%02X ", b & 0xFF)); +// } +// System.out.println(sb.toString()); +// +// FrameInfo frameInfo = unpackFrame(frame); +// System.out.println("CRC valid: " + frameInfo.isCrcValid()); +// System.out.println("Payload: " + frameInfo.getPayload()); + } +} + diff --git a/app/src/main/java/com/example/longyi_groundstation/Main/Void/SQLClass.java b/app/src/main/java/com/example/longyi_groundstation/Main/Void/Sql/SQLClass.java similarity index 99% rename from app/src/main/java/com/example/longyi_groundstation/Main/Void/SQLClass.java rename to app/src/main/java/com/example/longyi_groundstation/Main/Void/Sql/SQLClass.java index 769728b..cd998b1 100644 --- a/app/src/main/java/com/example/longyi_groundstation/Main/Void/SQLClass.java +++ b/app/src/main/java/com/example/longyi_groundstation/Main/Void/Sql/SQLClass.java @@ -1,4 +1,4 @@ -package com.example.longyi_groundstation.Main.Void; +package com.example.longyi_groundstation.Main.Void.Sql; import android.content.ContentValues; import android.content.Context; diff --git a/app/src/main/java/com/example/longyi_groundstation/Main/Void/MyTool.java b/app/src/main/java/com/example/longyi_groundstation/Main/Void/Tool/MyTool.java similarity index 98% rename from app/src/main/java/com/example/longyi_groundstation/Main/Void/MyTool.java rename to app/src/main/java/com/example/longyi_groundstation/Main/Void/Tool/MyTool.java index 5f78f0f..3a2e77f 100644 --- a/app/src/main/java/com/example/longyi_groundstation/Main/Void/MyTool.java +++ b/app/src/main/java/com/example/longyi_groundstation/Main/Void/Tool/MyTool.java @@ -1,4 +1,4 @@ -package com.example.longyi_groundstation.Main.Void; +package com.example.longyi_groundstation.Main.Void.Tool; import android.app.Activity; import android.content.Context; @@ -50,6 +50,8 @@ public class MyTool { } + + // 添加以下成员变量 public long lastClickTime = 0; public int clickCount = 0; diff --git a/app/src/main/java/com/example/longyi_groundstation/Main/Void/SerialTool.java b/app/src/main/java/com/example/longyi_groundstation/Main/Void/Tool/SerialTool.java similarity index 98% rename from app/src/main/java/com/example/longyi_groundstation/Main/Void/SerialTool.java rename to app/src/main/java/com/example/longyi_groundstation/Main/Void/Tool/SerialTool.java index e8fea2f..1a40ba6 100644 --- a/app/src/main/java/com/example/longyi_groundstation/Main/Void/SerialTool.java +++ b/app/src/main/java/com/example/longyi_groundstation/Main/Void/Tool/SerialTool.java @@ -1,4 +1,4 @@ -package com.example.longyi_groundstation.Main.Void; +package com.example.longyi_groundstation.Main.Void.Tool; public class SerialTool { diff --git a/app/src/main/java/com/example/longyi_groundstation/Main/Void/FpvGestureHandler.java b/app/src/main/java/com/example/longyi_groundstation/Main/Void/XiangTuo/FpvGestureHandler.java similarity index 97% rename from app/src/main/java/com/example/longyi_groundstation/Main/Void/FpvGestureHandler.java rename to app/src/main/java/com/example/longyi_groundstation/Main/Void/XiangTuo/FpvGestureHandler.java index dc51e53..98b0c80 100644 --- a/app/src/main/java/com/example/longyi_groundstation/Main/Void/FpvGestureHandler.java +++ b/app/src/main/java/com/example/longyi_groundstation/Main/Void/XiangTuo/FpvGestureHandler.java @@ -1,12 +1,10 @@ -package com.example.longyi_groundstation.Main.Void; +package com.example.longyi_groundstation.Main.Void.XiangTuo; import android.view.GestureDetector; import android.view.MotionEvent; import android.view.ScaleGestureDetector; import android.view.View; -import com.example.longyi_groundstation.R; - public class FpvGestureHandler implements View.OnTouchListener { private GestureDetector gestureDetector; private ScaleGestureDetector scaleGestureDetector; diff --git a/app/src/main/java/com/example/longyi_groundstation/Util/Http/HttpUrl.java b/app/src/main/java/com/example/longyi_groundstation/Util/Http/HttpUrl.java index 5cad2a8..b906c02 100644 --- a/app/src/main/java/com/example/longyi_groundstation/Util/Http/HttpUrl.java +++ b/app/src/main/java/com/example/longyi_groundstation/Util/Http/HttpUrl.java @@ -2,7 +2,13 @@ package com.example.longyi_groundstation.Util.Http; public class HttpUrl { - public static final String BASE_URL = "https://api.longyi-uav-cloud.com"; +// public static final String BASE_URL = "https://api.longyi-uav-cloud.com"; + public static final String BASE_URL = "http://192.168.101.102:48080"; + //登录 public static final String LOGIN = BASE_URL + "/admin-api/system/auth/login"; + //刷新token + public static final String REFRESH_TOKEN = BASE_URL + " /admin-api/system/auth/refresh-token"; + //创建飞机 + public static final String CREATE_FOR_ANDROID = BASE_URL + "/admin-api/uav/base/createForAndroid"; } diff --git a/app/src/main/java/com/example/longyi_groundstation/Util/Http/HttpUtil.java b/app/src/main/java/com/example/longyi_groundstation/Util/Http/HttpUtil.java index 060f2be..6631025 100644 --- a/app/src/main/java/com/example/longyi_groundstation/Util/Http/HttpUtil.java +++ b/app/src/main/java/com/example/longyi_groundstation/Util/Http/HttpUtil.java @@ -1,5 +1,7 @@ package com.example.longyi_groundstation.Util.Http; +import android.content.Context; + import java.io.IOException; import java.util.Map; import java.util.concurrent.TimeUnit; @@ -17,10 +19,10 @@ import okhttp3.Response; public class HttpUtil { private static final MediaType MEDIA_TYPE_JSON = MediaType.parse("application/json; charset=utf-8"); private static final MediaType MEDIA_TYPE_FORM = MediaType.parse("application/x-www-form-urlencoded"); - + private OkHttpClient client; - - public HttpUtil() { + + public HttpUtil(Context context) { this.client = new OkHttpClient.Builder() .connectTimeout(10, TimeUnit.SECONDS) .readTimeout(30, TimeUnit.SECONDS) @@ -28,7 +30,7 @@ public class HttpUtil { .retryOnConnectionFailure(true) .build(); } - + /** * GET请求 * @param url 请求地址 @@ -37,14 +39,14 @@ public class HttpUtil { */ public void get(String url, Map headers, Callback callback) { Request.Builder builder = new Request.Builder().url(url); - + // 添加请求头 addHeaders(builder, headers); - + Request request = builder.get().build(); client.newCall(request).enqueue(callback); } - + /** * POST请求 - JSON格式 * @param url 请求地址 @@ -57,13 +59,13 @@ public class HttpUtil { Request.Builder builder = new Request.Builder() .url(url) .post(body); - + addHeaders(builder, headers); - + Request request = builder.build(); client.newCall(request).enqueue(callback); } - + /** * POST请求 - 表单格式 * @param url 请求地址 @@ -76,13 +78,13 @@ public class HttpUtil { Request.Builder builder = new Request.Builder() .url(url) .post(body); - + addHeaders(builder, headers); - + Request request = builder.build(); client.newCall(request).enqueue(callback); } - + /** * 同步GET请求 * @param url 请求地址 @@ -93,11 +95,11 @@ public class HttpUtil { public Response executeGet(String url, Map headers) throws IOException { Request.Builder builder = new Request.Builder().url(url); addHeaders(builder, headers); - + Request request = builder.get().build(); return client.newCall(request).execute(); } - + /** * 同步POST请求 - JSON格式 * @param url 请求地址 @@ -110,11 +112,28 @@ public class HttpUtil { RequestBody body = RequestBody.create(json, MEDIA_TYPE_JSON); Request.Builder builder = new Request.Builder().url(url).post(body); addHeaders(builder, headers); - + Request request = builder.build(); return client.newCall(request).execute(); } - + + /** + * 同步POST请求 - 表单格式 + * @param url 请求地址 + * @param formData 表单数据 + * @param headers 请求头 + * @return Response响应对象 + * @throws IOException IO异常 + */ + public Response executePostForm(String url, String formData, Map headers) throws IOException { + RequestBody body = RequestBody.create(formData, MEDIA_TYPE_FORM); + Request.Builder builder = new Request.Builder().url(url).post(body); + addHeaders(builder, headers); + + Request request = builder.build(); + return client.newCall(request).execute(); + } + /** * 添加请求头 * @param builder Request.Builder构建器 @@ -127,4 +146,7 @@ public class HttpUtil { } } } + + + } diff --git a/app/src/main/java/com/example/longyi_groundstation/Util/SharedPreferencesTool.java b/app/src/main/java/com/example/longyi_groundstation/Util/SharedPreferencesTool.java index b0275fb..b8cf953 100644 --- a/app/src/main/java/com/example/longyi_groundstation/Util/SharedPreferencesTool.java +++ b/app/src/main/java/com/example/longyi_groundstation/Util/SharedPreferencesTool.java @@ -18,15 +18,10 @@ public class SharedPreferencesTool { context.getSharedPreferences("user_info", MODE_PRIVATE); android.content.SharedPreferences.Editor editor = sharedPreferences.edit(); - editor.putInt("id", userData.getInt("id")); - editor.putString("avatar", userData.getString("avatar")); - editor.putString("nickname", userData.getString("nickname")); - editor.putString("mobile", userData.getString("mobile")); - editor.putLong("create_time", userData.getLong("create_time")); - editor.putLong("update_time", userData.getLong("update_time")); - editor.putInt("is_active", userData.getInt("is_active")); - editor.putInt("sort", userData.getInt("sort")); - editor.putString("token", userData.getString("token")); +// editor.putInt("id", userData.getInt("id")); + editor.putString("userId", userData.getString("userId")); + editor.putString("accessToken", userData.getString("accessToken")); + editor.putString("refreshToken", userData.getString("refreshToken")); editor.apply(); // 异步保存 }catch (Exception e){ Log.d(TAG, "saveLogin:error " + e); @@ -37,29 +32,10 @@ public class SharedPreferencesTool { public static String getToken(Context context){ android.content.SharedPreferences sharedPreferences = context.getSharedPreferences("user_info", MODE_PRIVATE); - String token = sharedPreferences.getString("token", null); + String token = sharedPreferences.getString("accessToken", null); return token; } - public static JSONObject getUserInfo(Context context){ - android.content.SharedPreferences sharedPreferences = - context.getSharedPreferences("user_info", MODE_PRIVATE); - JSONObject userInfo = new JSONObject(); - try { - userInfo.put("id", sharedPreferences.getInt("id", 0)); - userInfo.put("avatar", sharedPreferences.getString("avatar", "")); - userInfo.put("nickname", sharedPreferences.getString("nickname", "")); - userInfo.put("mobile", sharedPreferences.getString("mobile", "")); - userInfo.put("create_time", sharedPreferences.getLong("create_time", 0)); - userInfo.put("update_time", sharedPreferences.getLong( "update_time", 0)); - userInfo.put("is_active", sharedPreferences.getInt("is_active", 0)); - userInfo.put("sort", sharedPreferences.getInt("sort", 0)); - userInfo.put("token", sharedPreferences.getString("token", "")); - return userInfo; - }catch (Exception e){ - return null; - } - } } diff --git a/app/src/main/res/layout/activity_login.xml b/app/src/main/res/layout/activity_login.xml index ff5b756..9162f9f 100644 --- a/app/src/main/res/layout/activity_login.xml +++ b/app/src/main/res/layout/activity_login.xml @@ -27,7 +27,7 @@ android:layout_marginBottom="10dp"/> + android:visibility="visible">