├── .gitignore ├── README.md ├── apk_download └── app-debug.apk ├── app ├── .gitignore ├── build.gradle ├── proguard-rules.pro └── src │ ├── androidTest │ └── java │ │ └── com │ │ └── licheedev │ │ └── modbus4android │ │ └── ExampleInstrumentedTest.java │ ├── main │ ├── AndroidManifest.xml │ ├── java │ │ └── com │ │ │ └── licheedev │ │ │ ├── demo │ │ │ ├── App.java │ │ │ ├── ChooseModeActivity.java │ │ │ ├── MainActivity.java │ │ │ ├── MainActivityKt.kt │ │ │ ├── base │ │ │ │ ├── BaseActivity.java │ │ │ │ ├── ByteUtil.java │ │ │ │ ├── PrefUtil.java │ │ │ │ └── ToastUtil.java │ │ │ ├── modbus │ │ │ │ ├── DeviceConfig.java │ │ │ │ ├── ModbusManager.java │ │ │ │ └── Protocol.java │ │ │ └── utils │ │ │ │ └── RxUtilEx.java │ │ │ └── impl │ │ │ ├── kotlin │ │ │ └── ModbusWorkers.kt │ │ │ └── rxjava │ │ │ ├── ModbusObserver.java │ │ │ └── RxModbusWorker.java │ └── res │ │ ├── drawable-v24 │ │ └── ic_launcher_foreground.xml │ │ ├── drawable │ │ ├── ic_keyboard_arrow_down_black_32dp.xml │ │ ├── ic_keyboard_arrow_up_black_32dp.xml │ │ ├── ic_launcher_background.xml │ │ └── selector_serial_params_bg.xml │ │ ├── layout-land │ │ └── activity_main.xml │ │ ├── layout │ │ ├── activity_choose_mode.xml │ │ ├── activity_main.xml │ │ ├── include_control.xml │ │ └── include_log.xml │ │ ├── mipmap-anydpi-v26 │ │ ├── ic_launcher.xml │ │ └── ic_launcher_round.xml │ │ ├── mipmap-hdpi │ │ ├── ic_launcher.png │ │ └── ic_launcher_round.png │ │ ├── mipmap-mdpi │ │ ├── ic_launcher.png │ │ └── ic_launcher_round.png │ │ ├── mipmap-xhdpi │ │ ├── ic_launcher.png │ │ └── ic_launcher_round.png │ │ ├── mipmap-xxhdpi │ │ ├── ic_launcher.png │ │ └── ic_launcher_round.png │ │ ├── mipmap-xxxhdpi │ │ ├── ic_launcher.png │ │ └── ic_launcher_round.png │ │ └── values │ │ ├── adapt_screen_style.xml │ │ ├── colors.xml │ │ ├── functions.xml │ │ ├── serial_port_res.xml │ │ ├── strings.xml │ │ └── styles.xml │ └── test │ └── java │ └── com │ └── licheedev │ └── modbus4android │ └── ExampleUnitTest.java ├── build.gradle ├── gradle.properties ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── imgs ├── 01.png ├── 02.png ├── 03.png ├── 04.png ├── 05.gif ├── 06.gif ├── 15.gif ├── 16.gif ├── app.png ├── modbus_proto_cn.pdf └── tcp.png ├── jitpack.gradle ├── modbus4android ├── .gitignore ├── build.gradle ├── proguard-rules.pro └── src │ ├── androidTest │ └── java │ │ └── com │ │ └── licheedev │ │ └── modbus4android │ │ └── ExampleInstrumentedTest.java │ ├── main │ ├── AndroidManifest.xml │ ├── java │ │ └── com │ │ │ └── licheedev │ │ │ └── modbus4android │ │ │ ├── AndroidSerialPortWrapper.java │ │ │ ├── IModbusWorker.java │ │ │ ├── ModbusCallback.java │ │ │ ├── ModbusParam.java │ │ │ ├── ModbusRespException.java │ │ │ ├── ModbusWorker.java │ │ │ └── param │ │ │ ├── SerialParam.java │ │ │ └── TcpParam.java │ └── res │ │ └── values │ │ └── strings.xml │ └── test │ └── java │ └── com │ └── licheedev │ └── modbus4android │ └── ExampleUnitTest.java ├── modbus4j ├── .gitignore ├── build.gradle └── src │ └── main │ └── java │ └── com │ └── serotonin │ └── modbus4j │ ├── BasicProcessImage.java │ ├── BatchRead.java │ ├── BatchResults.java │ ├── ExceptionResult.java │ ├── Modbus.java │ ├── ModbusConfig.java │ ├── ModbusFactory.java │ ├── ModbusMaster.java │ ├── ModbusSlaveSet.java │ ├── NodeScanListener.java │ ├── ProcessImage.java │ ├── ProcessImageListener.java │ ├── base │ ├── BaseMessageParser.java │ ├── BaseRequestHandler.java │ ├── KeyedModbusLocator.java │ ├── ModbusUtils.java │ ├── RangeAndOffset.java │ ├── ReadFunctionGroup.java │ ├── SlaveAndRange.java │ └── SlaveProfile.java │ ├── code │ ├── DataType.java │ ├── ExceptionCode.java │ ├── FunctionCode.java │ └── RegisterRange.java │ ├── exception │ ├── ErrorResponseException.java │ ├── IllegalDataAddressException.java │ ├── IllegalDataTypeException.java │ ├── IllegalFunctionException.java │ ├── IllegalSlaveIdException.java │ ├── InvalidDataConversionException.java │ ├── ModbusIdException.java │ ├── ModbusInitException.java │ ├── ModbusTransportException.java │ └── SlaveIdNotEqual.java │ ├── ip │ ├── IpMessage.java │ ├── IpMessageResponse.java │ ├── IpParameters.java │ ├── encap │ │ ├── EncapMessage.java │ │ ├── EncapMessageParser.java │ │ ├── EncapMessageRequest.java │ │ ├── EncapMessageResponse.java │ │ ├── EncapRequestHandler.java │ │ └── EncapWaitingRoomKeyFactory.java │ ├── listener │ │ └── TcpListener.java │ ├── tcp │ │ ├── TcpMaster.java │ │ └── TcpSlave.java │ ├── udp │ │ ├── UdpMaster.java │ │ └── UdpSlave.java │ └── xa │ │ ├── XaMessage.java │ │ ├── XaMessageParser.java │ │ ├── XaMessageRequest.java │ │ ├── XaMessageResponse.java │ │ ├── XaRequestHandler.java │ │ └── XaWaitingRoomKeyFactory.java │ ├── locator │ ├── BaseLocator.java │ ├── BinaryLocator.java │ ├── NumericLocator.java │ └── StringLocator.java │ ├── msg │ ├── ExceptionRequest.java │ ├── ExceptionResponse.java │ ├── ModbusMessage.java │ ├── ModbusRequest.java │ ├── ModbusResponse.java │ ├── ReadBinaryRequest.java │ ├── ReadCoilsRequest.java │ ├── ReadCoilsResponse.java │ ├── ReadDiscreteInputsRequest.java │ ├── ReadDiscreteInputsResponse.java │ ├── ReadExceptionStatusRequest.java │ ├── ReadExceptionStatusResponse.java │ ├── ReadHoldingRegistersRequest.java │ ├── ReadHoldingRegistersResponse.java │ ├── ReadInputRegistersRequest.java │ ├── ReadInputRegistersResponse.java │ ├── ReadNumericRequest.java │ ├── ReadResponse.java │ ├── ReportSlaveIdRequest.java │ ├── ReportSlaveIdResponse.java │ ├── WriteCoilRequest.java │ ├── WriteCoilResponse.java │ ├── WriteCoilsRequest.java │ ├── WriteCoilsResponse.java │ ├── WriteMaskRegisterRequest.java │ ├── WriteMaskRegisterResponse.java │ ├── WriteRegisterRequest.java │ ├── WriteRegisterResponse.java │ ├── WriteRegistersRequest.java │ └── WriteRegistersResponse.java │ ├── serial │ ├── SerialMaster.java │ ├── SerialMessage.java │ ├── SerialPortWrapper.java │ ├── SerialSlave.java │ ├── SerialWaitingRoomKeyFactory.java │ ├── ascii │ │ ├── AsciiMaster.java │ │ ├── AsciiMessage.java │ │ ├── AsciiMessageParser.java │ │ ├── AsciiMessageRequest.java │ │ ├── AsciiMessageResponse.java │ │ ├── AsciiRequestHandler.java │ │ └── AsciiSlave.java │ └── rtu │ │ ├── RtuMaster.java │ │ ├── RtuMessage.java │ │ ├── RtuMessageParser.java │ │ ├── RtuMessageRequest.java │ │ ├── RtuMessageResponse.java │ │ ├── RtuRequestHandler.java │ │ └── RtuSlave.java │ ├── sero │ ├── NotImplementedException.java │ ├── ShouldNeverHappenException.java │ ├── epoll │ │ ├── InputStreamEPollWrapper.java │ │ └── Modbus4JInputStreamCallback.java │ ├── io │ │ ├── LineHandler.java │ │ ├── NullWriter.java │ │ └── StreamUtils.java │ ├── log │ │ ├── BaseIOLog.java │ │ ├── IOLog.java │ │ ├── RollingIOLog.java │ │ └── SimpleLog.java │ ├── messaging │ │ ├── DataConsumer.java │ │ ├── DefaultMessagingExceptionHandler.java │ │ ├── EpollStreamTransport.java │ │ ├── EpollStreamTransportCharSpaced.java │ │ ├── IncomingMessage.java │ │ ├── IncomingRequestMessage.java │ │ ├── IncomingResponseMessage.java │ │ ├── InputStreamListener.java │ │ ├── MessageControl.java │ │ ├── MessageParser.java │ │ ├── MessagingExceptionHandler.java │ │ ├── OutgoingMessage.java │ │ ├── OutgoingRequestMessage.java │ │ ├── OutgoingResponseMessage.java │ │ ├── RequestHandler.java │ │ ├── StreamTransport.java │ │ ├── StreamTransportCharSpaced.java │ │ ├── TestableTransport.java │ │ ├── TimeoutException.java │ │ ├── Transport.java │ │ ├── WaitingRoom.java │ │ ├── WaitingRoomException.java │ │ ├── WaitingRoomKey.java │ │ └── WaitingRoomKeyFactory.java │ ├── timer │ │ ├── SystemTimeSource.java │ │ └── TimeSource.java │ └── util │ │ ├── ArrayUtils.java │ │ ├── ProgressiveTask.java │ │ ├── ProgressiveTaskListener.java │ │ └── queue │ │ └── ByteQueue.java │ └── value │ └── ModbusValue.java └── settings.gradle /.gitignore: -------------------------------------------------------------------------------- 1 | *.iml 2 | .gradle 3 | .idea 4 | /local.properties 5 | /.idea/libraries 6 | /.idea/modules.xml 7 | /.idea/workspace.xml 8 | .DS_Store 9 | /build 10 | /captures 11 | .externalNativeBuild 12 | -------------------------------------------------------------------------------- /apk_download/app-debug.apk: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/licheedev/Modbus4Android/df3a8aa027aa574e8e8c34bde8bd4d05dfbf1988/apk_download/app-debug.apk -------------------------------------------------------------------------------- /app/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /app/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # You can control the set of applied configuration files using the 3 | # proguardFiles setting in build.gradle. 4 | # 5 | # For more details, see 6 | # http://developer.android.com/guide/developing/tools/proguard.html 7 | 8 | # If your project uses WebView with JS, uncomment the following 9 | # and specify the fully qualified class name to the JavaScript interface 10 | # class: 11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 12 | # public *; 13 | #} 14 | 15 | # Uncomment this to preserve the line number information for 16 | # debugging stack traces. 17 | #-keepattributes SourceFile,LineNumberTable 18 | 19 | # If you keep the line number information, uncomment this to 20 | # hide the original source file name. 21 | #-renamesourcefileattribute SourceFile 22 | -------------------------------------------------------------------------------- /app/src/androidTest/java/com/licheedev/modbus4android/ExampleInstrumentedTest.java: -------------------------------------------------------------------------------- 1 | package com.licheedev.modbus4android; 2 | 3 | import android.content.Context; 4 | import androidx.test.platform.app.InstrumentationRegistry; 5 | import androidx.test.ext.junit.runners.AndroidJUnit4; 6 | 7 | import org.junit.Test; 8 | import org.junit.runner.RunWith; 9 | 10 | import static org.junit.Assert.*; 11 | 12 | /** 13 | * Instrumented test, which will execute on an Android device. 14 | * 15 | * @see Testing documentation 16 | */ 17 | @RunWith(AndroidJUnit4.class) 18 | public class ExampleInstrumentedTest { 19 | @Test 20 | public void useAppContext() { 21 | // Context of the app under test. 22 | Context appContext = InstrumentationRegistry.getTargetContext(); 23 | 24 | assertEquals("com.licheedev.modbus4android", appContext.getPackageName()); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | 15 | 16 | 17 | 20 | 21 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 35 | 36 | 37 | -------------------------------------------------------------------------------- /app/src/main/java/com/licheedev/demo/App.java: -------------------------------------------------------------------------------- 1 | package com.licheedev.demo; 2 | 3 | import android.app.Application; 4 | import com.licheedev.demo.base.PrefUtil; 5 | import com.serotonin.modbus4j.ModbusConfig; 6 | 7 | public class App extends Application { 8 | 9 | static App sInstance; 10 | 11 | @Override 12 | public void onCreate() { 13 | super.onCreate(); 14 | sInstance = this; 15 | PrefUtil.init(this); 16 | 17 | configModbus(); 18 | } 19 | 20 | public static App getInstance() { 21 | return sInstance; 22 | } 23 | 24 | /** 25 | * 配置Modbus,可选 26 | */ 27 | private void configModbus() { 28 | // 启用rtu的crc校验(默认就启用) 29 | ModbusConfig.setEnableRtuCrc(true); 30 | // 打印数据log(默认全禁用) 31 | // System.out: MessagingControl.send: 01030000000305cb 32 | // System.out: MessagingConnection.read: 010306000100020000bd75 33 | ModbusConfig.setEnableDataLog(true, true); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /app/src/main/java/com/licheedev/demo/ChooseModeActivity.java: -------------------------------------------------------------------------------- 1 | package com.licheedev.demo; 2 | 3 | import android.os.Bundle; 4 | import androidx.annotation.Nullable; 5 | import android.view.View; 6 | import android.widget.Button; 7 | import butterknife.BindView; 8 | import butterknife.ButterKnife; 9 | import butterknife.OnClick; 10 | import com.licheedev.demo.base.BaseActivity; 11 | 12 | public class ChooseModeActivity extends BaseActivity { 13 | 14 | @BindView(R.id.btn_serial_port) 15 | Button mBtnSerialPort; 16 | @BindView(R.id.btn_tcp) 17 | Button mBtnTcp; 18 | 19 | @Override 20 | protected void onCreate(@Nullable Bundle savedInstanceState) { 21 | super.onCreate(savedInstanceState); 22 | setContentView(R.layout.activity_choose_mode); 23 | ButterKnife.bind(this); 24 | } 25 | 26 | @OnClick({ R.id.btn_serial_port, R.id.btn_tcp }) 27 | public void onClick(View view) { 28 | switch (view.getId()) { 29 | case R.id.btn_serial_port: 30 | startActivity(MainActivity.newIntent(this, MainActivity.MODE_SERIAL)); 31 | break; 32 | case R.id.btn_tcp: 33 | startActivity(MainActivity.newIntent(this, MainActivity.MODE_TCP)); 34 | break; 35 | } 36 | finish(); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /app/src/main/java/com/licheedev/demo/base/BaseActivity.java: -------------------------------------------------------------------------------- 1 | package com.licheedev.demo.base; 2 | 3 | import com.kaopiz.kprogresshud.KProgressHUD; 4 | import com.trello.rxlifecycle2.components.support.RxAppCompatActivity; 5 | 6 | public class BaseActivity extends RxAppCompatActivity { 7 | 8 | private KProgressHUD mPleaseWait; 9 | 10 | @Override 11 | protected void onStop() { 12 | super.onStop(); 13 | dismissWaitingProgress(); 14 | } 15 | 16 | public void showToast(int resId) { 17 | ToastUtil.show(this, resId); 18 | } 19 | 20 | public void showToast(String text) { 21 | ToastUtil.show(this, text); 22 | } 23 | 24 | public void showOneToast(int resId) { 25 | ToastUtil.showOne(this, resId); 26 | } 27 | 28 | public void showOneToast(String text) { 29 | ToastUtil.showOne(this, text); 30 | } 31 | 32 | public void showWaitingProgress(String text, boolean cancelable) { 33 | 34 | if (mPleaseWait == null) { 35 | mPleaseWait = KProgressHUD.create(this) 36 | .setStyle(KProgressHUD.Style.SPIN_INDETERMINATE) 37 | .setLabel(text) 38 | .setCancellable(cancelable) 39 | .setAnimationSpeed(2) 40 | .setDimAmount(0.5f); 41 | } else { 42 | mPleaseWait.setLabel(text); 43 | } 44 | 45 | mPleaseWait.setCancellable(cancelable); 46 | mPleaseWait.show(); 47 | } 48 | 49 | public void dismissWaitingProgress() { 50 | if (mPleaseWait != null && mPleaseWait.isShowing()) { 51 | mPleaseWait.dismiss(); 52 | } 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /app/src/main/java/com/licheedev/demo/base/ToastUtil.java: -------------------------------------------------------------------------------- 1 | package com.licheedev.demo.base; 2 | 3 | import android.content.Context; 4 | import android.widget.Toast; 5 | import java.lang.ref.WeakReference; 6 | 7 | /** 8 | * Toast工具类 9 | */ 10 | public class ToastUtil { 11 | 12 | private static WeakReference mToastRef = null; 13 | 14 | /** 15 | * 显示Toast,如果当前有Toast在显示,则复用之前的Toast,之前Toast的剩余显示时间会被忽略,重新计时 {@link Toast#LENGTH_SHORT} 16 | */ 17 | public static void showOne(Context context, String text) { 18 | Toast toast; 19 | if (mToastRef != null && (toast = mToastRef.get()) != null) { 20 | toast.cancel(); 21 | } 22 | toast = Toast.makeText(context.getApplicationContext(), text, Toast.LENGTH_SHORT); 23 | mToastRef = new WeakReference<>(toast); 24 | toast.show(); 25 | } 26 | 27 | /** 28 | * 显示Toast,如果当前有Toast在显示,则复用之前的Toast,之前Toast的剩余显示时间会被忽略,重新计时 {@link Toast#LENGTH_SHORT} 29 | */ 30 | public static void showOne(Context context, int resId) { 31 | showOne(context, context.getResources().getString(resId)); 32 | } 33 | 34 | /** 35 | * 普通的显示Toast,时间为 {@link Toast#LENGTH_SHORT} 36 | * 37 | * @param context 38 | * @param text 39 | */ 40 | public static void show(Context context, String text) { 41 | Toast.makeText(context, text, Toast.LENGTH_SHORT).show(); 42 | } 43 | 44 | /** 45 | * 普通的显示Toast,时间为 {@link Toast#LENGTH_SHORT} 46 | * 47 | * @param context 48 | * @param resId 49 | */ 50 | public static void show(Context context, int resId) { 51 | Toast.makeText(context, resId, Toast.LENGTH_SHORT).show(); 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /app/src/main/java/com/licheedev/demo/modbus/ModbusManager.java: -------------------------------------------------------------------------------- 1 | package com.licheedev.demo.modbus; 2 | 3 | import com.licheedev.impl.rxjava.RxModbusWorker; 4 | 5 | //public class ModbusManager extends ModbusWorker { 6 | public class ModbusManager extends RxModbusWorker { 7 | 8 | private static volatile ModbusManager sInstance; 9 | 10 | public static ModbusManager get() { 11 | ModbusManager manager = sInstance; 12 | if (manager == null) { 13 | synchronized (ModbusManager.class) { 14 | manager = sInstance; 15 | if (manager == null) { 16 | manager = new ModbusManager(); 17 | sInstance = manager; 18 | } 19 | } 20 | } 21 | return manager; 22 | } 23 | 24 | private ModbusManager() { 25 | } 26 | 27 | /** 28 | * 释放整个ModbusManager,单例会被置null 29 | */ 30 | public synchronized void release() { 31 | super.release(); 32 | sInstance = null; 33 | } 34 | 35 | // 36 | ///** 37 | // * 初始化modbus 38 | // * 39 | // * @param callback 40 | // */ 41 | //public synchronized void initModbus(ModbusCallback callback) { 42 | // 43 | // if (isModbusOpened()) { 44 | // return; 45 | // } 46 | // 47 | // // 串口 48 | // ModbusParam serialParam = SerialParam.create(Protocol.MODBUS_DEVICE, Protocol.BAUDRATE) 49 | // .setTimeout(Protocol.REQUEST_TIMEOUT) 50 | // .setRetries(0); // 不重试 51 | // 52 | // // TCP 53 | // ModbusParam tcpParam = TcpParam.create("127.0.0.1", 233) 54 | // .setEncapsulated(false) 55 | // .setKeepAlive(true) 56 | // .setTimeout(2000) 57 | // .setRetries(0); 58 | // 59 | // // 先把原来的关掉 60 | // closeModbusMaster(); 61 | // init(serialParam, callback); 62 | //} 63 | } 64 | -------------------------------------------------------------------------------- /app/src/main/java/com/licheedev/demo/modbus/Protocol.java: -------------------------------------------------------------------------------- 1 | package com.licheedev.demo.modbus; 2 | 3 | /** 4 | * Created by John on 2018/8/15. 5 | */ 6 | public interface Protocol { 7 | 8 | int SLAVE_ID = 0x01; 9 | 10 | String MODBUS_DEVICE = "/dev/ttyS0"; 11 | 12 | int BAUDRATE = 9600; 13 | /** 14 | * modbus请求超时时间 15 | */ 16 | int REQUEST_TIMEOUT = 1000; 17 | } 18 | -------------------------------------------------------------------------------- /app/src/main/java/com/licheedev/impl/rxjava/ModbusObserver.java: -------------------------------------------------------------------------------- 1 | package com.licheedev.impl.rxjava; 2 | 3 | import com.licheedev.modbus4android.ModbusRespException; 4 | import com.serotonin.modbus4j.exception.ModbusInitException; 5 | import com.serotonin.modbus4j.exception.ModbusTransportException; 6 | import com.serotonin.modbus4j.msg.ModbusResponse; 7 | import io.reactivex.Observer; 8 | import io.reactivex.disposables.Disposable; 9 | 10 | public abstract class ModbusObserver implements Observer { 11 | @Override 12 | public void onSubscribe(Disposable d) { 13 | 14 | } 15 | 16 | @Override 17 | public void onNext(T t) { 18 | if (t.isException()) { 19 | onFailure(new ModbusRespException(t)); 20 | } else { 21 | onSuccess(t); 22 | } 23 | } 24 | 25 | @Override 26 | public void onError(Throwable e) { 27 | onFailure(e); 28 | } 29 | 30 | @Override 31 | public void onComplete() { 32 | 33 | } 34 | 35 | public abstract void onSuccess(T t); 36 | 37 | /** 38 | * 失败 39 | * 40 | * @param tr 41 | * @see ModbusInitException 初始化失败或者没有初始化时的异常 42 | * @see ModbusTransportException modbus请求失败的异常 43 | * @see ModbusRespException modbus有响应,但是包含错误 44 | */ 45 | public abstract void onFailure(Throwable tr); 46 | } 47 | -------------------------------------------------------------------------------- /app/src/main/res/drawable-v24/ic_launcher_foreground.xml: -------------------------------------------------------------------------------- 1 | 7 | 12 | 13 | 19 | 22 | 25 | 26 | 27 | 28 | 34 | 35 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_keyboard_arrow_down_black_32dp.xml: -------------------------------------------------------------------------------- 1 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_keyboard_arrow_up_black_32dp.xml: -------------------------------------------------------------------------------- 1 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/selector_serial_params_bg.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /app/src/main/res/layout-land/activity_main.xml: -------------------------------------------------------------------------------- 1 | 2 | 9 | 10 | 11 | 16 | 17 | 18 | 23 | 24 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_choose_mode.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 8 |