Browse Source

x03-01/02

master
DESKTOP-1PDT1EL\10564 2 weeks ago
commit
edbe442e9f
  1. BIN
      .gradle/8.10.2/checksums/checksums.lock
  2. BIN
      .gradle/8.10.2/checksums/md5-checksums.bin
  3. BIN
      .gradle/8.10.2/checksums/sha1-checksums.bin
  4. 0
      .gradle/8.10.2/dependencies-accessors/gc.properties
  5. BIN
      .gradle/8.10.2/executionHistory/executionHistory.bin
  6. BIN
      .gradle/8.10.2/executionHistory/executionHistory.lock
  7. BIN
      .gradle/8.10.2/fileChanges/last-build.bin
  8. BIN
      .gradle/8.10.2/fileHashes/fileHashes.bin
  9. BIN
      .gradle/8.10.2/fileHashes/fileHashes.lock
  10. BIN
      .gradle/8.10.2/fileHashes/resourceHashesCache.bin
  11. 0
      .gradle/8.10.2/gc.properties
  12. BIN
      .gradle/buildOutputCleanup/buildOutputCleanup.lock
  13. 2
      .gradle/buildOutputCleanup/cache.properties
  14. BIN
      .gradle/buildOutputCleanup/outputFiles.bin
  15. 2
      .gradle/config.properties
  16. BIN
      .gradle/file-system.probe
  17. 0
      .gradle/vcs-1/gc.properties
  18. 3
      .idea/.gitignore
  19. 1
      .idea/.name
  20. 9
      .idea/PaintingApp.iml
  21. 9
      .idea/PaintingAppV1_0.iml
  22. 6
      .idea/compiler.xml
  23. 10
      .idea/deploymentTargetDropDown.xml
  24. 18
      .idea/deploymentTargetSelector.xml
  25. 20
      .idea/gradle.xml
  26. 10
      .idea/migrations.xml
  27. 16
      .idea/misc.xml
  28. 17
      .idea/runConfigurations.xml
  29. 6
      .idea/vcs.xml
  30. 6
      README.md
  31. 1
      app/.gitignore
  32. 65
      app/build.gradle
  33. 21
      app/proguard-rules.pro
  34. BIN
      app/release/Painting.apk
  35. 20
      app/release/output-metadata.json
  36. 26
      app/src/androidTest/java/com/example/washing02app/ExampleInstrumentedTest.java
  37. 53
      app/src/main/AndroidManifest.xml
  38. 30
      app/src/main/java/bsp_Error.proto
  39. 25
      app/src/main/java/bsp_IV.proto
  40. 17
      app/src/main/java/bsp_PV.proto
  41. 514
      app/src/main/java/com/example/washing02app/MainActivity.java
  42. 823
      app/src/main/java/com/example/washing02app/models/BspError.java
  43. 1606
      app/src/main/java/com/example/washing02app/models/BspIV.java
  44. 1162
      app/src/main/java/com/example/washing02app/models/BspPV.java
  45. 50
      app/src/main/java/com/example/washing02app/models/DisplayIV.java
  46. 38
      app/src/main/java/com/example/washing02app/models/DisplayPV.java
  47. 44
      app/src/main/java/com/example/washing02app/models/ErrorModel.java
  48. 43
      app/src/main/java/com/example/washing02app/models/ScrollBottomScrollView.java
  49. 26
      app/src/main/java/com/example/washing02app/services/ConvertHelper.java
  50. 22
      app/src/main/java/com/example/washing02app/services/CustomProber.java
  51. 71
      app/src/main/java/com/example/washing02app/services/DecimalDigitsInputFilter.java
  52. 58
      app/src/main/java/com/example/washing02app/services/ErrorDeocdeHelper.java
  53. 57
      app/src/main/java/com/example/washing02app/services/LineOverlayView.java
  54. 39
      app/src/main/java/com/example/washing02app/services/LogUtil.java
  55. 72
      app/src/main/java/com/example/washing02app/services/ModbusCRC.java
  56. 222
      app/src/main/java/com/example/washing02app/services/MyDataHelper.java
  57. 176
      app/src/main/java/com/example/washing02app/services/PopupHelper.java
  58. 302
      app/src/main/java/com/example/washing02app/services/ReceiivedIVHandler.java
  59. 64
      app/src/main/java/com/example/washing02app/services/RobotDataHanlder.java
  60. 55
      app/src/main/java/com/example/washing02app/services/ToggleRadioButton.java
  61. 89
      app/src/main/java/com/example/washing02app/services/UDPHelper.java
  62. 369
      app/src/main/java/com/example/washing02app/services/USBSerialPortHelper.java
  63. 47
      app/src/main/java/com/example/washing02app/services/VideoPlayerHelper.java
  64. 11
      app/src/main/java/com/example/washing02app/viewmodels/MainViewModel.java
  65. 2
      app/src/main/java/generate_java.bat
  66. BIN
      app/src/main/java/protoc.7z
  67. BIN
      app/src/main/java/protoc.exe
  68. 25
      app/src/main/res/drawable/background.xml
  69. BIN
      app/src/main/res/drawable/bgr.png
  70. BIN
      app/src/main/res/drawable/bigackground.png
  71. BIN
      app/src/main/res/drawable/bigackground2.png
  72. 25
      app/src/main/res/drawable/blue_rounded_rectangle.xml
  73. 10
      app/src/main/res/drawable/border.xml
  74. 31
      app/src/main/res/drawable/borderblue.xml
  75. 34
      app/src/main/res/drawable/bordergreen.xml
  76. 31
      app/src/main/res/drawable/borderlog.xml
  77. 24
      app/src/main/res/drawable/borderorange.xml
  78. 24
      app/src/main/res/drawable/bordersubmenu.xml
  79. 24
      app/src/main/res/drawable/borderwhite.xml
  80. 24
      app/src/main/res/drawable/buttonborderwhite.xml
  81. 14
      app/src/main/res/drawable/dash_line.xml
  82. 170
      app/src/main/res/drawable/ic_launcher_background.xml
  83. 30
      app/src/main/res/drawable/ic_launcher_foreground.xml
  84. 24
      app/src/main/res/drawable/message_rounded_rectangle.xml
  85. 26
      app/src/main/res/drawable/message_rounded_rectangle_red.xml
  86. 26
      app/src/main/res/drawable/orange_rounded_rectangle.xml
  87. 12
      app/src/main/res/drawable/radio_button_selected.xml
  88. 8
      app/src/main/res/drawable/radio_button_textcolor.xml
  89. 11
      app/src/main/res/drawable/radio_button_unselected.xml
  90. 5
      app/src/main/res/drawable/radiobutton_background.xml
  91. 11
      app/src/main/res/drawable/radiobutton_notsave_background.xml
  92. 12
      app/src/main/res/drawable/radiobutton_save_background.xml
  93. 28
      app/src/main/res/drawable/rounded_edittext.xml
  94. BIN
      app/src/main/res/drawable/smallbackground.png
  95. BIN
      app/src/main/res/drawable/squrelogo.png
  96. 24
      app/src/main/res/drawable/submenu.xml
  97. BIN
      app/src/main/res/drawable/submenu2.png
  98. BIN
      app/src/main/res/drawable/submenupng.png
  99. BIN
      app/src/main/res/font/font_you_yuan.ttf
  100. 608
      app/src/main/res/layout/activity_main.xml

BIN
.gradle/8.10.2/checksums/checksums.lock

Binary file not shown.

BIN
.gradle/8.10.2/checksums/md5-checksums.bin

Binary file not shown.

BIN
.gradle/8.10.2/checksums/sha1-checksums.bin

Binary file not shown.

0
.gradle/8.10.2/dependencies-accessors/gc.properties

BIN
.gradle/8.10.2/executionHistory/executionHistory.bin

Binary file not shown.

BIN
.gradle/8.10.2/executionHistory/executionHistory.lock

Binary file not shown.

BIN
.gradle/8.10.2/fileChanges/last-build.bin

Binary file not shown.

BIN
.gradle/8.10.2/fileHashes/fileHashes.bin

Binary file not shown.

BIN
.gradle/8.10.2/fileHashes/fileHashes.lock

Binary file not shown.

BIN
.gradle/8.10.2/fileHashes/resourceHashesCache.bin

Binary file not shown.

0
.gradle/8.10.2/gc.properties

BIN
.gradle/buildOutputCleanup/buildOutputCleanup.lock

Binary file not shown.

2
.gradle/buildOutputCleanup/cache.properties

@ -0,0 +1,2 @@
#Tue Jun 02 12:01:21 CST 2026
gradle.version=8.10.2

BIN
.gradle/buildOutputCleanup/outputFiles.bin

Binary file not shown.

2
.gradle/config.properties

@ -0,0 +1,2 @@
#Tue Jan 20 11:38:20 CST 2026
java.home=D\:\\Program Files\\Android\\Android Studio\\jbr

BIN
.gradle/file-system.probe

Binary file not shown.

0
.gradle/vcs-1/gc.properties

3
.idea/.gitignore

@ -0,0 +1,3 @@
# Default ignored files
/shelf/
/workspace.xml

1
.idea/.name

@ -0,0 +1 @@
Washing02APP

9
.idea/PaintingApp.iml

@ -0,0 +1,9 @@
<?xml version="1.0" encoding="UTF-8"?>
<module type="JAVA_MODULE" version="4">
<component name="NewModuleRootManager" inherit-compiler-output="true">
<exclude-output />
<content url="file://$MODULE_DIR$" />
<orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" />
</component>
</module>

9
.idea/PaintingAppV1_0.iml

@ -0,0 +1,9 @@
<?xml version="1.0" encoding="UTF-8"?>
<module type="JAVA_MODULE" version="4">
<component name="NewModuleRootManager" inherit-compiler-output="true">
<exclude-output />
<content url="file://$MODULE_DIR$" />
<orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" />
</component>
</module>

6
.idea/compiler.xml

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="CompilerConfiguration">
<bytecodeTargetLevel target="21" />
</component>
</project>

10
.idea/deploymentTargetDropDown.xml

@ -0,0 +1,10 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="deploymentTargetDropDown">
<value>
<entry key="app">
<State />
</entry>
</value>
</component>
</project>

18
.idea/deploymentTargetSelector.xml

@ -0,0 +1,18 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="deploymentTargetSelector">
<selectionStates>
<SelectionState runConfigName="app">
<option name="selectionMode" value="DROPDOWN" />
<DropdownSelection timestamp="2026-07-02T07:17:45.754662400Z">
<Target type="DEFAULT_BOOT">
<handle>
<DeviceId pluginId="Default" identifier="serial=192.168.144.20:5555;connection=f0374d99" />
</handle>
</Target>
</DropdownSelection>
<DialogSelection />
</SelectionState>
</selectionStates>
</component>
</project>

20
.idea/gradle.xml

@ -0,0 +1,20 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="GradleMigrationSettings" migrationVersion="1" />
<component name="GradleSettings">
<option name="linkedExternalProjectsSettings">
<GradleProjectSettings>
<option name="testRunner" value="CHOOSE_PER_TEST" />
<option name="externalProjectPath" value="$PROJECT_DIR$" />
<option name="gradleJvm" value="#GRADLE_LOCAL_JAVA_HOME" />
<option name="modules">
<set>
<option value="$PROJECT_DIR$" />
<option value="$PROJECT_DIR$/app" />
</set>
</option>
<option name="resolveExternalAnnotations" value="false" />
</GradleProjectSettings>
</option>
</component>
</project>

10
.idea/migrations.xml

@ -0,0 +1,10 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ProjectMigrations">
<option name="MigrateToGradleLocalJavaHome">
<set>
<option value="$PROJECT_DIR$" />
</set>
</option>
</component>
</project>

16
.idea/misc.xml

@ -0,0 +1,16 @@
<project version="4">
<component name="ExternalStorageConfigurationManager" enabled="true" />
<component name="ProjectRootManager" version="2" languageLevel="JDK_21" default="true" project-jdk-name="jbr-21" project-jdk-type="JavaSDK">
<output url="file://$PROJECT_DIR$/build/classes" />
</component>
<component name="ProjectType">
<option name="id" value="Android" />
</component>
<component name="VisualizationToolProject">
<option name="state">
<ProjectState>
<option name="scale" value="0.04120409906063194" />
</ProjectState>
</option>
</component>
</project>

17
.idea/runConfigurations.xml

@ -0,0 +1,17 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="RunConfigurationProducerService">
<option name="ignoredProducers">
<set>
<option value="com.intellij.execution.junit.AbstractAllInDirectoryConfigurationProducer" />
<option value="com.intellij.execution.junit.AllInPackageConfigurationProducer" />
<option value="com.intellij.execution.junit.PatternConfigurationProducer" />
<option value="com.intellij.execution.junit.TestInClassConfigurationProducer" />
<option value="com.intellij.execution.junit.UniqueIdConfigurationProducer" />
<option value="com.intellij.execution.junit.testDiscovery.JUnitTestDiscoveryConfigurationProducer" />
<option value="org.jetbrains.kotlin.idea.junit.KotlinJUnitRunConfigurationProducer" />
<option value="org.jetbrains.kotlin.idea.junit.KotlinPatternConfigurationProducer" />
</set>
</option>
</component>
</project>

6
.idea/vcs.xml

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="VcsDirectoryMappings">
<mapping directory="$PROJECT_DIR$" vcs="Git" />
</component>
</project>

6
README.md

@ -0,0 +1,6 @@
只有打磨模式下使用左右转检测到碰撞 回退
26/5/28 修改状态机版本fsm_state_run(&current_robot_move_state);
K1/2 控制大疙瘩正反转 K3控制电机上电 1上电,K4 喷漆电磁阀 1开、 K5控制喷水阀
需要修改S1 按键为非自锁
上电延时10s左右 包括急停恢复 再发报文
摄像头界面可在app startvedio 函数设置画面正反

1
app/.gitignore

@ -0,0 +1 @@
/build

65
app/build.gradle

@ -0,0 +1,65 @@
plugins {
id 'com.android.application'
}
android {
namespace 'com.example.washing02app'
compileSdk 35
viewBinding
{
enabled true
}
// //add this feature
dataBinding
{
enabled true
}
defaultConfig {
applicationId "com.example.washing02app"
minSdk 24
targetSdk 35
versionCode 1
versionName "1.0"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
}
android.applicationVariants.all { variant ->
variant.outputs.all {
outputFileName = "Painting.apk"
}
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
}
buildFeatures{
buildConfig true
}
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
}
dependencies {
implementation 'androidx.appcompat:appcompat:1.6.1'
implementation 'androidx.constraintlayout:constraintlayout:2.1.4'
implementation 'androidx.media3:media3-exoplayer:1.5.1'
implementation 'androidx.media3:media3-ui:1.5.1'
implementation 'androidx.media3:media3-exoplayer-rtsp:1.5.1'
implementation 'com.google.android.material:material:1.12.0'
testImplementation 'junit:junit:4.13.2'
androidTestImplementation 'androidx.test.ext:junit:1.1.5'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.5.1'
implementation 'com.github.mik3y:usb-serial-for-android:3.7.0'
implementation 'com.google.protobuf:protobuf-java:4.27.2'
implementation("org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.8.20")
implementation 'com.github.nodemedia:nodemediaclient-android:2.9.20'
implementation 'io.github.xmaihh:serialport:2.1.1'
}

21
app/proguard-rules.pro

@ -0,0 +1,21 @@
# Add project specific ProGuard rules here.
# You can control the set of applied configuration files using the
# proguardFiles setting in build.gradle.
#
# For more details, see
# http://developer.android.com/guide/developing/tools/proguard.html
# If your project uses WebView with JS, uncomment the following
# and specify the fully qualified class name to the JavaScript interface
# class:
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
# public *;
#}
# Uncomment this to preserve the line number information for
# debugging stack traces.
#-keepattributes SourceFile,LineNumberTable
# If you keep the line number information, uncomment this to
# hide the original source file name.
#-renamesourcefileattribute SourceFile

BIN
app/release/Painting.apk

Binary file not shown.

20
app/release/output-metadata.json

@ -0,0 +1,20 @@
{
"version": 3,
"artifactType": {
"type": "APK",
"kind": "Directory"
},
"applicationId": "com.example.paintingappv1_1",
"variantName": "release",
"elements": [
{
"type": "SINGLE",
"filters": [],
"attributes": [],
"versionCode": 1,
"versionName": "1.0",
"outputFile": "Painting.apk"
}
],
"elementType": "File"
}

26
app/src/androidTest/java/com/example/washing02app/ExampleInstrumentedTest.java

@ -0,0 +1,26 @@
package com.example.rougheningapp;
import static org.junit.Assert.assertEquals;
import android.content.Context;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.platform.app.InstrumentationRegistry;
import org.junit.Test;
import org.junit.runner.RunWith;
/**
* Instrumented test, which will execute on an Android device.
*
* @see <a href="http://d.android.com/tools/testing">Testing documentation</a>
*/
@RunWith(AndroidJUnit4.class)
public class ExampleInstrumentedTest {
@Test
public void useAppContext() {
// Context of the app under test.
Context appContext = InstrumentationRegistry.getInstrumentation().getTargetContext();
assertEquals("com.example.rougheningapp", appContext.getPackageName());
}
}

53
app/src/main/AndroidManifest.xml

@ -0,0 +1,53 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools">
<uses-feature android:name="android.hardware.camera" />
<uses-feature android:name="android.hardware.camera.autofocus" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.RECORD_AUDIO" />
<uses-permission android:name="android.permission.FLASHLIGHT" />
<uses-permission android:name="android.permission.USB_PERMISSION" />
<uses-feature
android:name="android.hardware.usb.accessory"
android:required="false" />
<uses-feature android:name="android.hardware.usb.host" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.VIBRATE" />
<application
android:allowBackup="true"
android:dataExtractionRules="@xml/data_extraction_rules"
android:fullBackupContent="@xml/backup_rules"
android:icon="@drawable/squrelogo"
android:label="@string/app_name"
android:roundIcon="@drawable/squrelogo"
android:supportsRtl="true"
android:theme="@style/Theme.RougheningApp"
tools:targetApi="31">
<meta-data
android:name="com.google.android.actions"
android:resource="@xml/check_boxs" />
<activity
android:name=".MainActivity"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
<action android:name="android.hardware.usb.action.USB_DEVICE_ATTACHED" />
</intent-filter>
<meta-data
android:name="android.hardware.usb.action.USB_DEVICE_ATTACHED"
android:resource="@xml/device_filter" />
</activity>
</application>
</manifest>

30
app/src/main/java/bsp_Error.proto

@ -0,0 +1,30 @@
syntax = "proto3";
option java_multiple_files = false;
option java_package = "com.example.washing02app.models";
message ErrorData
{
int32 Com_Error_Code=1;
int32 Left_Motor_Error_Code=2;
int32 Right_Motor_Error_Code=3;
}
enum ComError //枚举消息类型 Error Bit Define
{
MK32_SBus = 0;
TL720D = 1;
Ti5_1 = 2;
Ti5_2 = 3;
Ti5_3 = 4;
Ti5_4 = 5;
Ti5_5 = 6;
Ti5_6 = 7;
Remote_Button_Reset_State = 8;
}
//protoc --nanopb_out=. *.proto

25
app/src/main/java/bsp_IV.proto

@ -0,0 +1,25 @@
syntax = "proto3";
option java_multiple_files = false;
option java_package = "com.example.washing02app.models";
message IV_struct_define
{
int32 CurrentAngle= 1; //单位0.01°
int32 SBUS_State=2; //0断开 1连接
int32 SystemError=3; //硬件通讯错误及按键未初始化错误
int32 LeftFrontMotor_Err=4;//左前电机报警
int32 LeftBackMotor_Err=5;//右后电机报警
int32 RightFrontMotor_Err=6;//右前电机报警
int32 RightBackMotor_Err=7;//右后电机报警
int32 SwingMotor_Err=8;//左摆电机报警
int32 TiltMotor_Err=9;//伤摆电机报警
int32 IsWorking=10;//机器人正在执行运动指令
int64 TimeStamp=11;//当前时间戳
int32 IsRestart=12;//是否重启
int32 RobotMoveSpeed=13;
};

17
app/src/main/java/bsp_PV.proto

@ -0,0 +1,17 @@
syntax = "proto3";
option java_multiple_files = false;
option java_package = "com.example.washing02app.models";
message PV_struct_define{
// 洗舱项目
int32 WorkMode = 1; //1 清洗 2 刷洗 3 喷漆
int32 JointSpeed1=2; // 第一关节速度 °/s
int32 JointSpeed2= 3; // 第二关节速度 °/s
int32 ForceSet=4; // 下压力设置
double LeftComp=5; //左行补偿
double RightComp=6; //右行补偿
int32 IV_IsRestart_Notified=7;// 是否接收到IV restart flag
int64 TimeStamp=8;//
};

514
app/src/main/java/com/example/washing02app/MainActivity.java

@ -0,0 +1,514 @@
package com.example.washing02app;
import static com.example.washing02app.services.ReceiivedIVHandler.TIME_OUT;
import static com.example.washing02app.services.ReceiivedIVHandler.isAlarmDialogShowed;
import static com.example.washing02app.services.ReceiivedIVHandler.lastReceiveTime;
import static java.lang.Integer.parseInt;
import android.graphics.Color;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.text.Editable;
import android.text.InputFilter;
import android.text.TextUtils;
import android.text.TextWatcher;
import android.view.KeyEvent;
import android.view.View;
import android.view.ViewGroup;
import android.view.WindowManager;
import android.widget.Toast;
import androidx.appcompat.app.AlertDialog;
import androidx.appcompat.app.AppCompatActivity;
import androidx.databinding.DataBindingUtil;
import androidx.media3.common.MediaItem;
import androidx.media3.exoplayer.ExoPlayer;
import com.example.washing02app.databinding.ActivityMainBinding;
import com.example.washing02app.models.BspPV;
import com.example.washing02app.models.DisplayPV;
import com.example.washing02app.services.DecimalDigitsInputFilter;
import com.example.washing02app.services.ModbusCRC;
import com.example.washing02app.services.MyDataHelper;
import com.example.washing02app.services.PopupHelper;
import com.example.washing02app.services.ReceiivedIVHandler;
import com.example.washing02app.services.UDPHelper;
import com.example.washing02app.services.USBSerialPortHelper;
import com.example.washing02app.services.VideoPlayerHelper;
import java.util.List;
import java.util.Timer;
import java.util.TimerTask;
import cn.nodemedia.NodePlayer;
public class MainActivity extends AppCompatActivity {
public ActivityMainBinding mainBinding;//通过Binding可以获取界面数据
//USB 串口服务
public USBSerialPortHelper serialPortHelper;
public static BspPV.PV_struct_define _toSendPV;
Timer timer = new Timer();
public MyDataHelper myDataHelper = new MyDataHelper(this);
public PopupHelper popupHelper = new PopupHelper(this);
public String _parameters_Call_Value = "1";
public String _Work_Mode_Call_Value = "无";
public int screen =0;
//标记是否全屏
private boolean isFullScreen = false;
//保存原始布局参数(退出全屏用)
private ViewGroup.LayoutParams originalParams;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//设置全屏显示
getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN);
mainBinding = DataBindingUtil.setContentView(this, R.layout.activity_main);
mainBinding.editLeftCompTo32.setFilters(new InputFilter[]{new DecimalDigitsInputFilter()}); //editext 一位小数限制
mainBinding.editRightCompTo32.setFilters(new InputFilter[]{new DecimalDigitsInputFilter()}); //editext 一位小数限制
getWindow().clearFlags(WindowManager.LayoutParams.FLAG_DIM_BEHIND);
getWindow().setDimAmount(0f);
getWindow().setFlags(
WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED,
WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED
);
/* USB串口 控制区域*/
serialPortHelper = new USBSerialPortHelper(this);
serialPortHelper.intialize();
serialPortHelper.connect();
/* NodePlayer 播放视频区域*/
NodePlayer nodePlayer0=new NodePlayer(this);
String address0 = "rtsp://192.168.144.25:8554/main.264";
mainBinding.nodePlayerView0.setBackgroundColor(Color.BLACK);
VideoPlayerHelper.startVedio(mainBinding.nodePlayerView0,nodePlayer0,address0);
mainBinding.lineOverlay.setLinePosition(0.6f,0.8f);
// 保存原始宽高
originalParams = mainBinding.nodePlayerView0.getLayoutParams();
// 单击切换全屏
mainBinding.nodePlayerView0.setOnClickListener(v -> toggleFullScreen());
timer.schedule(new TimerTask() {
@Override
public void run() {
// 使用 Handler 或 runOnUiThread 更新 UI
runOnUiThread(new Runnable() {
@Override
public void run() {
mainBinding.nodePlayerView0.setAlpha(1.0f);
// 更新 UI 的代码
_toSendPV = BspPV.PV_struct_define.newBuilder().
build();
//单片机重启发1,安卓接收向单片机发送收到重启通知1,当单片机收到进而转为为 非重启状态
if(ReceiivedIVHandler._toReceiveIV_Variable.getIsRestart()==1)
{
_toSendPV=_toSendPV.toBuilder().setIVIsRestartNotified(1).build();
}else
{
_toSendPV=_toSendPV.toBuilder().setIVIsRestartNotified(0).build();
}
//发送时间戳 ms
_toSendPV = _toSendPV.toBuilder().setTimeStamp(System.currentTimeMillis()).build();
String jointSpeed1Str = mainBinding.jointSpeed1To32.getText().toString();
String jointSpeed2Str = mainBinding.jointSpeed2To32.getText().toString();
String forceSetStr = mainBinding.forceSetingTo32.getText().toString();
String leftCompStr = mainBinding.editLeftCompTo32.getText().toString();
String rightCompStr = mainBinding.editRightCompTo32.getText().toString();
//第一关节速度
if (jointSpeed1Str.isEmpty()) {
_toSendPV = _toSendPV.toBuilder().setJointSpeed1(8).build();
} else {
_toSendPV = _toSendPV.toBuilder()
.setJointSpeed1((Integer.parseInt(String.valueOf(mainBinding.jointSpeed1To32.getText())))).build();
}
//第2关节速度
if (jointSpeed2Str.isEmpty()) {
_toSendPV = _toSendPV.toBuilder().setJointSpeed2(8).build();
} else {
_toSendPV = _toSendPV.toBuilder()
.setJointSpeed2((Integer.parseInt(String.valueOf(mainBinding.jointSpeed2To32.getText())))).build();
}
//电流档位
if (forceSetStr.isEmpty()) {
_toSendPV = _toSendPV.toBuilder().setForceSet(0).build();
} else {
_toSendPV = _toSendPV.toBuilder()
.setForceSet((Integer.parseInt(String.valueOf(mainBinding.forceSetingTo32.getText())))).build();
}
//左补偿
try {
if (leftCompStr.isEmpty()) {
_toSendPV = _toSendPV.toBuilder().setLeftComp(0).build();
} else {
_toSendPV = _toSendPV.toBuilder()
.setLeftComp((int) (Double.parseDouble(String.valueOf(mainBinding.editLeftCompTo32.getText())) * 100)).build();
}
} catch (Exception e) {
}
//右补偿
try {
if (rightCompStr.isEmpty()) {
_toSendPV = _toSendPV.toBuilder().setRightComp(0).build();
} else {
_toSendPV = _toSendPV.toBuilder()
.setRightComp((int) (Double.parseDouble(String.valueOf(mainBinding.editRightCompTo32.getText())) * 100)).build();
}
} catch (Exception e) {
}
//发送作业模式值
if (_Work_Mode_Call_Value.equals("无")) {
_toSendPV = _toSendPV.toBuilder().setWorkMode(0).build();
} else if (_Work_Mode_Call_Value.equals("清洗")) {
_toSendPV = _toSendPV.toBuilder().setWorkMode(1).build();
} else if (_Work_Mode_Call_Value.equals("刷洗")) {
_toSendPV = _toSendPV.toBuilder().setWorkMode(2).build();
}
else if (_Work_Mode_Call_Value.equals("喷漆")) {
_toSendPV = _toSendPV.toBuilder().setWorkMode(3).build();
}
byte[] byteArray = _toSendPV.toByteArray();
byte[] sendbyteArray = new byte[byteArray.length + 4];
byte[] sendbyteArray3 = new byte[byteArray.length + 6];
if (byteArray.length != 0) {
System.arraycopy(byteArray, 0, sendbyteArray, 4, byteArray.length);
}
sendbyteArray[0] = (byte) 0x55;
sendbyteArray[1] = (byte) 0x55;
sendbyteArray[2] = (byte) 0x01;
sendbyteArray[3] = (byte) 0x01;
byte[] byteArray2 = ModbusCRC.calculateCRC(sendbyteArray);
System.arraycopy(sendbyteArray, 0, sendbyteArray3, 0, sendbyteArray.length);
System.arraycopy(byteArray2, 0, sendbyteArray3, sendbyteArray3.length - 2, 2);
serialPortHelper.SendData(sendbyteArray3);
}
});
}
}, 0, 200); // 延迟 0 毫秒,每隔 1000 毫秒执行一次
mainBinding.btnWorkMode.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
popupHelper.WorkModePopUp(this);
}
});
//setOnFocusChangeListener
mainBinding.jointSpeed1To32.setOnFocusChangeListener((v, hasFocus) -> {
// 当用户**输完离开输入框**时才检查
if (!hasFocus) {
String input = mainBinding.jointSpeed1To32.getText().toString().trim();
if (!input.isEmpty()) {
try {
int value = Integer.parseInt(input);
if (value < 10 || value > 30) {
showToast("请输入 10 ~ 90 之间的数字");
// 可以清空,也可以不清空,让用户自己改
mainBinding.jointSpeed1To32.setText("");
}
} catch (NumberFormatException e) {
showToast("请输入有效数字");
mainBinding.jointSpeed1To32.setText("");
}
}
}
});
mainBinding.jointSpeed2To32.setOnFocusChangeListener((v, hasFocus) -> {
// 当用户**输完离开输入框**时才检查
if (!hasFocus) {
String input = mainBinding.jointSpeed2To32.getText().toString().trim();
if (!input.isEmpty()) {
try {
int value = Integer.parseInt(input);
if (value < 10 || value > 30) {
showToast("请输入 10 ~ 90 之间的数字");
// 可以清空,也可以不清空,让用户自己改
mainBinding.jointSpeed2To32.setText("");
}
} catch (NumberFormatException e) {
showToast("请输入有效数字");
mainBinding.jointSpeed2To32.setText("");
}
}
}
});
mainBinding.editLeftCompTo32.addTextChangedListener(new TextWatcher() {
@Override
public void beforeTextChanged(CharSequence charSequence, int i, int i1, int i2) {
}
@Override
public void onTextChanged(CharSequence charSequence, int i, int i1, int i2) {
}
@Override
public void afterTextChanged(Editable s) {
String input = s.toString().trim();
// 1. 允许空输入(用户正在删除)
if (TextUtils.isEmpty(input)) {
return;
}
// 2. 允许合法的中间状态(如"-10.")
if (input.matches("^-?\\d*(\\.\\d*)?$")) {
// 合法格式:整数、负数、小数、小数点开头
try {
double value = Double.parseDouble(input);
// 检查输入值是否在 -50 到 100 范围内
if (value < -10 || value > 10) {
showToast("请输入 -10 到 10 之间的数字");
// 可以选择清除输入或限制在范围内
mainBinding.editLeftCompTo32.setText("");
} else {
showToast("输入有效: " + value);
}
// 尝试转换为double(处理小数)
//lastValidValue = Double.parseDouble(input);
} catch (NumberFormatException e) {
// 中间状态,忽略
}
}
}
});
mainBinding.editRightCompTo32.addTextChangedListener(new TextWatcher() {
@Override
public void beforeTextChanged(CharSequence charSequence, int i, int i1, int i2) {
}
@Override
public void onTextChanged(CharSequence charSequence, int i, int i1, int i2) {
}
@Override
public void afterTextChanged(Editable s) {
String input = s.toString().trim();
// 1. 允许空输入(用户正在删除)
if (TextUtils.isEmpty(input)) {
return;
}
// 2. 允许合法的中间状态(如"-10.")
if (input.matches("^-?\\d*(\\.\\d*)?$")) {
// 合法格式:整数、负数、小数、小数点开头
try {
double value = Double.parseDouble(input);
// 检查输入值是否在 -50 到 100 范围内
if (value < -10 || value > 10) {
showToast("请输入 -10 到 10 之间的数字");
// 可以选择清除输入或限制在范围内
mainBinding.editRightCompTo32.setText("");
} else {
showToast("输入有效: " + value);
}
// 尝试转换为double(处理小数)
//lastValidValue = Double.parseDouble(input);
} catch (NumberFormatException e) {
// 中间状态,忽略
}
}
}
});
mainBinding.forceSetingTo32.addTextChangedListener(new TextWatcher() {
@Override
public void beforeTextChanged(CharSequence charSequence, int i, int i1, int i2) {
}
@Override
public void onTextChanged(CharSequence charSequence, int i, int i1, int i2) {
}
@Override
public void afterTextChanged(Editable s) {
// 文本变化后的回调,在这里进行范围检查
String input = s.toString();
if (!input.isEmpty()) {
try {
int value = Integer.parseInt(input);
// 检查输入值是否在 -50 到 100 范围内
if (value < 0 || value > 8) {
showToast("请输入 0 到 8 之间的数字");
// 可以选择清除输入或限制在范围内
mainBinding.forceSetingTo32.setText("");
} else {
showToast("输入有效: " + value);
}
} catch (NumberFormatException e) {
showToast("请输入有效的数字");
}
}
}
});
mainBinding. ErrMessageBtn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
popupHelper.RobotErrorListPopUp(this);
}
});
mainBinding.lineChange.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if(mainBinding.lineState.getText() == "开启")
{
mainBinding.lineState.setText("关闭");
mainBinding.lineOverlay.setVisibility(View.GONE);
}
else{
mainBinding.lineState.setText("开启");
mainBinding.lineOverlay.setVisibility(View.VISIBLE);
}
}
});
mainBinding.screenRotate.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if(0 == screen)
{
mainBinding.nodePlayerView0.setRotation(180);
// VideoPlayerHelper.startVedio1(mainBinding.nodePlayerView0,nodePlayer0,address0);
screen = 1;
}
else
{
/* NodePlayer 播放视频区域*/
mainBinding.nodePlayerView0.setRotation(0);
screen = 0;
}
}
});
}
private void showToast(String message)
{
Toast.makeText(this, message, Toast.LENGTH_SHORT).show();
}
private void toggleFullScreen() {
if (!isFullScreen) {
// ---------- 进入全屏 ----------
isFullScreen = true;
mainBinding.messageRounded.setVisibility(View.GONE);
// 1. 隐藏状态栏、导航栏
getWindow().addFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN);
getWindow().getDecorView().setSystemUiVisibility(
View.SYSTEM_UI_FLAG_HIDE_NAVIGATION |
View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY);
// 2. 播放器铺满整个屏幕
ViewGroup.LayoutParams params = mainBinding.nodePlayerView0.getLayoutParams();
params.width = ViewGroup.LayoutParams.MATCH_PARENT;
params.height = ViewGroup.LayoutParams.MATCH_PARENT;
mainBinding.nodePlayerView0.setLayoutParams(params);
} else {
// ---------- 退出全屏 ----------
isFullScreen = false;
mainBinding.messageRounded.setVisibility(View.VISIBLE);
// 1. 恢复状态栏、导航栏
getWindow().clearFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN);
getWindow().getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_VISIBLE);
// 2. 恢复原来的宽高
mainBinding.nodePlayerView0.setLayoutParams(originalParams);
}
}
@Override
protected void onStart() {
super.onStart();
serialPortHelper.onStart();
}
@Override
public void onStop() {
serialPortHelper.onStop();
super.onStop();
}
@Override
public void onResume() {
super.onResume();
serialPortHelper.onResume();
}
@Override
public void onPause() {
serialPortHelper.onPause();
super.onPause();
}
@Override
protected void onDestroy() {
super.onDestroy();
if (timer != null) {
timer.cancel();
}
}
@Override
public boolean dispatchKeyEvent(KeyEvent event) {
if (event.getAction() == KeyEvent.ACTION_DOWN) {
// 防止View抢焦点
mainBinding.nodePlayerView0.clearFocus();
}
return super.dispatchKeyEvent(event);
}
}

823
app/src/main/java/com/example/washing02app/models/BspError.java

@ -0,0 +1,823 @@
// Generated by the protocol buffer compiler. DO NOT EDIT!
// NO CHECKED-IN PROTOBUF GENCODE
// source: bsp_Error.proto
// Protobuf Java Version: 4.27.2
package com.example.washing02app.models;
public final class BspError {
private BspError() {}
static {
com.google.protobuf.RuntimeVersion.validateProtobufGencodeVersion(
com.google.protobuf.RuntimeVersion.RuntimeDomain.PUBLIC,
/* major= */ 4,
/* minor= */ 27,
/* patch= */ 2,
/* suffix= */ "",
BspError.class.getName());
}
public static void registerAllExtensions(
com.google.protobuf.ExtensionRegistryLite registry) {
}
public static void registerAllExtensions(
com.google.protobuf.ExtensionRegistry registry) {
registerAllExtensions(
(com.google.protobuf.ExtensionRegistryLite) registry);
}
/**
* Protobuf enum {@code ComError}
*/
public enum ComError
implements com.google.protobuf.ProtocolMessageEnum {
/**
* <code>MK32_SBus = 0;</code>
*/
MK32_SBus(0),
/**
* <code>TL720D = 1;</code>
*/
TL720D(1),
/**
* <code>Ti5_1 = 2;</code>
*/
Ti5_1(2),
/**
* <code>Ti5_2 = 3;</code>
*/
Ti5_2(3),
/**
* <code>Ti5_3 = 4;</code>
*/
Ti5_3(4),
/**
* <code>Ti5_4 = 5;</code>
*/
Ti5_4(5),
/**
* <code>Ti5_5 = 6;</code>
*/
Ti5_5(6),
/**
* <code>Ti5_6 = 7;</code>
*/
Ti5_6(7),
/**
* <code>Remote_Button_Reset_State = 8;</code>
*/
Remote_Button_Reset_State(8),
UNRECOGNIZED(-1),
;
static {
com.google.protobuf.RuntimeVersion.validateProtobufGencodeVersion(
com.google.protobuf.RuntimeVersion.RuntimeDomain.PUBLIC,
/* major= */ 4,
/* minor= */ 27,
/* patch= */ 2,
/* suffix= */ "",
ComError.class.getName());
}
/**
* <code>MK32_SBus = 0;</code>
*/
public static final int MK32_SBus_VALUE = 0;
/**
* <code>TL720D = 1;</code>
*/
public static final int TL720D_VALUE = 1;
/**
* <code>Ti5_1 = 2;</code>
*/
public static final int Ti5_1_VALUE = 2;
/**
* <code>Ti5_2 = 3;</code>
*/
public static final int Ti5_2_VALUE = 3;
/**
* <code>Ti5_3 = 4;</code>
*/
public static final int Ti5_3_VALUE = 4;
/**
* <code>Ti5_4 = 5;</code>
*/
public static final int Ti5_4_VALUE = 5;
/**
* <code>Ti5_5 = 6;</code>
*/
public static final int Ti5_5_VALUE = 6;
/**
* <code>Ti5_6 = 7;</code>
*/
public static final int Ti5_6_VALUE = 7;
/**
* <code>Remote_Button_Reset_State = 8;</code>
*/
public static final int Remote_Button_Reset_State_VALUE = 8;
public final int getNumber() {
if (this == UNRECOGNIZED) {
throw new java.lang.IllegalArgumentException(
"Can't get the number of an unknown enum value.");
}
return value;
}
/**
* @param value The numeric wire value of the corresponding enum entry.
* @return The enum associated with the given numeric wire value.
* @deprecated Use {@link #forNumber(int)} instead.
*/
@java.lang.Deprecated
public static ComError valueOf(int value) {
return forNumber(value);
}
/**
* @param value The numeric wire value of the corresponding enum entry.
* @return The enum associated with the given numeric wire value.
*/
public static ComError forNumber(int value) {
switch (value) {
case 0: return MK32_SBus;
case 1: return TL720D;
case 2: return Ti5_1;
case 3: return Ti5_2;
case 4: return Ti5_3;
case 5: return Ti5_4;
case 6: return Ti5_5;
case 7: return Ti5_6;
case 8: return Remote_Button_Reset_State;
default: return null;
}
}
public static com.google.protobuf.Internal.EnumLiteMap<ComError>
internalGetValueMap() {
return internalValueMap;
}
private static final com.google.protobuf.Internal.EnumLiteMap<
ComError> internalValueMap =
new com.google.protobuf.Internal.EnumLiteMap<ComError>() {
public ComError findValueByNumber(int number) {
return ComError.forNumber(number);
}
};
public final com.google.protobuf.Descriptors.EnumValueDescriptor
getValueDescriptor() {
if (this == UNRECOGNIZED) {
throw new java.lang.IllegalStateException(
"Can't get the descriptor of an unrecognized enum value.");
}
return getDescriptor().getValues().get(ordinal());
}
public final com.google.protobuf.Descriptors.EnumDescriptor
getDescriptorForType() {
return getDescriptor();
}
public static final com.google.protobuf.Descriptors.EnumDescriptor
getDescriptor() {
return com.example.washing02app.models.BspError.getDescriptor().getEnumTypes().get(0);
}
private static final ComError[] VALUES = values();
public static ComError valueOf(
com.google.protobuf.Descriptors.EnumValueDescriptor desc) {
if (desc.getType() != getDescriptor()) {
throw new java.lang.IllegalArgumentException(
"EnumValueDescriptor is not for this type.");
}
if (desc.getIndex() == -1) {
return UNRECOGNIZED;
}
return VALUES[desc.getIndex()];
}
private final int value;
private ComError(int value) {
this.value = value;
}
// @@protoc_insertion_point(enum_scope:ComError)
}
public interface ErrorDataOrBuilder extends
// @@protoc_insertion_point(interface_extends:ErrorData)
com.google.protobuf.MessageOrBuilder {
/**
* <code>int32 Com_Error_Code = 1;</code>
* @return The comErrorCode.
*/
int getComErrorCode();
/**
* <code>int32 Left_Motor_Error_Code = 2;</code>
* @return The leftMotorErrorCode.
*/
int getLeftMotorErrorCode();
/**
* <code>int32 Right_Motor_Error_Code = 3;</code>
* @return The rightMotorErrorCode.
*/
int getRightMotorErrorCode();
}
/**
* Protobuf type {@code ErrorData}
*/
public static final class ErrorData extends
com.google.protobuf.GeneratedMessage implements
// @@protoc_insertion_point(message_implements:ErrorData)
ErrorDataOrBuilder {
private static final long serialVersionUID = 0L;
static {
com.google.protobuf.RuntimeVersion.validateProtobufGencodeVersion(
com.google.protobuf.RuntimeVersion.RuntimeDomain.PUBLIC,
/* major= */ 4,
/* minor= */ 27,
/* patch= */ 2,
/* suffix= */ "",
ErrorData.class.getName());
}
// Use ErrorData.newBuilder() to construct.
private ErrorData(com.google.protobuf.GeneratedMessage.Builder<?> builder) {
super(builder);
}
private ErrorData() {
}
public static final com.google.protobuf.Descriptors.Descriptor
getDescriptor() {
return com.example.washing02app.models.BspError.internal_static_ErrorData_descriptor;
}
@java.lang.Override
protected com.google.protobuf.GeneratedMessage.FieldAccessorTable
internalGetFieldAccessorTable() {
return com.example.washing02app.models.BspError.internal_static_ErrorData_fieldAccessorTable
.ensureFieldAccessorsInitialized(
com.example.washing02app.models.BspError.ErrorData.class, com.example.washing02app.models.BspError.ErrorData.Builder.class);
}
public static final int COM_ERROR_CODE_FIELD_NUMBER = 1;
private int comErrorCode_ = 0;
/**
* <code>int32 Com_Error_Code = 1;</code>
* @return The comErrorCode.
*/
@java.lang.Override
public int getComErrorCode() {
return comErrorCode_;
}
public static final int LEFT_MOTOR_ERROR_CODE_FIELD_NUMBER = 2;
private int leftMotorErrorCode_ = 0;
/**
* <code>int32 Left_Motor_Error_Code = 2;</code>
* @return The leftMotorErrorCode.
*/
@java.lang.Override
public int getLeftMotorErrorCode() {
return leftMotorErrorCode_;
}
public static final int RIGHT_MOTOR_ERROR_CODE_FIELD_NUMBER = 3;
private int rightMotorErrorCode_ = 0;
/**
* <code>int32 Right_Motor_Error_Code = 3;</code>
* @return The rightMotorErrorCode.
*/
@java.lang.Override
public int getRightMotorErrorCode() {
return rightMotorErrorCode_;
}
private byte memoizedIsInitialized = -1;
@java.lang.Override
public final boolean isInitialized() {
byte isInitialized = memoizedIsInitialized;
if (isInitialized == 1) return true;
if (isInitialized == 0) return false;
memoizedIsInitialized = 1;
return true;
}
@java.lang.Override
public void writeTo(com.google.protobuf.CodedOutputStream output)
throws java.io.IOException {
if (comErrorCode_ != 0) {
output.writeInt32(1, comErrorCode_);
}
if (leftMotorErrorCode_ != 0) {
output.writeInt32(2, leftMotorErrorCode_);
}
if (rightMotorErrorCode_ != 0) {
output.writeInt32(3, rightMotorErrorCode_);
}
getUnknownFields().writeTo(output);
}
@java.lang.Override
public int getSerializedSize() {
int size = memoizedSize;
if (size != -1) return size;
size = 0;
if (comErrorCode_ != 0) {
size += com.google.protobuf.CodedOutputStream
.computeInt32Size(1, comErrorCode_);
}
if (leftMotorErrorCode_ != 0) {
size += com.google.protobuf.CodedOutputStream
.computeInt32Size(2, leftMotorErrorCode_);
}
if (rightMotorErrorCode_ != 0) {
size += com.google.protobuf.CodedOutputStream
.computeInt32Size(3, rightMotorErrorCode_);
}
size += getUnknownFields().getSerializedSize();
memoizedSize = size;
return size;
}
@java.lang.Override
public boolean equals(final java.lang.Object obj) {
if (obj == this) {
return true;
}
if (!(obj instanceof com.example.washing02app.models.BspError.ErrorData)) {
return super.equals(obj);
}
com.example.washing02app.models.BspError.ErrorData other = (com.example.washing02app.models.BspError.ErrorData) obj;
if (getComErrorCode()
!= other.getComErrorCode()) return false;
if (getLeftMotorErrorCode()
!= other.getLeftMotorErrorCode()) return false;
if (getRightMotorErrorCode()
!= other.getRightMotorErrorCode()) return false;
if (!getUnknownFields().equals(other.getUnknownFields())) return false;
return true;
}
@java.lang.Override
public int hashCode() {
if (memoizedHashCode != 0) {
return memoizedHashCode;
}
int hash = 41;
hash = (19 * hash) + getDescriptor().hashCode();
hash = (37 * hash) + COM_ERROR_CODE_FIELD_NUMBER;
hash = (53 * hash) + getComErrorCode();
hash = (37 * hash) + LEFT_MOTOR_ERROR_CODE_FIELD_NUMBER;
hash = (53 * hash) + getLeftMotorErrorCode();
hash = (37 * hash) + RIGHT_MOTOR_ERROR_CODE_FIELD_NUMBER;
hash = (53 * hash) + getRightMotorErrorCode();
hash = (29 * hash) + getUnknownFields().hashCode();
memoizedHashCode = hash;
return hash;
}
public static com.example.washing02app.models.BspError.ErrorData parseFrom(
java.nio.ByteBuffer data)
throws com.google.protobuf.InvalidProtocolBufferException {
return PARSER.parseFrom(data);
}
public static com.example.washing02app.models.BspError.ErrorData parseFrom(
java.nio.ByteBuffer data,
com.google.protobuf.ExtensionRegistryLite extensionRegistry)
throws com.google.protobuf.InvalidProtocolBufferException {
return PARSER.parseFrom(data, extensionRegistry);
}
public static com.example.washing02app.models.BspError.ErrorData parseFrom(
com.google.protobuf.ByteString data)
throws com.google.protobuf.InvalidProtocolBufferException {
return PARSER.parseFrom(data);
}
public static com.example.washing02app.models.BspError.ErrorData parseFrom(
com.google.protobuf.ByteString data,
com.google.protobuf.ExtensionRegistryLite extensionRegistry)
throws com.google.protobuf.InvalidProtocolBufferException {
return PARSER.parseFrom(data, extensionRegistry);
}
public static com.example.washing02app.models.BspError.ErrorData parseFrom(byte[] data)
throws com.google.protobuf.InvalidProtocolBufferException {
return PARSER.parseFrom(data);
}
public static com.example.washing02app.models.BspError.ErrorData parseFrom(
byte[] data,
com.google.protobuf.ExtensionRegistryLite extensionRegistry)
throws com.google.protobuf.InvalidProtocolBufferException {
return PARSER.parseFrom(data, extensionRegistry);
}
public static com.example.washing02app.models.BspError.ErrorData parseFrom(java.io.InputStream input)
throws java.io.IOException {
return com.google.protobuf.GeneratedMessage
.parseWithIOException(PARSER, input);
}
public static com.example.washing02app.models.BspError.ErrorData parseFrom(
java.io.InputStream input,
com.google.protobuf.ExtensionRegistryLite extensionRegistry)
throws java.io.IOException {
return com.google.protobuf.GeneratedMessage
.parseWithIOException(PARSER, input, extensionRegistry);
}
public static com.example.washing02app.models.BspError.ErrorData parseDelimitedFrom(java.io.InputStream input)
throws java.io.IOException {
return com.google.protobuf.GeneratedMessage
.parseDelimitedWithIOException(PARSER, input);
}
public static com.example.washing02app.models.BspError.ErrorData parseDelimitedFrom(
java.io.InputStream input,
com.google.protobuf.ExtensionRegistryLite extensionRegistry)
throws java.io.IOException {
return com.google.protobuf.GeneratedMessage
.parseDelimitedWithIOException(PARSER, input, extensionRegistry);
}
public static com.example.washing02app.models.BspError.ErrorData parseFrom(
com.google.protobuf.CodedInputStream input)
throws java.io.IOException {
return com.google.protobuf.GeneratedMessage
.parseWithIOException(PARSER, input);
}
public static com.example.washing02app.models.BspError.ErrorData parseFrom(
com.google.protobuf.CodedInputStream input,
com.google.protobuf.ExtensionRegistryLite extensionRegistry)
throws java.io.IOException {
return com.google.protobuf.GeneratedMessage
.parseWithIOException(PARSER, input, extensionRegistry);
}
@java.lang.Override
public Builder newBuilderForType() { return newBuilder(); }
public static Builder newBuilder() {
return DEFAULT_INSTANCE.toBuilder();
}
public static Builder newBuilder(com.example.washing02app.models.BspError.ErrorData prototype) {
return DEFAULT_INSTANCE.toBuilder().mergeFrom(prototype);
}
@java.lang.Override
public Builder toBuilder() {
return this == DEFAULT_INSTANCE
? new Builder() : new Builder().mergeFrom(this);
}
@java.lang.Override
protected Builder newBuilderForType(
com.google.protobuf.GeneratedMessage.BuilderParent parent) {
Builder builder = new Builder(parent);
return builder;
}
/**
* Protobuf type {@code ErrorData}
*/
public static final class Builder extends
com.google.protobuf.GeneratedMessage.Builder<Builder> implements
// @@protoc_insertion_point(builder_implements:ErrorData)
com.example.washing02app.models.BspError.ErrorDataOrBuilder {
public static final com.google.protobuf.Descriptors.Descriptor
getDescriptor() {
return com.example.washing02app.models.BspError.internal_static_ErrorData_descriptor;
}
@java.lang.Override
protected com.google.protobuf.GeneratedMessage.FieldAccessorTable
internalGetFieldAccessorTable() {
return com.example.washing02app.models.BspError.internal_static_ErrorData_fieldAccessorTable
.ensureFieldAccessorsInitialized(
com.example.washing02app.models.BspError.ErrorData.class, com.example.washing02app.models.BspError.ErrorData.Builder.class);
}
// Construct using com.example.washing02app.models.BspError.ErrorData.newBuilder()
private Builder() {
}
private Builder(
com.google.protobuf.GeneratedMessage.BuilderParent parent) {
super(parent);
}
@java.lang.Override
public Builder clear() {
super.clear();
bitField0_ = 0;
comErrorCode_ = 0;
leftMotorErrorCode_ = 0;
rightMotorErrorCode_ = 0;
return this;
}
@java.lang.Override
public com.google.protobuf.Descriptors.Descriptor
getDescriptorForType() {
return com.example.washing02app.models.BspError.internal_static_ErrorData_descriptor;
}
@java.lang.Override
public com.example.washing02app.models.BspError.ErrorData getDefaultInstanceForType() {
return com.example.washing02app.models.BspError.ErrorData.getDefaultInstance();
}
@java.lang.Override
public com.example.washing02app.models.BspError.ErrorData build() {
com.example.washing02app.models.BspError.ErrorData result = buildPartial();
if (!result.isInitialized()) {
throw newUninitializedMessageException(result);
}
return result;
}
@java.lang.Override
public com.example.washing02app.models.BspError.ErrorData buildPartial() {
com.example.washing02app.models.BspError.ErrorData result = new com.example.washing02app.models.BspError.ErrorData(this);
if (bitField0_ != 0) { buildPartial0(result); }
onBuilt();
return result;
}
private void buildPartial0(com.example.washing02app.models.BspError.ErrorData result) {
int from_bitField0_ = bitField0_;
if (((from_bitField0_ & 0x00000001) != 0)) {
result.comErrorCode_ = comErrorCode_;
}
if (((from_bitField0_ & 0x00000002) != 0)) {
result.leftMotorErrorCode_ = leftMotorErrorCode_;
}
if (((from_bitField0_ & 0x00000004) != 0)) {
result.rightMotorErrorCode_ = rightMotorErrorCode_;
}
}
@java.lang.Override
public Builder mergeFrom(com.google.protobuf.Message other) {
if (other instanceof com.example.washing02app.models.BspError.ErrorData) {
return mergeFrom((com.example.washing02app.models.BspError.ErrorData)other);
} else {
super.mergeFrom(other);
return this;
}
}
public Builder mergeFrom(com.example.washing02app.models.BspError.ErrorData other) {
if (other == com.example.washing02app.models.BspError.ErrorData.getDefaultInstance()) return this;
if (other.getComErrorCode() != 0) {
setComErrorCode(other.getComErrorCode());
}
if (other.getLeftMotorErrorCode() != 0) {
setLeftMotorErrorCode(other.getLeftMotorErrorCode());
}
if (other.getRightMotorErrorCode() != 0) {
setRightMotorErrorCode(other.getRightMotorErrorCode());
}
this.mergeUnknownFields(other.getUnknownFields());
onChanged();
return this;
}
@java.lang.Override
public final boolean isInitialized() {
return true;
}
@java.lang.Override
public Builder mergeFrom(
com.google.protobuf.CodedInputStream input,
com.google.protobuf.ExtensionRegistryLite extensionRegistry)
throws java.io.IOException {
if (extensionRegistry == null) {
throw new java.lang.NullPointerException();
}
try {
boolean done = false;
while (!done) {
int tag = input.readTag();
switch (tag) {
case 0:
done = true;
break;
case 8: {
comErrorCode_ = input.readInt32();
bitField0_ |= 0x00000001;
break;
} // case 8
case 16: {
leftMotorErrorCode_ = input.readInt32();
bitField0_ |= 0x00000002;
break;
} // case 16
case 24: {
rightMotorErrorCode_ = input.readInt32();
bitField0_ |= 0x00000004;
break;
} // case 24
default: {
if (!super.parseUnknownField(input, extensionRegistry, tag)) {
done = true; // was an endgroup tag
}
break;
} // default:
} // switch (tag)
} // while (!done)
} catch (com.google.protobuf.InvalidProtocolBufferException e) {
throw e.unwrapIOException();
} finally {
onChanged();
} // finally
return this;
}
private int bitField0_;
private int comErrorCode_ ;
/**
* <code>int32 Com_Error_Code = 1;</code>
* @return The comErrorCode.
*/
@java.lang.Override
public int getComErrorCode() {
return comErrorCode_;
}
/**
* <code>int32 Com_Error_Code = 1;</code>
* @param value The comErrorCode to set.
* @return This builder for chaining.
*/
public Builder setComErrorCode(int value) {
comErrorCode_ = value;
bitField0_ |= 0x00000001;
onChanged();
return this;
}
/**
* <code>int32 Com_Error_Code = 1;</code>
* @return This builder for chaining.
*/
public Builder clearComErrorCode() {
bitField0_ = (bitField0_ & ~0x00000001);
comErrorCode_ = 0;
onChanged();
return this;
}
private int leftMotorErrorCode_ ;
/**
* <code>int32 Left_Motor_Error_Code = 2;</code>
* @return The leftMotorErrorCode.
*/
@java.lang.Override
public int getLeftMotorErrorCode() {
return leftMotorErrorCode_;
}
/**
* <code>int32 Left_Motor_Error_Code = 2;</code>
* @param value The leftMotorErrorCode to set.
* @return This builder for chaining.
*/
public Builder setLeftMotorErrorCode(int value) {
leftMotorErrorCode_ = value;
bitField0_ |= 0x00000002;
onChanged();
return this;
}
/**
* <code>int32 Left_Motor_Error_Code = 2;</code>
* @return This builder for chaining.
*/
public Builder clearLeftMotorErrorCode() {
bitField0_ = (bitField0_ & ~0x00000002);
leftMotorErrorCode_ = 0;
onChanged();
return this;
}
private int rightMotorErrorCode_ ;
/**
* <code>int32 Right_Motor_Error_Code = 3;</code>
* @return The rightMotorErrorCode.
*/
@java.lang.Override
public int getRightMotorErrorCode() {
return rightMotorErrorCode_;
}
/**
* <code>int32 Right_Motor_Error_Code = 3;</code>
* @param value The rightMotorErrorCode to set.
* @return This builder for chaining.
*/
public Builder setRightMotorErrorCode(int value) {
rightMotorErrorCode_ = value;
bitField0_ |= 0x00000004;
onChanged();
return this;
}
/**
* <code>int32 Right_Motor_Error_Code = 3;</code>
* @return This builder for chaining.
*/
public Builder clearRightMotorErrorCode() {
bitField0_ = (bitField0_ & ~0x00000004);
rightMotorErrorCode_ = 0;
onChanged();
return this;
}
// @@protoc_insertion_point(builder_scope:ErrorData)
}
// @@protoc_insertion_point(class_scope:ErrorData)
private static final com.example.washing02app.models.BspError.ErrorData DEFAULT_INSTANCE;
static {
DEFAULT_INSTANCE = new com.example.washing02app.models.BspError.ErrorData();
}
public static com.example.washing02app.models.BspError.ErrorData getDefaultInstance() {
return DEFAULT_INSTANCE;
}
private static final com.google.protobuf.Parser<ErrorData>
PARSER = new com.google.protobuf.AbstractParser<ErrorData>() {
@java.lang.Override
public ErrorData parsePartialFrom(
com.google.protobuf.CodedInputStream input,
com.google.protobuf.ExtensionRegistryLite extensionRegistry)
throws com.google.protobuf.InvalidProtocolBufferException {
Builder builder = newBuilder();
try {
builder.mergeFrom(input, extensionRegistry);
} catch (com.google.protobuf.InvalidProtocolBufferException e) {
throw e.setUnfinishedMessage(builder.buildPartial());
} catch (com.google.protobuf.UninitializedMessageException e) {
throw e.asInvalidProtocolBufferException().setUnfinishedMessage(builder.buildPartial());
} catch (java.io.IOException e) {
throw new com.google.protobuf.InvalidProtocolBufferException(e)
.setUnfinishedMessage(builder.buildPartial());
}
return builder.buildPartial();
}
};
public static com.google.protobuf.Parser<ErrorData> parser() {
return PARSER;
}
@java.lang.Override
public com.google.protobuf.Parser<ErrorData> getParserForType() {
return PARSER;
}
@java.lang.Override
public com.example.washing02app.models.BspError.ErrorData getDefaultInstanceForType() {
return DEFAULT_INSTANCE;
}
}
private static final com.google.protobuf.Descriptors.Descriptor
internal_static_ErrorData_descriptor;
private static final
com.google.protobuf.GeneratedMessage.FieldAccessorTable
internal_static_ErrorData_fieldAccessorTable;
public static com.google.protobuf.Descriptors.FileDescriptor
getDescriptor() {
return descriptor;
}
private static com.google.protobuf.Descriptors.FileDescriptor
descriptor;
static {
java.lang.String[] descriptorData = {
"\n\017bsp_Error.proto\"b\n\tErrorData\022\026\n\016Com_Er" +
"ror_Code\030\001 \001(\005\022\035\n\025Left_Motor_Error_Code\030" +
"\002 \001(\005\022\036\n\026Right_Motor_Error_Code\030\003 \001(\005*\206\001" +
"\n\010ComError\022\r\n\tMK32_SBus\020\000\022\n\n\006TL720D\020\001\022\t\n" +
"\005Ti5_1\020\002\022\t\n\005Ti5_2\020\003\022\t\n\005Ti5_3\020\004\022\t\n\005Ti5_4\020" +
"\005\022\t\n\005Ti5_5\020\006\022\t\n\005Ti5_6\020\007\022\035\n\031Remote_Button" +
"_Reset_State\020\010B#\n\037com.example.washing02a" +
"pp.modelsP\000b\006proto3"
};
descriptor = com.google.protobuf.Descriptors.FileDescriptor
.internalBuildGeneratedFileFrom(descriptorData,
new com.google.protobuf.Descriptors.FileDescriptor[] {
});
internal_static_ErrorData_descriptor =
getDescriptor().getMessageTypes().get(0);
internal_static_ErrorData_fieldAccessorTable = new
com.google.protobuf.GeneratedMessage.FieldAccessorTable(
internal_static_ErrorData_descriptor,
new java.lang.String[] { "ComErrorCode", "LeftMotorErrorCode", "RightMotorErrorCode", });
descriptor.resolveAllFeaturesImmutable();
}
// @@protoc_insertion_point(outer_class_scope)
}

1606
app/src/main/java/com/example/washing02app/models/BspIV.java

File diff suppressed because it is too large

1162
app/src/main/java/com/example/washing02app/models/BspPV.java

File diff suppressed because it is too large

50
app/src/main/java/com/example/washing02app/models/DisplayIV.java

@ -0,0 +1,50 @@
package com.example.washing02app.models;
import androidx.databinding.BaseObservable;
public class DisplayIV extends BaseObservable {
private double leftCompensation;
private double rightCompensation;
private double currentAngle;
public double getLeftCompensation() {
return leftCompensation;
}
public void setLeftCompensation(double leftCompensation) {
this.leftCompensation = leftCompensation;
}
public double getRightCompensation() {
return rightCompensation;
}
public void setRightCompensation(double rightCompensation) {
this.rightCompensation = rightCompensation;
}
public double getCurrentAngle() {
return currentAngle;
}
public void setCurrentAngle(double currentAngle) {
this.currentAngle = currentAngle;
}
public double getRobotMoveSpeed() {
return robotMoveSpeed;
}
public void setRobotMoveSpeed(double robotMoveSpeed) {
this.robotMoveSpeed = robotMoveSpeed;
}
private double robotMoveSpeed;
public DisplayIV(double leftCompensation, double rightCompensation, double currentAngle, double robotMoveSpeed) {
this.leftCompensation = leftCompensation;
this.rightCompensation = rightCompensation;
this.currentAngle = currentAngle;
this.robotMoveSpeed = robotMoveSpeed;
}
}

38
app/src/main/java/com/example/washing02app/models/DisplayPV.java

@ -0,0 +1,38 @@
package com.example.washing02app.models;
import androidx.databinding.BaseObservable;
public class DisplayPV extends BaseObservable {
private int id;
private int laneChangeDistance;
private double verticalAdjust;
public DisplayPV(int id, int laneChangeDistance, double verticalAdjust) {
this.id = id;
this.laneChangeDistance=laneChangeDistance;
this.verticalAdjust=verticalAdjust;
}
public int getId() { return id; }
public void setId(int id) {
this.id = id;
}
public int getLaneChangeDistance() {
return laneChangeDistance;
}
public void setLaneChangeDistance(int laneChangeDistance) { this.laneChangeDistance = laneChangeDistance;}
public double getVerticalAdjust(){
return verticalAdjust;
}
public void setVerticalAdjust(int verticalAdjust) {
this.verticalAdjust = verticalAdjust;
}
}

44
app/src/main/java/com/example/washing02app/models/ErrorModel.java

@ -0,0 +1,44 @@
package com.example.washing02app.models;
public class ErrorModel {
public ErrorModel(long timeID, String errorInfo) {
this.timeID = timeID;
this.errorInfo = errorInfo;
}
private long timeID;
public void setDateTimeBJ(String dateTimeUTC) {
this.dateTimeBJ = dateTimeUTC;
}
private String errorInfo;
public String getDateTimeBJ() {
return dateTimeBJ;
}
private String dateTimeBJ;
@Override
public String toString() {
return String.valueOf(dateTimeBJ + errorInfo);
}
public void setTimeID(long timeID) {
this.timeID = timeID;
}
public void setErrorInfo(String errorInfo) {
this.errorInfo = errorInfo;
}
public long getTimeID() {
return timeID;
}
public String getErrorInfo() {
return errorInfo;
}
}

43
app/src/main/java/com/example/washing02app/models/ScrollBottomScrollView.java

@ -0,0 +1,43 @@
package com.example.washing02app.models;
import android.content.Context;
import android.util.AttributeSet;
import android.view.View;
import android.widget.ScrollView;
public class ScrollBottomScrollView extends ScrollView {
private OnScrollBottomListener listener;
private int calCount;
public interface OnScrollBottomListener {
void scrollToBottom();
}
public void onScrollViewScrollToBottom(OnScrollBottomListener l) {
listener = l;
}
public void unRegisterOnScrollViewScrollToBottom() {
listener = null;
}
public ScrollBottomScrollView(Context context, AttributeSet attrs) {
super(context, attrs);
}
@Override
protected void onScrollChanged(int l, int t, int oldl, int oldt) {
View view = this.getChildAt(0);
if (this.getHeight() + this.getScrollY() == view.getHeight()) {
calCount++;
if (calCount == 1) {
if (listener != null) {
listener.scrollToBottom();
}
}
} else {
calCount = 0;
}
}
}

26
app/src/main/java/com/example/washing02app/services/ConvertHelper.java

@ -0,0 +1,26 @@
package com.example.washing02app.services;
import android.widget.EditText;
import android.widget.TextView;
public class ConvertHelper {
public static int convertEditTextToInt(TextView editText) {
// 获取 EditText 中的文本
String input = editText.getText().toString().trim();
try {
// 尝试将字符串转换为整数
return Integer.parseInt(input);
} catch (NumberFormatException e) {
// 输入不是有效的整数格式,返回 -1 表示转换失败
return -1;
}
}
public static boolean isEditTextNullOrEmpty(EditText editText) {
String str = String.valueOf(editText.getText());
return str == null || str.isEmpty();
}
}

22
app/src/main/java/com/example/washing02app/services/CustomProber.java

@ -0,0 +1,22 @@
package com.example.washing02app.services;
import com.hoho.android.usbserial.driver.FtdiSerialDriver;
import com.hoho.android.usbserial.driver.ProbeTable;
import com.hoho.android.usbserial.driver.UsbSerialProber;
/**
* add devices here, that are not known to DefaultProber
*
* if the App should auto start for these devices, also
* add IDs to app/src/main/res/xml/device_filter.xml
*/
public class CustomProber {
public static UsbSerialProber getCustomProber() {
ProbeTable customTable = new ProbeTable();
customTable.addProduct(0x1234, 0x0001, FtdiSerialDriver.class); // e.g. device with custom VID+PID
customTable.addProduct(0x1234, 0x0002, FtdiSerialDriver.class); // e.g. device with custom VID+PID
return new UsbSerialProber(customTable);
}
}

71
app/src/main/java/com/example/washing02app/services/DecimalDigitsInputFilter.java

@ -0,0 +1,71 @@
package com.example.washing02app.services;
import android.text.InputFilter;
import android.text.Spanned;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/*
自定义 InputFilter 类,用于限制输入格式
支持整数、负数和最多一位小数的输入
使用方法:editText.setFilters(new InputFilter[]{new DecimalDigitsInputFilter()});
*/
public class DecimalDigitsInputFilter implements InputFilter {
// 最终验证的正则表达式
private final Pattern mFinalPattern;
// 中间状态允许的正则表达式
private final Pattern mIntermediatePattern;
public DecimalDigitsInputFilter() {
// 最终验证:必须是完整的数字格式
mFinalPattern = Pattern.compile("^-?(0|[1-9]\\d*)(\\.\\d)?$");
// 中间状态:允许临时的不完整格式(如 "-"、"0."、"-2.")
mIntermediatePattern = Pattern.compile("^-?(0|[1-9]\\d*)?(\\.)?$");
}
@Override
public CharSequence filter(CharSequence source, int start, int end, Spanned dest, int dstart, int dend) {
// 处理删除操作
if (end - start == 0) {
return null;
}
// 拼接新的输入内容
String newText = dest.toString().substring(0, dstart) +
source.toString().substring(start, end) +
dest.toString().substring(dend);
// 允许空字符串或单独的负号
if (newText.isEmpty() || newText.equals("-")) {
return null;
}
// 防止前导零(除非是 0 或 0.x)
if (newText.startsWith("0") && newText.length() > 1 &&
!newText.startsWith("0.") && !newText.equals("0")) {
return "";
}
// 防止多个负号
if (newText.indexOf('-') > 0) {
return "";
}
// 防止多个小数点
if (newText.indexOf('.') != newText.lastIndexOf('.')) {
return "";
}
// 检查是否匹配最终模式或中间模式
Matcher finalMatcher = mFinalPattern.matcher(newText);
Matcher intermediateMatcher = mIntermediatePattern.matcher(newText);
if (finalMatcher.matches() || intermediateMatcher.matches()) {
return null; // 匹配成功,允许输入
}
return ""; // 匹配失败,阻止输入
}
}

58
app/src/main/java/com/example/washing02app/services/ErrorDeocdeHelper.java

@ -0,0 +1,58 @@
package com.example.washing02app.services;
import com.example.washing02app.models.BspError;
public class ErrorDeocdeHelper {
//private static Map<String, Integer> flagMap = new HashMap<>();
// public static void AddMap(String errorName, Integer bitPosition)
// {
// flagMap.put(errorName,bitPosition);
// }
private static String ErrorResult;
private static String addErrorResult;
public static String ErrorDeocde(int data)
{
ErrorResult="";
// 循环遍历 Map
for (BspError.ComError err : BspError.ComError.values()) {
int bitPosiiton = err.ordinal();
// if (err.toString().equals("UNRECOGNIZED")) continue;
// if (err.toString().equals("TL720D"))
// addErrorResult = " 作业模式已切换至手动";
// else
// addErrorResult = " ";
//
// if (err.toString().equals("MK32_InitialState"))
// addErrorResult = " 遥控器按键未复位";
// else
// addErrorResult = " ";
// 使用左移操作生成要检查的标志位
int bitToCheck = 1 << bitPosiiton;
// 判断该位置是否有对应的标志位
if ((data & bitToCheck) != 0)
{
// ErrorResult += String.valueOf(bitPosiiton);
if (err.toString().equals("Remote_Button_Reset_State"))
{
ErrorResult = "未复位" ;
}
// else
// {
// ErrorResult += err.toString()+addErrorResult+"\t";
// }
}
}
return ErrorResult;
}
}

57
app/src/main/java/com/example/washing02app/services/LineOverlayView.java

@ -0,0 +1,57 @@
package com.example.washing02app.services;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.util.AttributeSet;
import android.view.View;
public class LineOverlayView extends View {
private Paint paint;
// 两条线的位置(百分比)
private float line1Percent = 0.3f;
private float line2Percent = 0.7f;
public LineOverlayView(Context context) {
super(context);
init();
}
public LineOverlayView(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
private void init() {
paint = new Paint();
paint.setColor(Color.RED);
paint.setStrokeWidth(5);
paint.setAntiAlias(true);
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
int width = getWidth();
int height = getHeight();
float y1 = height * line1Percent;
float y2 = height * line2Percent;
// 第一条水平线
canvas.drawLine(0, y1, width, y1, paint);
// 第二条水平线
canvas.drawLine(0, y2, width, y2, paint);
}
public void setLinePosition(float p1, float p2) {
line1Percent = p1;
line2Percent = p2;
invalidate();
}
}

39
app/src/main/java/com/example/washing02app/services/LogUtil.java

@ -0,0 +1,39 @@
package com.example.washing02app.services;
import android.util.Log;
public class LogUtil {
private String TAG;
private boolean isRelease = false;
private boolean isDebug;
public LogUtil(Class c, boolean isDebug) {
this.TAG = c.getName();
this.isDebug = isDebug;
}
public void d(String msg) {
if (!isRelease && isDebug) {
Log.d(TAG, "--------->" + msg);
}
}
public void i(String msg) {
if (!isRelease && isDebug) {
Log.i(TAG, "--------->" + msg);
}
}
public void w(String msg) {
if (!isRelease && isDebug) {
Log.w(TAG, "--------->" + msg);
}
}
public void e(String msg) {
if (!isRelease && isDebug) {
Log.e(TAG, "--------->" + msg);
}
}
}

72
app/src/main/java/com/example/washing02app/services/ModbusCRC.java

@ -0,0 +1,72 @@
package com.example.washing02app.services;
public class ModbusCRC {
// /**
// * 一个字节包含位的数量 8
// */
// private static final int BITS_OF_BYTE = 8;
// /**
// * 多项式
// */
// private static final int POLYNOMIAL = 0xA001;
// /**
// * 初始值
// */
// private static final int INITIAL_VALUE = 0xFFFF;
//
// /**
// * CRC16 编码
// *
// * @param bytes 编码内容
// * @return 编码结果
// */
// public static int crc16(byte[] bytes) {
// int res = INITIAL_VALUE;
// for (int data : bytes) {
// res = res ^ data;
// for (int i = 0; i < BITS_OF_BYTE; i++) {
// res = (res & 0x0001) == 1 ? (res >> 1) ^ POLYNOMIAL : res >> 1;
// }
// }
// return revert(res);
// }
//
// /**
// * 翻转16位的高八位和低八位字节
// *
// * @param src 翻转数字
// * @return 翻转结果
// */
// private static int revert(int src) {
// int lowByte = (src & 0xFF00) >> 8;
// int highByte = (src & 0x00FF) << 8;
// return lowByte | highByte;
// }
/**
* 计算 Modbus CRC 校验值
* @param data 要计算校验值的字节数组
* @return CRC 校验值,以 2 字节的数组形式返回
*/
public static byte[] calculateCRC(byte[] data) {
int crc = 0xFFFF;
for (byte b : data) {
crc ^= (b & 0xFF);
for (int i = 0; i < 8; i++) {
if ((crc & 0x0001) != 0) {
crc >>= 1;
crc ^= 0xA001;
} else {
crc >>= 1;
}
}
}
// 将 CRC 结果拆分为两个字节
byte[] crcBytes = new byte[2];
crcBytes[0] = (byte) (crc & 0xFF);
crcBytes[1] = (byte) ((crc >> 8) & 0xFF);
return crcBytes;
}
}

222
app/src/main/java/com/example/washing02app/services/MyDataHelper.java

@ -0,0 +1,222 @@
package com.example.washing02app.services;
import android.annotation.SuppressLint;
import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
import android.util.Log;
import androidx.annotation.Nullable;
import com.example.washing02app.models.DisplayPV;
import com.example.washing02app.models.ErrorModel;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.TimeZone;
public class MyDataHelper extends SQLiteOpenHelper {
public static final String COLUMN_ID = "id";
public static final String TABLE_NAME = "information";
public static final String COLUMN_LANCE_CHANGE_DISTANCE = "lanceChangeDistance";
public static final String COLUMN_VERTICAL_CALIBRATION = "verticalCalibration";
public static final String Error_TABLE_NAME = "error";
public static final String Error_COLUMN_Iime_ID = "timeID";
public static final String Error_COLUMN_ERROR_INFO = "errorInfo";
List<ErrorModel> robotErrorList = new ArrayList<>() ;
public MyDataHelper(@Nullable Context context) {
super(context, "bingRobot.db", null, 2);
}
@SuppressLint("SQLiteString")
@Override
public void onCreate(SQLiteDatabase db) {
String sql = "CREATE TABLE " + TABLE_NAME + "(" + COLUMN_ID + " INTEGER PRIMARY KEY ," +
COLUMN_LANCE_CHANGE_DISTANCE + " INTEGER," +
COLUMN_VERTICAL_CALIBRATION + " DOUBLE" +
")";
db.execSQL(sql);
sql = "CREATE TABLE " + Error_TABLE_NAME + "(" + Error_COLUMN_Iime_ID + " INTEGER PRIMARY KEY ," +
Error_COLUMN_ERROR_INFO + " STRING " + ")";
db.execSQL(sql);
}
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
db.execSQL("DROP TABLE IF EXISTS " + TABLE_NAME);
db.execSQL("DROP TABLE IF EXISTS " + Error_TABLE_NAME);
onCreate(db);
}
//增 删 改 查
public String addOrUpdateDisplayData(DisplayPV pv) {
ContentValues cv = new ContentValues();
cv.put(COLUMN_ID, pv.getId());
cv.put(COLUMN_LANCE_CHANGE_DISTANCE, pv.getLaneChangeDistance());
cv.put(COLUMN_VERTICAL_CALIBRATION, pv.getVerticalAdjust());
SQLiteDatabase sqliteDatabase = this.getWritableDatabase();
long insert = sqliteDatabase.insertWithOnConflict(TABLE_NAME, null, cv, SQLiteDatabase.CONFLICT_REPLACE);
sqliteDatabase.close();
if (insert == -1) {
return "failed";
}
return "success";
}
public String deleteAll() {
SQLiteDatabase sqLiteDatabase = this.getWritableDatabase();
int delete = sqLiteDatabase.delete(TABLE_NAME, null,
null);
sqLiteDatabase.close();
if (delete == 0) {
return "failed";
}
return "success";
}
public void IntializeDataBase() {
for (int i = 1; i < 6; i++) {
List<DisplayPV> list = getDisplayData(i);
if (list.isEmpty()) {
DisplayPV pv = new DisplayPV(i, 1, 0);
addOrUpdateDisplayData(pv);
}
}
}
public List<DisplayPV> getDisplayData(int id) {
List<DisplayPV> list = new ArrayList<>();
String sql = "SELECT * FROM " + TABLE_NAME + " WHERE " + COLUMN_ID + " = " + String.valueOf(id);
SQLiteDatabase sqLiteDatabase = this.getWritableDatabase();
Cursor cursor = sqLiteDatabase.rawQuery(sql, null);
int idIndex = cursor.getColumnIndex(COLUMN_ID);
int _laneChangeDistanceIndex = cursor.getColumnIndex(COLUMN_LANCE_CHANGE_DISTANCE);
int _vertical_calibraton = cursor.getColumnIndex(COLUMN_VERTICAL_CALIBRATION);
while (cursor.moveToNext()) {
DisplayPV pv = new DisplayPV(cursor.getInt(idIndex),
cursor.getInt(_laneChangeDistanceIndex), cursor.getDouble(_vertical_calibraton)
);
list.add(pv);
}
cursor.close();
sqLiteDatabase.close();
return list;
}
public String AddOrUpdateErrorModel(ErrorModel em) {
ContentValues cv = new ContentValues();
cv.put(Error_COLUMN_Iime_ID, em.getTimeID());
cv.put(Error_COLUMN_ERROR_INFO, em.getErrorInfo());
SQLiteDatabase sqliteDatabase = this.getWritableDatabase();
long insert = sqliteDatabase.insertWithOnConflict(Error_TABLE_NAME, null, cv, SQLiteDatabase.CONFLICT_REPLACE);
// ===================== 核心逻辑 =====================
// 数据太多 → 删200行
try {
Cursor cursor = sqliteDatabase.rawQuery("SELECT COUNT(*) FROM " + Error_TABLE_NAME, null);
int count = 0;
if (cursor.moveToFirst()) {
count = cursor.getInt(0);
}
cursor.close();
//数据超过 500 条,就删除最早的 200 条
if (count > 100) {
sqliteDatabase.beginTransaction();
String deleteQuery = "DELETE FROM " + Error_TABLE_NAME
+ " WHERE " + Error_COLUMN_Iime_ID
+ " IN (SELECT " + Error_COLUMN_Iime_ID
+ " FROM " + Error_TABLE_NAME
+ " ORDER BY " + Error_COLUMN_Iime_ID + " ASC LIMIT 50)";
sqliteDatabase.execSQL(deleteQuery);
sqliteDatabase.setTransactionSuccessful();
sqliteDatabase.endTransaction();
Log.d("数据库", "数据太多,已删除最早200条");
}
} catch (Exception e) {
e.printStackTrace();
}
// ========================================================
sqliteDatabase.close();
return insert == -1 ? "failed" : "success";
}
public String DeleteAllErrorModels() {
SQLiteDatabase sqLiteDatabase = this.getWritableDatabase();
int delete = sqLiteDatabase.delete(Error_TABLE_NAME, null,
null);
sqLiteDatabase.close();
if (delete == 0) {
return "failed";
}
return "success";
}
public List<ErrorModel> GetAllErrorModels() {
List<ErrorModel> list = new ArrayList<>();
String sql = "SELECT * FROM " + Error_TABLE_NAME;
SQLiteDatabase sqLiteDatabase = this.getWritableDatabase();
Cursor cursor = sqLiteDatabase.rawQuery(sql, null);
int _time_id_Index = cursor.getColumnIndex(Error_COLUMN_Iime_ID);
int _error_Index = cursor.getColumnIndex(Error_COLUMN_ERROR_INFO);
while (cursor.moveToNext()) {
ErrorModel em = new ErrorModel(cursor.getLong(_time_id_Index),cursor.getString(_error_Index));
Date date = new Date(em.getTimeID()); // 将时间戳转换为Date对象
// 创建SimpleDateFormat实例,并设置时区为UTC
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
sdf.setTimeZone(TimeZone.getTimeZone("Asia/Shanghai")); // 设置为UTC时区
// 格式化日期
String utcTime = sdf.format(date);
// System.out.println("UTC时间: " + utcTime);
em.setDateTimeBJ(utcTime);
list.add(em);
}
cursor.close();
sqLiteDatabase.close();
return list;
}
}

176
app/src/main/java/com/example/washing02app/services/PopupHelper.java

@ -0,0 +1,176 @@
package com.example.washing02app.services;
import android.app.Dialog;
import android.text.method.ScrollingMovementMethod;
import android.view.View;
import android.widget.Button;
import android.widget.RadioButton;
import android.widget.RadioGroup;
import android.widget.ScrollView;
import android.widget.TextView;
import android.widget.Toast;
import com.example.washing02app.MainActivity;
import com.example.washing02app.R;
import com.example.washing02app.models.ErrorModel;
import com.example.washing02app.models.ScrollBottomScrollView;
import java.util.List;
import java.util.Objects;
public class PopupHelper {
String manual_Mode_Call_Value = "无";
String work_Mode_Call_Temp;
String result="1";
private final MainActivity mainActivity;
public PopupHelper(MainActivity mainActivity)
{
this.mainActivity = mainActivity;
}
public void WorkModePopUp(View.OnClickListener context) {
Dialog dialog = new Dialog(mainActivity);
dialog.setContentView(R.layout.workmodepopup); // 设置自定义布局
dialog.setCancelable(true); // 设置点击外部是否关闭弹窗
// 获取布局中的视图
Button cancelButton = dialog.findViewById(R.id.manualModeCancel);
Button confirmButton = dialog.findViewById(R.id.manualModeModeApply);
// 设置取消按钮点击事件
cancelButton.setOnClickListener(v -> {
Toast.makeText(mainActivity, "点击了取消", Toast.LENGTH_SHORT).show();
dialog.dismiss(); // 关闭弹窗
});
// 设置单选按钮点击事件
RadioGroup radioGroup = dialog.findViewById(R.id.manualModeSelectorGroup);
radioGroup.setOnCheckedChangeListener(new RadioGroup.OnCheckedChangeListener() {
@Override
public void onCheckedChanged(RadioGroup group, int checkedId) {
RadioButton radioButton = (RadioButton) group.findViewById(checkedId);
work_Mode_Call_Temp = radioButton.getText().toString();
}
});
String ii = (mainActivity._Work_Mode_Call_Value);
switch (ii)
{
case "无": {
radioGroup.check(R.id.rb_one);
break;
}
case "清洗": {
radioGroup.check(R.id.rb_two);
break;
}
case "刷洗": {
radioGroup.check(R.id.rb_three);
break;
}
case "喷漆": {
radioGroup.check(R.id.rb_four);
break;
}
}
// 设置确定按钮点击事件
confirmButton.setOnClickListener(v -> {
mainActivity._Work_Mode_Call_Value = work_Mode_Call_Temp;
mainActivity.mainBinding.workModeDisplay.setText(mainActivity._Work_Mode_Call_Value);
Toast.makeText(mainActivity, "设置成功", Toast.LENGTH_SHORT).show();
dialog.dismiss(); // 关闭弹窗
});
dialog.show(); // 显示弹窗
}
public void RobotErrorListPopUp(View.OnClickListener context)
{
Dialog dialog = new Dialog(mainActivity);
dialog.setContentView(R.layout.log_item); // 设置自定义布局
dialog.setCancelable(true); // 设置点击外部是否关闭弹窗
TextView LogText = dialog.findViewById(R.id.popUpErrorLogTextView);
ScrollBottomScrollView LogScrollView = dialog.findViewById(R.id.popUpErrorLogScrollview);
List<ErrorModel> list = mainActivity.myDataHelper.GetAllErrorModels();
LogText.setMovementMethod(ScrollingMovementMethod.getInstance());
final int[] firstDisplay = {1};
final int[] display = {2};
final int[] displayOver = {0};
int displayNum = 29;
LogScrollView.post(new Runnable() {
@Override
public void run() {
if(firstDisplay[0] == 1){
//滑动顶部
LogScrollView.fullScroll(ScrollView.FOCUS_UP);
firstDisplay[0] = 0;
}
}
});
LogScrollView.onScrollViewScrollToBottom(new ScrollBottomScrollView.OnScrollBottomListener() {
@Override
public void scrollToBottom() {
//请求数据
if (!list.isEmpty()) {
if(list.size() > displayNum * display[0]) {
for(int i = list.size() - displayNum * (display[0]-1); i-- > list.size() - displayNum * display[0];){
ErrorModel item = list.get(i);
String RobotErrorLog = item.getDateTimeBJ() + item.getErrorInfo() +"\n";
LogText.append(RobotErrorLog);
}
display[0] ++;
}
else{
if(displayOver[0]==0){
for(int i = list.size() - displayNum * (display[0]-1); i-- > 0;){
ErrorModel item = list.get(i);
String RobotErrorLog = item.getDateTimeBJ() + item.getErrorInfo() +"\n";
LogText.append(RobotErrorLog);
displayOver[0]=1;
}
}
}
}
}});
if (!list.isEmpty()) {
if(list.size() > displayNum) {
for(int i = list.size(); i-- > list.size() - displayNum;){
ErrorModel item = list.get(i);
String RobotErrorLog = item.getDateTimeBJ() + item.getErrorInfo() +"\n";
LogText.append(RobotErrorLog);
}
}
else{
for(int i = list.size(); i-- > 0;){
ErrorModel item = list.get(i);
String RobotErrorLog = item.getDateTimeBJ() + item.getErrorInfo() +"\n";
LogText.append(RobotErrorLog);
}
}
}
// String list3 = mainActivity.myDataHelper.DeleteAllErrorModels();
dialog.show(); // 显示弹窗
}
}

302
app/src/main/java/com/example/washing02app/services/ReceiivedIVHandler.java

@ -0,0 +1,302 @@
package com.example.washing02app.services;
import static com.example.washing02app.services.ErrorDeocdeHelper.ErrorDeocde;
import static com.example.washing02app.services.USBSerialPortHelper.errorLast;
import static com.example.washing02app.services.USBSerialPortHelper.toHex4Digits;
import static com.example.washing02app.services.USBSerialPortHelper.unsignedIntToBinaryWithSeparator;
import android.graphics.Color;
import android.view.Gravity;
import android.widget.TextView;
import android.widget.Toast;
import com.example.washing02app.MainActivity;
import com.example.washing02app.R;
import com.example.washing02app.models.BspIV;
import com.example.washing02app.models.ErrorModel;
import com.google.protobuf.InvalidProtocolBufferException;
import java.util.Objects;
public class ReceiivedIVHandler {
// 心跳检测相关
public static long lastReceiveTime = System.currentTimeMillis(); // 最后一次收到数据的时间
public static final long TIME_OUT = 5000; // 超时时间:2秒没收到数据就算离线
public static boolean isAlarmDialogShowed = false; // 防止弹窗重复弹出
public static void midToast(String str, int showTime, com.example.washing02app.MainActivity MainActivity) {
Toast toast = Toast.makeText(MainActivity, str, showTime);
toast.setGravity(Gravity.CENTER_VERTICAL | Gravity.CENTER_HORIZONTAL, 0, 0); //设置显示位置
TextView v = (TextView) toast.getView().findViewById(android.R.id.message);
v.setTextColor(Color.YELLOW); //设置字体颜色
toast.show();
}
public static BspIV.IV_struct_define _toReceiveIV = BspIV.IV_struct_define.newBuilder().build();//上一次有效数据
public static BspIV.IV_struct_define _toReceiveIV_Variable = BspIV.IV_struct_define.newBuilder().build();//最新数据
public static void HandleData(com.example.washing02app.MainActivity MainActivity, byte[] data) {
try {
byte[] crcbytes = new byte[data.length - 2];
System.arraycopy(data, 0, crcbytes, 0, data.length - 2);
byte[] crc = ModbusCRC.calculateCRC(crcbytes);
// status(bytesToHex(data));
if (data[data.length - 2] == (byte) (crc[1] & 0xff) && data[data.length - 1] == (byte) (crc[0] & 0xff)) {
if ((data[0] == 0x55) && (data[1] == 0x55)) {
byte[] bytes = new byte[data.length - 4];
System.arraycopy(data, 2, bytes, 0, data.length - 4);
try {
lastReceiveTime = System.currentTimeMillis();
isAlarmDialogShowed = false; // 收到数据,重置弹窗标记
_toReceiveIV_Variable = BspIV.IV_struct_define.parseFrom(bytes);//单片机新数据到来
if (_toReceiveIV_Variable != null) {
if(_toReceiveIV_Variable.getIsRestart()==1)//单片机重启 将收到的时间戳归0
{
_toReceiveIV=_toReceiveIV.toBuilder().setTimeStamp(0).build();
// MainActivity._toSendPV=MainActivity._toSendPV.toBuilder().setIVIsRestartNotified(1).build();
}
//新数据的时间大于上次时间 将新数据赋值给上次数据
if (_toReceiveIV_Variable.getTimeStamp() >= _toReceiveIV.getTimeStamp()) {
_toReceiveIV = _toReceiveIV_Variable;
}
MainActivity.runOnUiThread(
() -> {
MainActivity.mainBinding.tvSpeedFrom32.setText(String.valueOf(_toReceiveIV.getRobotMoveSpeed()));
MainActivity.mainBinding.tvAngleFrom32.setText(String.valueOf((double) _toReceiveIV.getCurrentAngle() / 100));
int errorInt = _toReceiveIV.getSystemError();
String errorString2 = ErrorDeocde(errorInt);
String errorString = unsignedIntToBinaryWithSeparator(errorInt);
errorString += toHex4Digits(_toReceiveIV.getLeftFrontMotorErr());
errorString += toHex4Digits(_toReceiveIV.getRightFrontMotorErr());
errorString += toHex4Digits(_toReceiveIV.getLeftBackMotorErr());
errorString += toHex4Digits(_toReceiveIV.getRightBackMotorErr());
errorString += toHex4Digits(_toReceiveIV.getSwingMotorErr());
errorString += toHex4Digits(_toReceiveIV.getTiltMotorErr());
// String errorString = " # " + unsignedIntToBinaryWithSeparator(errorInt);
// errorString += " " + toHex4Digits(_toReceiveIV.getLeftFrontMotorErr());
// errorString += " " + toHex4Digits(_toReceiveIV.getRightFrontMotorErr());
// errorString += " " + toHex4Digits(_toReceiveIV.getLeftBackMotorErr());
//
// errorString += " " + toHex4Digits(_toReceiveIV.getRightBackMotorErr());
// errorString += " " + toHex4Digits(_toReceiveIV.getSwingMotorErr());
// errorString += " " + toHex4Digits(_toReceiveIV.getTiltMotorErr());
// 真正的错误 = (errorInt不是0 ) OR 电机有错误
boolean hasRealError =
(errorInt != 0 ) || _toReceiveIV.getLeftFrontMotorErr() != 0
|| _toReceiveIV.getLeftBackMotorErr() != 0
|| _toReceiveIV.getRightFrontMotorErr() != 0
|| _toReceiveIV.getRightBackMotorErr() != 0
|| _toReceiveIV.getSwingMotorErr() != 0
|| _toReceiveIV.getTiltMotorErr() != 0;
// 核心判断:只对真正错误变红
if (hasRealError) {
if (!Objects.equals(errorLast, errorString)) {
// 转换
String errorText = parseError(
errorInt,
_toReceiveIV.getLeftFrontMotorErr(),
_toReceiveIV.getRightFrontMotorErr(),
_toReceiveIV.getLeftBackMotorErr(),
_toReceiveIV.getRightBackMotorErr(),
_toReceiveIV.getSwingMotorErr(),
_toReceiveIV.getTiltMotorErr()
);
// 存数据库
ErrorModel em = new ErrorModel(System.currentTimeMillis(), errorText);
MainActivity.myDataHelper.AddOrUpdateErrorModel(em);
// ErrorModel em = new ErrorModel(System.currentTimeMillis(), errorString);
// MainActivity.myDataHelper.AddOrUpdateErrorModel(em);
if (Objects.equals(errorString2, "未复位")) {
MainActivity.mainBinding.mainViewErrMessageTxView.setText(String.valueOf(errorString2));
MainActivity.mainBinding.messageRounded.setBackgroundResource(R.drawable.message_rounded_rectangle_red);
} else {
MainActivity.mainBinding.mainViewErrMessageTxView.setText("通信故障");
MainActivity.mainBinding.messageRounded.setBackgroundResource(R.drawable.message_rounded_rectangle_red);
}
errorLast = errorString;
}
} else {
// 无错误 或 只有32/64 → 全部显示正常
errorLast = errorString;
MainActivity.mainBinding.mainViewErrMessageTxView.setText("无");
MainActivity.mainBinding.messageRounded.setBackgroundResource(R.drawable.message_rounded_rectangle);
}
if (_toReceiveIV.getIsWorking() == 1) {
MainActivity.mainBinding.messageRounded.setEnabled(false);
MainActivity.mainBinding.messageRounded.setAlpha(0.5f);
MainActivity.mainBinding.btnWorkMode.setEnabled(false);
MainActivity.mainBinding.btnWorkMode.setAlpha(0.5f);
MainActivity.mainBinding.jointSpeed1To32.setEnabled(false);
MainActivity.mainBinding.jointSpeed1To32.setAlpha(0.5f);
MainActivity.mainBinding.jointSpeed2To32.setEnabled(false);
MainActivity.mainBinding.jointSpeed2To32.setAlpha(0.5f);
MainActivity.mainBinding.forceSetingTo32.setEnabled(false);
MainActivity.mainBinding.forceSetingTo32.setAlpha(0.5f);
MainActivity.mainBinding.editLeftCompTo32.setEnabled(false);
MainActivity.mainBinding.editLeftCompTo32.setAlpha(0.5f);
MainActivity.mainBinding.editRightCompTo32.setEnabled(false);
MainActivity.mainBinding.editRightCompTo32.setAlpha(0.5f);
// MainActivity.mainBinding.mainViewErrMessageBtnPaint.setAlpha(0.5f);
}
else {
MainActivity.mainBinding.messageRounded.setEnabled(true);
MainActivity.mainBinding.messageRounded.setAlpha(1.0f);
MainActivity.mainBinding.btnWorkMode.setEnabled(true);
MainActivity.mainBinding.btnWorkMode.setAlpha(1.0f);
MainActivity.mainBinding.jointSpeed1To32.setEnabled(true);
MainActivity.mainBinding.jointSpeed1To32.setAlpha(1.0f);
MainActivity.mainBinding.jointSpeed2To32.setEnabled(true);
MainActivity.mainBinding.jointSpeed2To32.setAlpha(1.0f);
MainActivity.mainBinding.forceSetingTo32.setEnabled(true);
MainActivity.mainBinding.forceSetingTo32.setAlpha(1.0f);
MainActivity.mainBinding.editLeftCompTo32.setEnabled(true);
MainActivity.mainBinding.editLeftCompTo32.setAlpha(1.0f);
MainActivity.mainBinding.editRightCompTo32.setEnabled(true);
MainActivity.mainBinding.editRightCompTo32.setAlpha(1.0f);
//
// MainActivity.mainBinding.mainViewErrMessageBtnPaint.setAlpha(1.0f);
}
});
}
else { //_toReceiveIV != null
}
} catch (InvalidProtocolBufferException ex) {
}
} else { //校验
}
} else {//校验
//status("crc failed");
}
} catch (Exception e) {
}
}
public static String parseError(
int systemError,
int m1,
int m2,
int m3,
int m4,
int m5,
int m6)
{
StringBuilder sb = new StringBuilder();
// 通信故障(bit24~bit32)
String[] commErrors =
{
"sbus",
"720D",
"M1",
"M2",
"M3",
"M4",
"M5",
"M6",
"未复位"
};
for (int i = 0; i < 9; i++)
{
if ((systemError & (1 << i)) != 0)
{
if (sb.length() > 0)
{
sb.append("、");
}
sb.append(commErrors[i]);
}
}
// 电机报警码(直接显示数值)
appendMotorError(sb, "M1", m1);
appendMotorError(sb, "M2", m2);
appendMotorError(sb, "M3", m3);
appendMotorError(sb, "M4", m4);
appendMotorError(sb, "M5", m5);
appendMotorError(sb, "M6", m6);
if (sb.length() == 0)
{
return "无故障";
}
return sb.toString();
}
private static void appendMotorError(
StringBuilder sb,
String motorName,
int errorCode)
{
if (errorCode != 0)
{
if (sb.length() > 0)
{
sb.append("、");
}
sb.append(motorName)
.append(":")
.append(errorCode);
}
}
}

64
app/src/main/java/com/example/washing02app/services/RobotDataHanlder.java

@ -0,0 +1,64 @@
package com.example.washing02app.services;
import com.example.washing02app.models.BspIV;
import com.example.washing02app.models.BspPV;
import com.google.protobuf.InvalidProtocolBufferException;
public class RobotDataHanlder {
public static void test()
{
//byte[] data=hexToByteArray("080110830118313A04B1CBBACF");
byte[] data=hexToByteArray("100A180A28013A32B1CBBACF00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000");
}
public static void DeoodeDataFromRobot(byte[] data)
{
try
{
if(data[0]==0x55&&data[1]==0x55)
{
if (data[2]==0x01)
{
BspIV.IV_struct_define iv = BspIV.IV_struct_define.parseFrom(data);
}else if(data[2]==0x02)
{
BspPV.PV_struct_define pv = BspPV.PV_struct_define.parseFrom(data);
}
}
} catch (InvalidProtocolBufferException e)
{
}
}
public static byte[] hexToByteArray(String inHex){
int hexlen = inHex.length();
byte[] result;
if (hexlen % 2 == 1){
//奇数
hexlen++;
result = new byte[(hexlen/2)];
inHex="0"+inHex;
}else {
//偶数
result = new byte[(hexlen/2)];
}
int j=0;
for (int i = 0; i < hexlen; i+=2){
result[j]=hexToByte(inHex.substring(i,i+2));
j++;
}
return result;
}
public static byte hexToByte(String inHex){
return (byte)Integer.parseInt(inHex,16);
}
}

55
app/src/main/java/com/example/washing02app/services/ToggleRadioButton.java

@ -0,0 +1,55 @@
package com.example.washing02app.services;
import android.content.Context;
import android.util.AttributeSet;
import android.view.ViewParent;
import android.widget.RadioGroup;
import androidx.appcompat.widget.AppCompatRadioButton;
import com.example.washing02app.R;
/**********自己的raidobutton按钮类*************/
public class ToggleRadioButton extends AppCompatRadioButton {
public ToggleRadioButton(Context context) {
super(context);
}
public ToggleRadioButton(Context context, AttributeSet attrs) {
super(context, attrs);
}
public ToggleRadioButton(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
@Override
public boolean performClick() {
// 获取当前选中状态
boolean wasChecked = isChecked();
// 先让父类处理点击事件(这会触发正常的选中逻辑)
boolean result = super.performClick();
// 如果点击前已经是选中状态,说明用户想要取消选中
if (wasChecked) {
setChecked(false);
// 需要手动清除RadioGroup的选择状态
clearSelectionInParent();
}
return result;
}
/**
* 清除父RadioGroup中的选择状态
*/
private void clearSelectionInParent() {
ViewParent parent = getParent();
if (parent instanceof RadioGroup) {
((RadioGroup) parent).clearCheck();
}
}
}

89
app/src/main/java/com/example/washing02app/services/UDPHelper.java

@ -0,0 +1,89 @@
package com.example.washing02app.services;
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.util.logging.Handler;
public class UDPHelper {
private static com.example.washing02app.MainActivity MainActivity;
private static Thread receiveThread;
private static boolean running = false;
private static DatagramSocket sendSocket;
private static DatagramSocket receiveSocket;
private static Handler handler;// = new Handler(Looper.getMainLooper());
private static String target_ip;
private static int target_port;
private static int listening_port;
public static void Intialize(com.example.washing02app.MainActivity mainActivity, String targetip, int targetPort, int listentingPort) {
try {
MainActivity = mainActivity;
target_ip = targetip;
target_port = targetPort;
listening_port = listentingPort;
sendSocket = new DatagramSocket(10000);
//sendSocket.setBroadcast(true);
running = true;
receiveSocket = new DatagramSocket(listening_port);
receiveSocket.setBroadcast(true);
running = true;
receiveThread = new Thread(() -> {
byte[] buffer = new byte[1024];
DatagramPacket packet = new DatagramPacket(buffer, buffer.length);
while (running) {
try {
receiveSocket.receive(packet);
byte[] receivedArray = new byte[packet.getLength()];
System.arraycopy( packet.getData(), 0, receivedArray, 0, receivedArray.length);
ReceiivedIVHandler.HandleData(MainActivity, receivedArray);
} catch (IOException e) {
if (running) {
}
}
}
});
receiveThread.start();
} catch (IOException e) {
// tvOutput.setText("Socket error: " + e.getMessage());
}
}
public static void SendData(byte[] buffer) {
new Thread(() ->
{
DatagramSocket socket = null;
try {
InetAddress address = InetAddress.getByName(target_ip);
DatagramPacket packet = new DatagramPacket(buffer, buffer.length, address, target_port);
sendSocket.send(packet);
} catch (Exception e) {
}
}).start();
}
public static void Destroy() {
running = false;
if (receiveSocket != null && !receiveSocket.isClosed()) {
receiveSocket.close();
}
if (sendSocket != null && !sendSocket.isClosed()) {
sendSocket.close();
}
}
}

369
app/src/main/java/com/example/washing02app/services/USBSerialPortHelper.java

@ -0,0 +1,369 @@
package com.example.washing02app.services;
import android.annotation.SuppressLint;
import android.app.PendingIntent;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.hardware.usb.UsbDevice;
import android.hardware.usb.UsbDeviceConnection;
import android.hardware.usb.UsbManager;
import android.os.Build;
import android.os.CountDownTimer;
import android.os.Handler;
import android.os.Looper;
import androidx.core.content.ContextCompat;
import com.example.washing02app.BuildConfig;
import com.example.washing02app.MainActivity;
import com.example.washing02app.R;
import com.hoho.android.usbserial.driver.UsbSerialDriver;
import com.hoho.android.usbserial.driver.UsbSerialPort;
import com.hoho.android.usbserial.driver.UsbSerialProber;
import com.hoho.android.usbserial.util.SerialInputOutputManager;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
public class USBSerialPortHelper implements SerialInputOutputManager.Listener {
public USBSerialPortHelper(MainActivity mainActivity)
{
this.MainActivity=mainActivity;
}
private final MainActivity MainActivity;
//sserial port part start
private enum UsbPermission {Unknown, Requested, Granted, Denied}
private final String INTENT_ACTION_GRANT_USB = BuildConfig.APPLICATION_ID + ".GRANT_USB";
// <usb-device vendor-id="4292" product-id="60000" /> <!-- 0xea60: CP2102 and other CP210x single port devices -->
// <usb-device vendor-id="4292" product-id="60016" /> <!-- 0xea70: CP2105 -->
// <usb-device vendor-id="4292" product-id="60017" /> <!-- 0xea71: CP2108 -->
private int deviceId = 60000;
private int deviceId_test = 60000;
private int portNum;
private final int READ_WAIT_MILLIS = 100;
private String PortNameContians = "SILICON";/**/
// private static String PortNameContians="FTD";
private int baudRate = 57600;
private boolean withIoManager = true;
private BroadcastReceiver broadcastReceiver;
private Handler mainLooper;
private SerialInputOutputManager usbIoManager;
private UsbSerialPort usbSerialPort;
private UsbPermission usbPermission = UsbPermission.Unknown;
private boolean connected = false;
static String errorLast = "";
public void intialize() {
broadcastReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
if (INTENT_ACTION_GRANT_USB.equals(intent.getAction())) {
usbPermission = intent.getBooleanExtra(UsbManager.EXTRA_PERMISSION_GRANTED, false) ? UsbPermission.Granted : UsbPermission.Denied;
connect();
}
}
};
mainLooper = new Handler(Looper.getMainLooper());
_receiveBufferlist = new ArrayList<Byte>();
}
/*
* Serial
*/
@Override
public void onNewData(byte[] data) {
status("new data");
mainLooper.post(() -> {
receive(data);
// receive data
});
}
@Override
public void onRunError(Exception e) {
mainLooper.post(() -> {
status("connection lost: " + e.getMessage());
disconnect();
});
}
/*
* Serial + UI
*/
public void connect() {
UsbDevice device = null;
UsbManager usbManager = (UsbManager) MainActivity.getSystemService(Context.USB_SERVICE);
for (UsbDevice v : usbManager.getDeviceList().values()) {
status(v.getManufacturerName().toUpperCase());
if (v.getManufacturerName().toUpperCase().contains(PortNameContians)) {
device = v;
break;
}
}
if (device == null) {
// _serialPortSwitch.setChecked(false);
status("找不到设备");
return;
}
UsbSerialDriver driver = UsbSerialProber.getDefaultProber().probeDevice(device);
if (driver == null) {
driver = CustomProber.getCustomProber().probeDevice(device);
}
if (driver == null) {
// _serialPortSwitch.setChecked(false);
status("无驱动");
return;
}
if (driver.getPorts().size() < portNum) //就是0 cp2102 或者同一个驱动,第一个
{
status("connection failed: not enough ports at device");
status("找不到设备");
return;
}
usbSerialPort = driver.getPorts().get(portNum);
UsbDeviceConnection usbConnection = usbManager.openDevice(driver.getDevice());
if (usbConnection == null && usbPermission == UsbPermission.Unknown && !usbManager.hasPermission(driver.getDevice())) {
usbPermission = UsbPermission.Requested;
int flags = Build.VERSION.SDK_INT >= Build.VERSION_CODES.M ? PendingIntent.FLAG_MUTABLE : 0;
Intent intent = new Intent(INTENT_ACTION_GRANT_USB);
intent.setPackage(MainActivity.getPackageName());
PendingIntent usbPermissionIntent = PendingIntent.getBroadcast(MainActivity, 0, intent, flags);
usbManager.requestPermission(driver.getDevice(), usbPermissionIntent);
return;
}
if (usbConnection == null) {
if (!usbManager.hasPermission(driver.getDevice())) {
status("connection failed: permission denied");
} else {
status("connection failed: open failed");
}
return;
}
try {
usbSerialPort.open(usbConnection);
try {
usbSerialPort.setParameters(baudRate, 8, 1, UsbSerialPort.PARITY_NONE);
status("connected: ");
} catch (UnsupportedOperationException e) {
status("unsupport setparameters");
}
if (withIoManager) {
usbIoManager = new SerialInputOutputManager(usbSerialPort, this);
usbIoManager.setReadBufferSize(40960);
usbIoManager.setReadTimeout(READ_WAIT_MILLIS);
usbIoManager.start();
}
//status("connected");
connected = true;
// _serialPortSwitch.setChecked(true);
//switch set true
} catch (Exception e) {
status("connection failed: " + e.getMessage());
disconnect();
}
}
private void disconnect() {
connected = false;
if (usbIoManager != null) {
usbIoManager.setListener(null);
usbIoManager.stop();
}
usbIoManager = null;
try {
usbSerialPort.close();
} catch (IOException ignored) {
}
usbSerialPort = null;
}
List<Byte> _receiveBufferlist;
private static byte[] listTobyte(List<Byte> list) {
if (list == null || list.size() < 0) return null;
byte[] bytes = new byte[list.size()];
int i = 0;
Iterator<Byte> iterator = list.iterator();
while (iterator.hasNext()) {
bytes[i] = iterator.next();
i++;
}
return bytes;
}
boolean StartCountDown = false;
// byte _receivedData
private void receive(byte[] data) {
// status("read data");
for (int i = 0; i < data.length; i++) {
_receiveBufferlist.add(data[i]);
}
//decodeRceive(data);
if (!StartCountDown)//从收到第一个数据开始计时
{
StartCountDown = true;
new CountDownTimer(10, 5) {
public void onTick(long millisUntilFinished) {
}
public void onFinish() {
status("read finished");
decodeRceive(listTobyte(_receiveBufferlist));
_receiveBufferlist.clear();
StartCountDown = false;
}
}.start();
}
}
void status(String str) {
// SpannableStringBuilder spn = new SpannableStringBuilder(str+'\r'+'\n');
//
// // spn.append(getTime());
//
// spn.setSpan(new ForegroundColorSpan(MainActivity.getResources().getColor(R.color.colorAccent)), 0, spn.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
// receiveText.append(spn);
// mainBinding.roll.fullScroll(ScrollView.FOCUS_DOWN);
// MainActivity.mainBinding.message.setText(str);
}
/*
逐位检查并构建二进制字符串
*/
String unsignedIntToBinary(int value) {
StringBuilder sb = new StringBuilder(32);
for (int i = 7; i >= 0; i--) {
sb.append((value & (1 << i)) == 0 ? '0' : '1');
}
return sb.toString();
}
/*
逐位检查并构建二进制字符串 每4位添加一个分隔符
*/
public static String unsignedIntToBinaryWithSeparator(int value) {
StringBuilder sb = new StringBuilder(35);
for (int i = 8; i >= 0; i--) {
sb.append((value & (1 << i)) == 0 ? '0' : '1');
// if (i % 4 == 0 && i != 0) {
// sb.append(' '); // 每4位添加一个分隔符
// }
}
return sb.toString();
}
public static String toHex4Digits(int value) {
char[] hexChars = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'};
int low16Bits = value & 0xFFFF;
char[] result = new char[4];
result[0] = hexChars[(low16Bits >> 12) & 0xF];
result[1] = hexChars[(low16Bits >> 8) & 0xF];
result[2] = hexChars[(low16Bits >> 4) & 0xF];
result[3] = hexChars[low16Bits & 0xF];
return new String(result);
}
@SuppressLint("SetTextI18n")
private void decodeRceive(byte[] data) {
try {
ReceiivedIVHandler.HandleData(MainActivity, data);
} catch (Exception e) {
}
}
public static String bytesToHex(byte[] bytes) {
StringBuilder result = new StringBuilder();
for (byte b : bytes) {
result.append(String.format("%02X ", b & 0xFF));
}
return result.toString();
}
public void onStart() {
ContextCompat.registerReceiver(MainActivity, broadcastReceiver, new IntentFilter(INTENT_ACTION_GRANT_USB), ContextCompat.RECEIVER_NOT_EXPORTED);
status("onStart");
}
public void onStop() {
MainActivity.unregisterReceiver(broadcastReceiver);
status("onStop");
}
public void onResume() {
if (!connected && (usbPermission == UsbPermission.Unknown || usbPermission == UsbPermission.Granted)) {
mainLooper.post(this::connect);
}
}
public void onPause() {
if (connected) {
status("串口断开");
// _serialPortSwitch.setChecked(false);
disconnect();
}
}
public void SendData(byte[] data) {
if (connected) {
try {
int WRITE_WAIT_MILLIS = 500;
usbSerialPort.write(data, WRITE_WAIT_MILLIS);
} catch (IOException e)
{
status("Send Failed");
connected = false;
}
} else {
status("usb serialport disconnected");
}
}
}

47
app/src/main/java/com/example/washing02app/services/VideoPlayerHelper.java

@ -0,0 +1,47 @@
package com.example.washing02app.services;
import cn.nodemedia.NodePlayer;
import cn.nodemedia.NodePlayerView;
public class VideoPlayerHelper {
public static void startVedio(NodePlayerView nodePlayerView, NodePlayer nodePlayer,String address ){
nodePlayerView.setRenderType(NodePlayerView.RenderType.TEXTUREVIEW);
//nodePlayerView.setRenderType(NodePlayerView.RenderType.SURFACEVIEW);//设置渲染器类型
nodePlayerView.setRotation(180); // 1号 不注释 2号不注释
nodePlayerView.setUIViewContentMode(NodePlayerView.UIViewContentMode.ScaleToFill);//设置视频画面缩放模式
//nodePlayer=new NodePlayer(this);
nodePlayer.setPlayerView(nodePlayerView);//设置播放视图
//设置RTSP流使用的传输协议,支持的模式有:
nodePlayer.setRtspTransport(NodePlayer.RTSP_TRANSPORT_TCP);//设置传输
nodePlayer.setInputUrl(address);
nodePlayer.setVideoEnable(true);//设置视频启用
nodePlayer.setBufferTime(100);//设置缓冲时间
nodePlayer.setMaxBufferTime(200);//设置最大缓冲时间
nodePlayer.start();
}
public static void startVedio1(NodePlayerView nodePlayerView, NodePlayer nodePlayer,String address ){
nodePlayerView.setRenderType(NodePlayerView.RenderType.TEXTUREVIEW);
//nodePlayerView.setRenderType(NodePlayerView.RenderType.SURFACEVIEW);//设置渲染器类型
//nodePlayerView.setRotation(180); // 1号 不注释 2号不注释
nodePlayerView.setUIViewContentMode(NodePlayerView.UIViewContentMode.ScaleToFill);//设置视频画面缩放模式
//nodePlayer=new NodePlayer(this);
nodePlayer.setPlayerView(nodePlayerView);//设置播放视图
//设置RTSP流使用的传输协议,支持的模式有:
nodePlayer.setRtspTransport(NodePlayer.RTSP_TRANSPORT_TCP);//设置传输
nodePlayer.setInputUrl(address);
nodePlayer.setVideoEnable(true);//设置视频启用
nodePlayer.setBufferTime(100);//设置缓冲时间
nodePlayer.setMaxBufferTime(200);//设置最大缓冲时间
nodePlayer.start();
}
}

11
app/src/main/java/com/example/washing02app/viewmodels/MainViewModel.java

@ -0,0 +1,11 @@
package com.example.washing02app.viewmodels;
import androidx.lifecycle.ViewModel;
public class MainViewModel extends ViewModel {
public MainViewModel() {
}
}

2
app/src/main/java/generate_java.bat

@ -0,0 +1,2 @@
protoc --java_out . *.proto
pause

BIN
app/src/main/java/protoc.7z

Binary file not shown.

BIN
app/src/main/java/protoc.exe

Binary file not shown.

25
app/src/main/res/drawable/background.xml

@ -0,0 +1,25 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<!-- 设置透明背景色 -->
<!-- <solid android:color="@color/gainsboro" />-->
<solid android:color="#f2f3f4" />
<!-- 设置一个黑色边框 -->
<!-- <stroke-->
<!-- android:width="4px"-->
<!-- android:color="@color/deepskyblue" />-->
<!-- 设置四个圆角的半径 -->
<corners
android:bottomLeftRadius="8dp"
android:bottomRightRadius="8dp"
android:topLeftRadius="8dp"
android:topRightRadius="8dp" />
<!-- 设置一下边距,让空间大一点 -->
<!-- <padding-->
<!-- android:bottom="5dp"-->
<!-- android:left="5dp"-->
<!-- android:right="5dp"-->
<!-- android:top="5dp" />-->
</shape>

BIN
app/src/main/res/drawable/bgr.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

BIN
app/src/main/res/drawable/bigackground.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 162 KiB

BIN
app/src/main/res/drawable/bigackground2.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.7 KiB

25
app/src/main/res/drawable/blue_rounded_rectangle.xml

@ -0,0 +1,25 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<!-- 设置透明背景色 -->
<!-- <solid android:color="@color/white" />-->
<solid android:color="#d6eaf8" />
<!-- 设置一个黑色边框 -->
<!-- <stroke-->
<!-- android:width="4px"-->
<!-- android:color="@color/deepskyblue" />-->
<!-- 设置四个圆角的半径 -->
<corners
android:bottomLeftRadius="8dp"
android:bottomRightRadius="8dp"
android:topLeftRadius="8dp"
android:topRightRadius="8dp" />
<!-- 设置一下边距,让空间大一点 -->
<!-- <padding-->
<!-- android:bottom="5dp"-->
<!-- android:left="5dp"-->
<!-- android:right="5dp"-->
<!-- android:top="5dp" />-->
</shape>

10
app/src/main/res/drawable/border.xml

@ -0,0 +1,10 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android" >
<!-- 设置一个黑色边框 -->
<stroke android:width="4px" android:color="#ffffff"/>
<!-- 渐变 -->
<!-- 设置一下边距,让空间大一点 -->
</shape>

31
app/src/main/res/drawable/borderblue.xml

@ -0,0 +1,31 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<!-- 设置透明背景色 -->
<!-- <solid android:color="##deebf7" />-->
<solid android:color="#d6eaf8" />
<!-- 设置一个黑色边框 -->
<!-- <stroke-->
<!-- android:width="4px"-->
<!-- android:color="@color/deepskyblue" />-->
<!-- 设置四个圆角的半径 -->
<corners
android:bottomLeftRadius="5dp"
android:bottomRightRadius="5dp"
android:topLeftRadius="5dp"
android:topRightRadius="5dp" />
<!-- <corners-->
<!-- android:bottomLeftRadius="10px"-->
<!-- android:bottomRightRadius="10px"-->
<!-- android:topLeftRadius="10px"-->
<!-- android:topRightRadius="10px" />-->
<!-- 设置一下边距,让空间大一点 -->
<!-- <padding-->
<!-- android:bottom="5dp"-->
<!-- android:left="5dp"-->
<!-- android:right="5dp"-->
<!-- android:top="5dp" />-->
</shape>

34
app/src/main/res/drawable/bordergreen.xml

@ -0,0 +1,34 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<!-- 设置透明背景色 -->
<!-- <solid android:color="#87CEEB" />-->
<!-- &lt;!&ndash; 设置一个黑色边框 &ndash;&gt;-->
<!-- <stroke-->
<!-- android:width="4px"-->
<!-- android:color="@color/green" />-->
<!-- &lt;!&ndash; 设置四个圆角的半径 &ndash;&gt;-->
<!-- <corners-->
<!-- android:bottomLeftRadius="5dp"-->
<!-- android:bottomRightRadius="5dp"-->
<!-- android:topLeftRadius="5dp"-->
<!-- android:topRightRadius="5dp" />-->
<!-- 设置一个黑色边框 -->
<stroke
android:width="4px"
android:color="#6efe00" />
<!-- 设置四个圆角的半径 -->
<corners
android:bottomLeftRadius="10px"
android:bottomRightRadius="10px"
android:topLeftRadius="10px"
android:topRightRadius="10px" />
<!-- 设置一下边距,让空间大一点 -->
<!-- <padding-->
<!-- android:bottom="5dp"-->
<!-- android:left="5dp"-->
<!-- android:right="5dp"-->
<!-- android:top="5dp" />-->
</shape>

31
app/src/main/res/drawable/borderlog.xml

@ -0,0 +1,31 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<!-- 设置透明背景色 -->
<!-- <solid android:color="##deebf7" />-->
<solid android:color="@color/white" />
<!-- 设置一个黑色边框 -->
<stroke
android:width="4px"
android:color="@color/grey" />
<!-- 设置四个圆角的半径 -->
<corners
android:bottomLeftRadius="5dp"
android:bottomRightRadius="5dp"
android:topLeftRadius="5dp"
android:topRightRadius="5dp" />
<!-- <corners-->
<!-- android:bottomLeftRadius="10px"-->
<!-- android:bottomRightRadius="10px"-->
<!-- android:topLeftRadius="10px"-->
<!-- android:topRightRadius="10px" />-->
<!-- 设置一下边距,让空间大一点 -->
<!-- <padding-->
<!-- android:bottom="5dp"-->
<!-- android:left="5dp"-->
<!-- android:right="5dp"-->
<!-- android:top="5dp" />-->
</shape>

24
app/src/main/res/drawable/borderorange.xml

@ -0,0 +1,24 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<!-- 设置透明背景色 -->
<solid android:color="#f6ddcc" />
<!-- 设置一个黑色边框 -->
<!-- <stroke-->
<!-- android:width="4px"-->
<!-- android:color="#ed7041" />-->
<!-- 设置四个圆角的半径 -->
<corners
android:bottomLeftRadius="5dp"
android:bottomRightRadius="5dp"
android:topLeftRadius="5dp"
android:topRightRadius="5dp" />
<!-- 设置一下边距,让空间大一点 -->
<!-- <padding-->
<!-- android:bottom="5dp"-->
<!-- android:left="5dp"-->
<!-- android:right="5dp"-->
<!-- android:top="5dp" />-->
</shape>

24
app/src/main/res/drawable/bordersubmenu.xml

@ -0,0 +1,24 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<!-- 设置透明背景色 -->
<!-- <solid android:color="#87CEEB" />-->
<!-- 设置一个黑色边框 -->
<stroke
android:width="4px"
android:color="@color/green" />
<!-- 设置四个圆角的半径 -->
<corners
android:bottomLeftRadius="5dp"
android:bottomRightRadius="5dp"
android:topLeftRadius="5dp"
android:topRightRadius="5dp" />
<!-- 设置一下边距,让空间大一点 -->
<!-- <padding-->
<!-- android:bottom="5dp"-->
<!-- android:left="5dp"-->
<!-- android:right="5dp"-->
<!-- android:top="5dp" />-->
</shape>

24
app/src/main/res/drawable/borderwhite.xml

@ -0,0 +1,24 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<!-- 设置透明背景色 -->
<!-- <solid android:color="#87CEEB" />-->
<!-- 设置一个黑色边框 -->
<stroke
android:width="2px"
android:color="#ffffff" />
<!-- 设置四个圆角的半径 -->
<corners
android:bottomLeftRadius="10px"
android:bottomRightRadius="10px"
android:topLeftRadius="10px"
android:topRightRadius="10px" />
<!-- 设置一下边距,让空间大一点 -->
<!-- <padding-->
<!-- android:bottom="5dp"-->
<!-- android:left="5dp"-->
<!-- android:right="5dp"-->
<!-- android:top="5dp" />-->
</shape>

24
app/src/main/res/drawable/buttonborderwhite.xml

@ -0,0 +1,24 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<!-- 设置透明背景色 -->
<solid android:color="#00ffffff" />
<!-- 设置一个黑色边框 -->
<stroke
android:width="16px"
android:color="#ffffff" />
<!-- 设置四个圆角的半径 -->
<corners
android:bottomLeftRadius="10px"
android:bottomRightRadius="10px"
android:topLeftRadius="10px"
android:topRightRadius="10px" />
<!-- 设置一下边距,让空间大一点 -->
<!-- <padding-->
<!-- android:bottom="5dp"-->
<!-- android:left="5dp"-->
<!-- android:right="5dp"-->
<!-- android:top="5dp" />-->
</shape>

14
app/src/main/res/drawable/dash_line.xml

@ -0,0 +1,14 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android" android:shape="line">
<stroke
android:color="#ffffff"
android:dashWidth="10dp"
/>
<!--width:线条的高度
color:颜色
android:dashGap="8dp"
dashWidth:破折线的宽度
dashGap:破折线间空隙的宽度
如果这里设置了width,xml中android:layout_height的值必须比它大。不设置就默认为0
-->
</shape>

170
app/src/main/res/drawable/ic_launcher_background.xml

@ -0,0 +1,170 @@
<?xml version="1.0" encoding="utf-8"?>
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="108dp"
android:height="108dp"
android:viewportWidth="108"
android:viewportHeight="108">
<path
android:fillColor="#3DDC84"
android:pathData="M0,0h108v108h-108z" />
<path
android:fillColor="#00000000"
android:pathData="M9,0L9,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M19,0L19,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M29,0L29,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M39,0L39,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M49,0L49,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M59,0L59,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M69,0L69,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M79,0L79,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M89,0L89,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M99,0L99,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,9L108,9"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,19L108,19"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,29L108,29"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,39L108,39"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,49L108,49"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,59L108,59"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,69L108,69"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,79L108,79"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,89L108,89"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,99L108,99"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M19,29L89,29"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M19,39L89,39"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M19,49L89,49"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M19,59L89,59"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M19,69L89,69"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M19,79L89,79"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M29,19L29,89"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M39,19L39,89"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M49,19L49,89"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M59,19L59,89"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M69,19L69,89"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M79,19L79,89"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
</vector>

30
app/src/main/res/drawable/ic_launcher_foreground.xml

@ -0,0 +1,30 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:aapt="http://schemas.android.com/aapt"
android:width="108dp"
android:height="108dp"
android:viewportWidth="108"
android:viewportHeight="108">
<path android:pathData="M31,63.928c0,0 6.4,-11 12.1,-13.1c7.2,-2.6 26,-1.4 26,-1.4l38.1,38.1L107,108.928l-32,-1L31,63.928z">
<aapt:attr name="android:fillColor">
<gradient
android:endX="85.84757"
android:endY="92.4963"
android:startX="42.9492"
android:startY="49.59793"
android:type="linear">
<item
android:color="#44000000"
android:offset="0.0" />
<item
android:color="#00000000"
android:offset="1.0" />
</gradient>
</aapt:attr>
</path>
<path
android:fillColor="#FFFFFF"
android:fillType="nonZero"
android:pathData="M65.3,45.828l3.8,-6.6c0.2,-0.4 0.1,-0.9 -0.3,-1.1c-0.4,-0.2 -0.9,-0.1 -1.1,0.3l-3.9,6.7c-6.3,-2.8 -13.4,-2.8 -19.7,0l-3.9,-6.7c-0.2,-0.4 -0.7,-0.5 -1.1,-0.3C38.8,38.328 38.7,38.828 38.9,39.228l3.8,6.6C36.2,49.428 31.7,56.028 31,63.928h46C76.3,56.028 71.8,49.428 65.3,45.828zM43.4,57.328c-0.8,0 -1.5,-0.5 -1.8,-1.2c-0.3,-0.7 -0.1,-1.5 0.4,-2.1c0.5,-0.5 1.4,-0.7 2.1,-0.4c0.7,0.3 1.2,1 1.2,1.8C45.3,56.528 44.5,57.328 43.4,57.328L43.4,57.328zM64.6,57.328c-0.8,0 -1.5,-0.5 -1.8,-1.2s-0.1,-1.5 0.4,-2.1c0.5,-0.5 1.4,-0.7 2.1,-0.4c0.7,0.3 1.2,1 1.2,1.8C66.5,56.528 65.6,57.328 64.6,57.328L64.6,57.328z"
android:strokeWidth="1"
android:strokeColor="#00000000" />
</vector>

24
app/src/main/res/drawable/message_rounded_rectangle.xml

@ -0,0 +1,24 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<!-- 设置透明背景色 -->
<solid android:color="#f6ddcc" />
<!-- 设置一个黑色边框 -->
<!-- <stroke-->
<!-- android:width="4px"-->
<!-- android:color="@color/" />-->
<!-- 设置四个圆角的半径 -->
<corners
android:bottomLeftRadius="15dp"
android:bottomRightRadius="15dp"
android:topLeftRadius="15dp"
android:topRightRadius="15dp" />
<!-- 设置一下边距,让空间大一点 -->
<!-- <padding-->
<!-- android:bottom="5dp"-->
<!-- android:left="5dp"-->
<!-- android:right="5dp"-->
<!-- android:top="5dp" />-->
</shape>

26
app/src/main/res/drawable/message_rounded_rectangle_red.xml

@ -0,0 +1,26 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<!-- 设置透明背景色 -->
<!-- <solid android:color="#F44336" />-->
<solid android:color="#FF0000" />
<!-- 设置一个黑色边框 -->
<!-- <stroke-->
<!-- android:width="4px"-->
<!-- android:color="@color/" />-->
<!-- 设置四个圆角的半径 -->
<corners
android:bottomLeftRadius="8dp"
android:bottomRightRadius="8dp"
android:topLeftRadius="8dp"
android:topRightRadius="8dp" />
<!-- 设置一下边距,让空间大一点 -->
<!-- <padding-->
<!-- android:bottom="5dp"-->
<!-- android:left="5dp"-->
<!-- android:right="5dp"-->
<!-- android:top="5dp" />-->
</shape>

26
app/src/main/res/drawable/orange_rounded_rectangle.xml

@ -0,0 +1,26 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<!-- 设置透明背景色 -->
<!-- <solid android:color="@color/white" />-->
<!-- <solid android:color="#c5e1a5" />-->
<solid android:color="#FBD6D6 " />
<!-- 设置一个黑色边框 -->
<!-- <stroke-->
<!-- android:width="4px"-->
<!-- android:color="@color/deepskyblue" />-->
<!-- 设置四个圆角的半径 -->
<corners
android:bottomLeftRadius="8dp"
android:bottomRightRadius="8dp"
android:topLeftRadius="8dp"
android:topRightRadius="8dp" />
<!-- 设置一下边距,让空间大一点 -->
<!-- <padding-->
<!-- android:bottom="5dp"-->
<!-- android:left="5dp"-->
<!-- android:right="5dp"-->
<!-- android:top="5dp" />-->
</shape>

12
app/src/main/res/drawable/radio_button_selected.xml

@ -0,0 +1,12 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android" android:shape="rectangle">
<solid android:color="#d6eaf8" />
<!-- 设置一个黑色边框 -->
<!-- <stroke android:width="4px" android:color="@color/deepskyblue"/>-->
<corners android:radius="5dp" />
<!-- 渐变 -->
<!-- 设置一下边距,让空间大一点 -->
</shape>

8
app/src/main/res/drawable/radio_button_textcolor.xml

@ -0,0 +1,8 @@
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:color="@color/grey"
android:state_checked="false" />
<item android:color="@color/deepskyblue"
android:state_checked="true" />
</selector>

11
app/src/main/res/drawable/radio_button_unselected.xml

@ -0,0 +1,11 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<!-- 填充 -->
<!-- <solid android:color="@color/gainsboro" />-->
<solid android:color="#eaeded" />
<!-- <stroke android:width="4px" android:color="@color/grey"/>-->
<!-- 圆角 -->
<corners android:radius="5dp" />
</shape>

5
app/src/main/res/drawable/radiobutton_background.xml

@ -0,0 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_checked="true" android:drawable="@drawable/radio_button_selected" />
<item android:state_checked="false" android:drawable="@drawable/radio_button_unselected" />
</selector>

11
app/src/main/res/drawable/radiobutton_notsave_background.xml

@ -0,0 +1,11 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<!-- 填充 -->
<!-- <solid android:color="@color/gainsboro" />-->
<solid android:color="#eaeded" />
<!-- <stroke android:width="4px" android:color="@color/grey"/>-->
<!-- 圆角 -->
<corners android:radius="5dp" />
</shape>

12
app/src/main/res/drawable/radiobutton_save_background.xml

@ -0,0 +1,12 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android" android:shape="rectangle">
<solid android:color="#FFFF00" />
<!-- 设置一个黑色边框 -->
<!-- <stroke android:width="4px" android:color="@color/deepskyblue"/>-->
<corners android:radius="5dp" />
<!-- 渐变 -->
<!-- 设置一下边距,让空间大一点 -->
</shape>

28
app/src/main/res/drawable/rounded_edittext.xml

@ -0,0 +1,28 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<!-- 设置Editext的形状-->
<!-- 设置透明背景色 -->
<!-- <solid android:color="#87CEEB" />-->
<!-- 设置一个自定义颜色边框 -->
<stroke
android:width="1px"
android:color="@color/trasnparent" />
<!-- 设置四个圆角的半径 -->
<corners
android:bottomLeftRadius="10px"
android:bottomRightRadius="10px"
android:topLeftRadius="10px"
android:topRightRadius="10px" />
<!-- 设置一下边距,让空间大一点 -->
<!-- <padding-->
<!-- android:bottom="5dp"-->
<!-- android:left="5dp"-->
<!-- android:right="5dp"-->
<!-- android:top="5dp" />-->
</shape>

BIN
app/src/main/res/drawable/smallbackground.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 85 KiB

BIN
app/src/main/res/drawable/squrelogo.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 75 KiB

24
app/src/main/res/drawable/submenu.xml

@ -0,0 +1,24 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<!-- 设置透明背景色 -->
<solid android:color="@color/white" />
<!-- <solid android:color="#d6eaf8" />-->
<!-- 设置一个黑色边框 -->
<stroke
android:width="2px"
android:color="@color/deepskyblue" />
<!-- 设置四个圆角的半径 -->
<corners
android:bottomLeftRadius="2dp"
android:bottomRightRadius="2dp"
android:topLeftRadius="2dp"
android:topRightRadius="2dp" />
<!-- 设置一下边距,让空间大一点 -->
<!-- <padding-->
<!-- android:bottom="5dp"-->
<!-- android:left="5dp"-->
<!-- android:right="5dp"-->
<!-- android:top="5dp" />-->
</shape>

BIN
app/src/main/res/drawable/submenu2.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.2 KiB

BIN
app/src/main/res/drawable/submenupng.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

BIN
app/src/main/res/font/font_you_yuan.ttf

Binary file not shown.

608
app/src/main/res/layout/activity_main.xml

@ -0,0 +1,608 @@
<layout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
tools:context=".MainActivity">
<!--根布局-->
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@drawable/background"
android:orientation="vertical">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1">
<!--左侧显示半框-->
<LinearLayout
android:id="@+id/messageRounded"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_marginTop="15dp"
android:layout_marginBottom="15dp"
android:layout_marginLeft="15dp"
android:orientation="vertical"
android:layout_weight="1"
android:background="@drawable/orange_rounded_rectangle"
>
<!--机器人速度-->
<LinearLayout
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
>
<TextView
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_gravity="center"
android:layout_marginLeft="8dp"
android:layout_weight="1.5"
android:fontFamily="@font/font_you_yuan"
android:gravity="left|center"
android:text="@string/moveSpeed"
android:textColor="@color/black"
android:textSize="12sp"
android:textStyle="bold" />
<TextView
android:id="@+id/tv_speedFrom32"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="2"
android:gravity="center"
android:text="xxx"
android:textColor="@color/navy_blue"
android:textSize="15sp"
android:textStyle="bold" />
<TextView
android:layout_width="35dp"
android:layout_height="match_parent"
android:gravity="center"
android:text="m/min"
android:textColor="@color/dark_ink_blue"
android:textSize="10dp" />
</LinearLayout>
<!--作业模式-->
<LinearLayout
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:orientation="horizontal">
<FrameLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="horizontal">
<TextView
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_gravity="center"
android:layout_marginLeft="8dp"
android:layout_weight="1.5"
android:gravity="left|center"
android:text="@string/workMode"
android:textColor="@color/black"
android:textSize="12sp"
android:textStyle="bold"
android:fontFamily="@font/font_you_yuan" />
<TextView
android:id="@+id/workModeDisplay"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="2"
android:gravity="center"
android:text="无"
android:textColor="@color/navy_blue"
android:textSize="15sp"
android:textStyle="bold" />
<TextView
android:layout_width="35dp"
android:layout_height="match_parent"
android:gravity="center"
android:text=""
android:textColor="@color/dark_ink_blue"
android:textSize="10dp" />
</LinearLayout>
<Button
android:id="@+id/btnWorkMode"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/trasnparent"
android:gravity="center"
android:textAlignment="center" />
</FrameLayout>
</LinearLayout>
<!--当前角度-->
<LinearLayout
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
>
<TextView
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_gravity="center"
android:layout_weight="1.5"
android:gravity="left|center"
android:text="@string/realAngle"
android:layout_marginLeft="8dp"
android:textColor="@color/black"
android:textSize="12sp"
android:textStyle="bold"
android:fontFamily="@font/font_you_yuan" />
<TextView
android:id="@+id/tvAngleFrom32"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="2"
android:gravity="center"
android:text="xxx"
android:textColor="@color/navy_blue"
android:textSize="15sp"
android:textStyle="bold" />
<TextView
android:layout_width="35dp"
android:layout_height="match_parent"
android:gravity="center"
android:text="°"
android:textColor="@color/dark_ink_blue"
android:textSize="10dp" />
</LinearLayout>
<!--第一关节速度-->
<LinearLayout
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1" >
<TextView
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_gravity="center"
android:layout_weight="1.5"
android:gravity="left|center"
android:layout_marginLeft="8dp"
android:text="@string/jointSpeed1"
android:textColor="@color/black"
android:textSize="12sp"
android:textStyle="bold"
android:fontFamily="@font/font_you_yuan" />
<EditText
android:id="@+id/jointSpeed1To32"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="2"
android:gravity="center"
android:text="10"
android:inputType="number"
android:hint="请输入10到30之间的数字"
android:background="@drawable/rounded_edittext"
android:textColor="@color/navy_blue"
android:imeOptions="actionDone"
android:textSize="15sp"
android:textStyle="bold" />
<TextView
android:layout_width="35dp"
android:layout_height="match_parent"
android:gravity="center"
android:text="°/s"
android:textColor="@color/dark_ink_blue"
android:textSize="10dp" />
</LinearLayout>
<!--第二关节速度-->
<LinearLayout
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:gravity="center_vertical"
>
<TextView
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_gravity="center"
android:layout_weight="1.5"
android:gravity="left|center"
android:layout_marginLeft="8dp"
android:text="@string/jointSpeed2"
android:textColor="@color/black"
android:textSize="12sp"
android:textStyle="bold"
android:fontFamily="@font/font_you_yuan" />
<EditText
android:id="@+id/jointSpeed2To32"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="2"
android:gravity="center"
android:text="10"
android:inputType="number"
android:background="@drawable/rounded_edittext"
android:hint="请输入10到30之间的数字"
android:imeOptions="actionDone"
android:textColor="@color/navy_blue"
android:textSize="15sp"
android:textStyle="bold" />
<TextView
android:layout_width="35dp"
android:layout_height="match_parent"
android:gravity="center"
android:text="°/s"
android:textColor="@color/dark_ink_blue"
android:textSize="10dp" />
</LinearLayout>
<!--下压力设置-->
<LinearLayout
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
>
<TextView
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_gravity="center"
android:layout_weight="1.5"
android:gravity="left|center"
android:layout_marginLeft="8dp"
android:text="@string/forceSet"
android:textColor="@color/black"
android:textSize="12sp"
android:textStyle="bold"
android:fontFamily="@font/font_you_yuan" />
<EditText
android:id="@+id/forceSetingTo32"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="2"
android:gravity="center"
android:text="0"
android:inputType="number"
android:hint="请输入0到8之间的数字"
android:background="@drawable/rounded_edittext"
android:imeOptions="actionDone"
android:textColor="@color/navy_blue"
android:textSize="15sp"
android:textStyle="bold" />
<TextView
android:layout_width="35dp"
android:layout_height="match_parent"
android:gravity="center"
android:text=""
android:textColor="@color/dark_ink_blue"
android:textSize="10dp" />
</LinearLayout>
<!--左行补偿-->
<LinearLayout
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
>
<TextView
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_gravity="center"
android:layout_weight="1.5"
android:gravity="left|center"
android:text="@string/leftComp"
android:layout_marginLeft="8dp"
android:textColor="@color/black"
android:textSize="12sp"
android:textStyle="bold"
android:fontFamily="@font/font_you_yuan" />
<EditText
android:id="@+id/edit_leftCompTo32"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="2"
android:gravity="center"
android:text="0.0"
android:background="@drawable/rounded_edittext"
android:inputType="numberSigned|numberDecimal"
android:hint="请输入-10到10之间的数字"
android:imeOptions="actionDone"
android:textColor="@color/navy_blue"
android:textSize="15sp"
android:textStyle="bold" />
<TextView
android:layout_width="35dp"
android:layout_height="match_parent"
android:gravity="center"
android:text="°"
android:textColor="@color/dark_ink_blue"
android:textSize="10dp" />
</LinearLayout>
<!--右行补偿-->
<LinearLayout
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
>
<TextView
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_gravity="center"
android:layout_weight="1.5"
android:gravity="left|center"
android:text="@string/rightComp"
android:layout_marginLeft="8dp"
android:textColor="@color/black"
android:textSize="12sp"
android:textStyle="bold"
android:fontFamily="@font/font_you_yuan" />
<EditText
android:id="@+id/edit_rightCompTo32"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="2"
android:gravity="center"
android:text="0.0"
android:background="@drawable/rounded_edittext"
android:inputType="numberSigned|numberDecimal"
android:textColor="@color/navy_blue"
android:hint="请输入-10到10之间的数字"
android:textSize="15sp"
android:textStyle="bold" />
<TextView
android:layout_width="35dp"
android:layout_height="match_parent"
android:gravity="center"
android:text="°"
android:textColor="@color/dark_ink_blue"
android:textSize="10dp" />
</LinearLayout>
<!--辅助线-->
<LinearLayout
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:orientation="horizontal">
<FrameLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="horizontal">
<TextView
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_gravity="center"
android:layout_marginLeft="8dp"
android:layout_weight="1.5"
android:gravity="left|center"
android:text="@string/lineplay"
android:textColor="@color/black"
android:textSize="12sp"
android:textStyle="bold"
android:fontFamily="@font/font_you_yuan" />
<TextView
android:id="@+id/lineState"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="2"
android:gravity="center"
android:text="开启"
android:textColor="@color/navy_blue"
android:textSize="15sp"
android:textStyle="bold" />
<TextView
android:layout_width="35dp"
android:layout_height="match_parent"
android:gravity="center"
android:text=""
android:textColor="@color/dark_ink_blue"
android:textSize="10dp" />
</LinearLayout>
<Button
android:id="@+id/lineChange"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/trasnparent"
android:gravity="center"
android:textAlignment="center" />
</FrameLayout>
</LinearLayout>
<!--机器人错误信息-->
<FrameLayout
android:id="@+id/mainViewErrMessageFrameLayout"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center"
android:orientation="horizontal">
<TextView
android:layout_width="0dp"
android:layout_weight="1.5"
android:layout_height="match_parent"
android:gravity="center|left"
android:layout_marginLeft="6dp"
android:text="报错"
android:textColor="@color/black"
android:fontFamily="@font/font_you_yuan"
android:textSize="12sp"
android:textStyle="bold" />
<TextView
android:id="@+id/mainViewErrMessageTxView"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_margin="1dp"
android:layout_weight="2"
android:gravity="center"
android:text="xxx"
android:textColor="@color/midnightblue"
android:textSize="15sp"
android:textStyle="bold" />
<TextView
android:layout_width="35dp"
android:layout_height="match_parent"
android:gravity="center"
android:text=""
android:textColor="@color/midnightblue"
android:textSize="10dp"
android:textStyle="bold" />
</LinearLayout>
<Button
android:id="@+id/ErrMessageBtn"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_row="0"
android:layout_column="6"
android:layout_marginStart="0dp"
android:background="@color/trasnparent"
android:textAlignment="center" />
</FrameLayout>
<!--画面切换-->
<LinearLayout
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:orientation="horizontal">
<FrameLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="horizontal">
</LinearLayout>
<Button
android:id="@+id/screenRotate"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/trasnparent"
android:gravity="center"
android:text="画面旋转"
android:textAlignment="center"
android:textColor="@color/black"
android:textSize="12sp"
android:textStyle="bold"
android:fontFamily="@font/font_you_yuan" />
</FrameLayout>
</LinearLayout>
</LinearLayout>
<!--右侧显示半框-->
<LinearLayout
android:id="@+id/rightSend"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_margin="15dp"
android:orientation="vertical"
android:layout_weight="2"
>
<FrameLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<cn.nodemedia.NodePlayerView
android:id="@+id/nodePlayerView0"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:focusable="false"
android:focusableInTouchMode="false"
android:clickable="false">
</cn.nodemedia.NodePlayerView>
<!-- 上层标线遮罩,透明背景,只画两条线 -->
<com.example.washing02app.services.LineOverlayView
android:id="@+id/lineOverlay"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
</FrameLayout>
</LinearLayout>
</LinearLayout>
</LinearLayout>
</layout>

Some files were not shown because too many files changed in this diff

Loading…
Cancel
Save