/* * Copyright (c) 2022. UnknownNetworkService Group * This file is created by UnknownObject at 2022 - 9 - 18 */ package com.uns.maincar.gui; import android.annotation.SuppressLint; import android.content.Context; import android.content.Intent; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.net.DhcpInfo; import android.net.wifi.WifiManager; import android.os.Bundle; import android.os.Handler; import android.os.Message; import android.text.format.Formatter; import android.text.method.ScrollingMovementMethod; import android.util.Log; import android.widget.EditText; import android.widget.ImageView; import android.widget.TextView; import android.widget.Toast; import androidx.annotation.Nullable; import androidx.appcompat.app.AppCompatActivity; import com.bkrcl.control_car_video.camerautil.CameraCommandUtil; import com.bkrcl.control_car_video.camerautil.SearchCameraUtil; import com.uns.maincar.R; import com.uns.maincar.communication.CommandDecoder; import com.uns.maincar.communication.CommandEncoder; import com.uns.maincar.communication.DataTransferCore; import com.uns.maincar.communication.SerialPortTransferCore; import com.uns.maincar.communication.WifiTransferCore; import com.uns.maincar.constants.Commands; import com.uns.maincar.constants.Flags; import com.uns.maincar.constants.Flags.TrafficLightColors; import com.uns.maincar.constants.GlobalSignType; import com.uns.maincar.cpp_interface.CarLicense; import com.uns.maincar.cpp_interface.EnvTest; import com.uns.maincar.cpp_interface.MainCarAES; import com.uns.maincar.cpp_interface.OCR; import com.uns.maincar.cpp_interface.QRDecoder; import com.uns.maincar.cpp_interface.ShapeColor; import com.uns.maincar.cpp_interface.TrafficLight; import com.uns.maincar.cpp_interface.TrafficSign; import com.uns.maincar.tools.ImageReleaser; import com.uns.maincar.tools.OCRDataReleaser; import com.uns.maincar.tools.TextFilter; import java.io.UnsupportedEncodingException; import java.util.ArrayList; import java.util.Objects; public class MainActivity extends AppCompatActivity { //数据接收处理器 private final Handler recvHandler; //主车相机地址,默认值不重要 private String IPCamera = "192.168.1.101:81"; //摄像头当前图像 private Bitmap currImage; //存储小车的IP private String IPCar; //通信客户端 private DataTransferCore dtc_client; //DHCP相关信息,用于获取IP地址 private DhcpInfo dhcpInfo; //WIFI管理器 private WifiManager wifiManager; //控件——存储从摄像头获取到的图像 private ImageView pic_received; //控件——存储Toast的内容,由ToastLog()进行管理 private TextView text_toast; //控制主车相机 private CameraCommandUtil cameraCommandUtil; //寻找主车相机 private SearchCameraUtil searchCameraUtil = null; //程序状态,通过所有自检后会设置为true private boolean SystemStatus = false; //文件状态,获取到存储权限并释放完毕所有文件会设置为true private boolean FileStatus = false; //申请存储空间使用的请求码 private final int permission_request_code = 0x100942; //串口通信的设备名 private final String SerialPortPath = "/dev/ttyS4"; //通信通道标志,true为Wifi,false为串口 private final boolean CommunicationUsingWifi = true; //调试用16进制数组 private final String[] byte_str = { "0x00", "0x01", "0x02", "0x03", "0x04", "0x05", "0x06", "0x07", "0x08", "0x09", "0x0A", "0x0B", "0x0C", "0x0D", "0x0E", "0x0F", "0x10", "0x11", "0x12", "0x13", "0x14", "0x15", "0x16", "0x17", "0x18", "0x19", "0x1A", "0x1B", "0x1C", "0x1D", "0x1E", "0x1F", "0x20", "0x21", "0x22", "0x23", "0x24", "0x25", "0x26", "0x27", "0x28", "0x29", "0x2A", "0x2B", "0x2C", "0x2D", "0x2E", "0x2F", "0x30", "0x31", "0x32", "0x33", "0x34", "0x35", "0x36", "0x37", "0x38", "0x39", "0x3A", "0x3B", "0x3C", "0x3D", "0x3E", "0x3F", "0x40", "0x41", "0x42", "0x43", "0x44", "0x45", "0x46", "0x47", "0x48", "0x49", "0x4A", "0x4B", "0x4C", "0x4D", "0x4E", "0x4F", "0x50", "0x51", "0x52", "0x53", "0x54", "0x55", "0x56", "0x57", "0x58", "0x59", "0x5A", "0x5B", "0x5C", "0x5D", "0x5E", "0x5F", "0x60", "0x61", "0x62", "0x63", "0x64", "0x65", "0x66", "0x67", "0x68", "0x69", "0x6A", "0x6B", "0x6C", "0x6D", "0x6E", "0x6F", "0x70", "0x71", "0x72", "0x73", "0x74", "0x75", "0x76", "0x77", "0x78", "0x79", "0x7A", "0x7B", "0x7C", "0x7D", "0x7E", "0x7F", "0x80", "0x81", "0x82", "0x83", "0x84", "0x85", "0x86", "0x87", "0x88", "0x89", "0x8A", "0x8B", "0x8C", "0x8D", "0x8E", "0x8F", "0x90", "0x91", "0x92", "0x93", "0x94", "0x95", "0x96", "0x97", "0x98", "0x99", "0x9A", "0x9B", "0x9C", "0x9D", "0x9E", "0x9F", "0xA0", "0xA1", "0xA2", "0xA3", "0xA4", "0xA5", "0xA6", "0xA7", "0xA8", "0xA9", "0xAA", "0xAB", "0xAC", "0xAD", "0xAE", "0xAF", "0xB0", "0xB1", "0xB2", "0xB3", "0xB4", "0xB5", "0xB6", "0xB7", "0xB8", "0xB9", "0xBA", "0xBB", "0xBC", "0xBD", "0xBE", "0xBF", "0xC0", "0xC1", "0xC2", "0xC3", "0xC4", "0xC5", "0xC6", "0xC7", "0xC8", "0xC9", "0xCA", "0xCB", "0xCC", "0xCD", "0xCE", "0xCF", "0xD0", "0xD1", "0xD2", "0xD3", "0xD4", "0xD5", "0xD6", "0xD7", "0xD8", "0xD9", "0xDA", "0xDB", "0xDC", "0xDD", "0xDE", "0xDF", "0xE0", "0xE1", "0xE2", "0xE3", "0xE4", "0xE5", "0xE6", "0xE7", "0xE8", "0xE9", "0xEA", "0xEB", "0xEC", "0xED", "0xEE", "0xEF", "0xF0", "0xF1", "0xF2", "0xF3", "0xF4", "0xF5", "0xF6", "0xF7", "0xF8", "0xF9", "0xFA", "0xFB", "0xFC", "0xFD", "0xFE", "0xFF"}; static { System.loadLibrary("opencv_support"); } //原生函数导入,用于长按保存的功能 private static native boolean SaveImage(Bitmap img, String time); @SuppressLint("HandlerLeak") public MainActivity() { //接收内部消息的处理器,用于处理内部消息 recvHandler = new Handler() { @Override public void handleMessage(Message msg) { super.handleMessage(msg); //内部消息:收到图片;执行操作:更新GUI上的图片 if (msg.what == Flags.RECEIVED_IMAGE) pic_received.setImageBitmap(currImage); //内部消息:收到主车数据;执行操作:解析指令并执行 if (msg.what == Flags.RECEIVED_CAR_DATA) { byte[] recv = (byte[]) msg.obj; if (recv != null) { //打印接收到的指令 ToastLog("RECV: [" + ByteArray2String(recv) + "]", true, false); //解析指令 CommandDecoder decoder = new CommandDecoder(recv); if (decoder.CommandReady()) { ToastLog("Command Decode Ready.", false, false); Thread th_run_command = new Thread(() -> { switch (decoder.GetMainCommand()) { //收到全自动指令,返回程序自检状态 case Commands.RECEIVE_FULL_AUTO: dtc_client.Send(SystemStatusCommand()); break; //收到QR指令,开始识别二维码,回传识别成功的数据 case Commands.RECEIVE_QR: byte[] cmd = RecognizeQrCode(); if (cmd[2] == Commands.QR_FAILED) dtc_client.Send(cmd); else { CommandEncoder encoder = new CommandEncoder(); dtc_client.Send(encoder.GenerateCommand(Commands.QR_SUCCESS_1, cmd[0], cmd[1], cmd[2])); Sleep(500); dtc_client.Send(encoder.GenerateCommand(Commands.QR_SUCCESS_2, cmd[3], cmd[4], cmd[5])); } break; //收到TRAFFIC_LIGHT指令,开始识别交通灯,回传识别成功的数据 case Commands.RECEIVE_TRAFFIC_LIGHT: dtc_client.Send(RecognizeTrafficLight()); break; //收到SHAPE_COLOR指令,开始识别形状颜色,回传识别成功的数据 case Commands.RECEIVE_SHAPE_COLOR: dtc_client.Send(RecognizeShapeColor()); break; //收到CAR_ID指令,开始识别车牌号,回传识别成功的数据 case Commands.RECEIVE_CAR_ID: RecognizeCarID(); break; //收到TRAFFIC_SIGN指令,开始识别交通标志,回传识别成功的数据 case Commands.RECEIVE_TRAFFIC_SIGN: dtc_client.Send(RecognizeTrafficSign()); break; //收到OCR指令,开始识别文本,回传识别成功的数据 case Commands.RECEIVE_TEXT_OCR: OCRRecognizeText(); break; //收到未知指令,回传异常指令,表示无法解析当前指令 default: CommandEncoder error = new CommandEncoder(); dtc_client.Send(error.GenerateCommand(Commands.CMD_NOT_MATCH, (byte) 0x00, (byte) 0x00, (byte) 0x00)); break; } }); th_run_command.start(); } //指令解析失败,回传异常指令,表示无法解析当前指令 else { CommandEncoder error = new CommandEncoder(); dtc_client.ThreadSend(error.GenerateCommand(Commands.CMD_NOT_MATCH, (byte) 0x00, (byte) 0x00, (byte) 0x00)); } } //收到NULL,输出日志,不做操作 else ToastLog("NULL Received", true, false); } //内部消息:打印数组;操作:打印收到的数组 if (msg.what == Flags.PRINT_DATA_ARRAY) { byte[] data = (byte[]) msg.obj; if (data != null) ToastLog("SEND: [" + ByteArray2String(data) + "]", false, false); } //内部消息:打印日志;操作:打印收到的日志 if (msg.what == Flags.PRINT_SYSTEM_LOG) { String str = (String) msg.obj; if (str != null) ToastLog(str, false, false); } } }; } //处理二维码数据,使用从C++代码中导出的算法 private byte[] ProcessQRData(ArrayList qr_data) { return MainCarAES.CalcAES(qr_data.get(0)); } //获取程序自检指令,根据自检状态返回成功或失败 private byte[] SystemStatusCommand() { CommandEncoder encoder = new CommandEncoder(); if (SystemStatus && FileStatus) return encoder.GenerateCommand(Commands.STATUS_SUCCESS, (byte) 0, (byte) 0, (byte) 0); else return encoder.GenerateCommand(Commands.STATUS_FAILED, (byte) 0, (byte) 0, (byte) 0); } //识别二维码 private byte[] RecognizeQrCode() { CommandEncoder encoder = new CommandEncoder(); ArrayList qr_result = new ArrayList<>(); if (!QRDecoder.BeginQRDecode(currImage)) return encoder.GenerateCommand(Commands.QR_FAILED, (byte) 0, (byte) 0, (byte) 0); while (QRDecoder.HasNextCode()) qr_result.add(QRDecoder.DecodeNextQR()); if (qr_result.size() <= 0) return encoder.GenerateCommand(Commands.QR_FAILED, (byte) 0, (byte) 0, (byte) 0); else { qr_result.forEach(qr -> ToastLog(qr, false, true)); return ProcessQRData(qr_result); } } //识别交通灯 private byte[] RecognizeTrafficLight() { TrafficLightColors color = TrafficLight.RecognizeTrafficLight(currImage); CommandEncoder encoder = new CommandEncoder(); switch (color) { case RED: return encoder.GenerateCommand(Commands.TRAFFIC_LIGHT_SUCCESS, Commands.TRAFFIC_LIGHT_RED, (byte) 0, (byte) 0); case NULL: return encoder.GenerateCommand(Commands.TRAFFIC_LIGHT_FAILED, (byte) 0, (byte) 0, (byte) 0); case GREEN: return encoder.GenerateCommand(Commands.TRAFFIC_LIGHT_SUCCESS, Commands.TRAFFIC_LIGHT_GREEN, (byte) 0, (byte) 0); case YELLOW: return encoder.GenerateCommand(Commands.TRAFFIC_LIGHT_SUCCESS, Commands.TRAFFIC_LIGHT_YELLOW, (byte) 0, (byte) 0); } return encoder.GenerateCommand(Commands.TRAFFIC_LIGHT_FAILED, (byte) -1, (byte) -1, (byte) -1); } //识别形状颜色 private byte[] RecognizeShapeColor() { CommandEncoder encoder = new CommandEncoder(); if (!ShapeColor.RecognizeEverything(currImage)) return encoder.GenerateCommand(Commands.COLOR_SHAPE_FAILED, (byte) 0, (byte) 0, (byte) 0); else { byte a = 0, b = 0, c = 0; //测试用输出 /*ToastLog("C-R-"+ShapeColor.LookupResult(GlobalShape.CIRCLE, GlobalColor.RED), false, false); ToastLog("C-BL-"+ShapeColor.LookupResult(GlobalShape.CIRCLE, GlobalColor.BLACK), false, false); ToastLog("C-G-"+ShapeColor.LookupResult(GlobalShape.CIRCLE, GlobalColor.GREEN), false, false); ToastLog("C-BU-"+ShapeColor.LookupResult(GlobalShape.CIRCLE, GlobalColor.BLUE), false, false); ToastLog("C-C-"+ShapeColor.LookupResult(GlobalShape.CIRCLE, GlobalColor.CYAN), false, false); ToastLog("C-P-"+ShapeColor.LookupResult(GlobalShape.CIRCLE, GlobalColor.PURPLE), false, false); ToastLog("C-W-"+ShapeColor.LookupResult(GlobalShape.CIRCLE, GlobalColor.WHITE), false, false); ToastLog("C-Y-"+ShapeColor.LookupResult(GlobalShape.CIRCLE, GlobalColor.YELLOW), false, false); ToastLog("S-R-"+ShapeColor.LookupResult(GlobalShape.STAR, GlobalColor.RED), false, false); ToastLog("S-BL-"+ShapeColor.LookupResult(GlobalShape.STAR, GlobalColor.BLACK), false, false); ToastLog("S-G-"+ShapeColor.LookupResult(GlobalShape.STAR, GlobalColor.GREEN), false, false); ToastLog("S-BU-"+ShapeColor.LookupResult(GlobalShape.STAR, GlobalColor.BLUE), false, false); ToastLog("S-C-"+ShapeColor.LookupResult(GlobalShape.STAR, GlobalColor.CYAN), false, false); ToastLog("S-P-"+ShapeColor.LookupResult(GlobalShape.STAR, GlobalColor.PURPLE), false, false); ToastLog("S-W-"+ShapeColor.LookupResult(GlobalShape.STAR, GlobalColor.WHITE), false, false); ToastLog("S-Y-"+ShapeColor.LookupResult(GlobalShape.STAR, GlobalColor.YELLOW), false, false); ToastLog("s-R-"+ShapeColor.LookupResult(GlobalShape.SQUARE, GlobalColor.RED), false, false); ToastLog("s-BL-"+ShapeColor.LookupResult(GlobalShape.SQUARE, GlobalColor.BLACK), false, false); ToastLog("s-G-"+ShapeColor.LookupResult(GlobalShape.SQUARE, GlobalColor.GREEN), false, false); ToastLog("s-BU-"+ShapeColor.LookupResult(GlobalShape.SQUARE, GlobalColor.BLUE), false, false); ToastLog("s-C-"+ShapeColor.LookupResult(GlobalShape.SQUARE, GlobalColor.CYAN), false, false); ToastLog("s-P-"+ShapeColor.LookupResult(GlobalShape.SQUARE, GlobalColor.PURPLE), false, false); ToastLog("s-W-"+ShapeColor.LookupResult(GlobalShape.SQUARE, GlobalColor.WHITE), false, false); ToastLog("s-Y-"+ShapeColor.LookupResult(GlobalShape.SQUARE, GlobalColor.YELLOW), false, false); ToastLog("R-R-"+ShapeColor.LookupResult(GlobalShape.RECTANGLE, GlobalColor.RED), false, false); ToastLog("R-BL-"+ShapeColor.LookupResult(GlobalShape.RECTANGLE, GlobalColor.BLACK), false, false); ToastLog("R-G-"+ShapeColor.LookupResult(GlobalShape.RECTANGLE, GlobalColor.GREEN), false, false); ToastLog("R-BU-"+ShapeColor.LookupResult(GlobalShape.RECTANGLE, GlobalColor.BLUE), false, false); ToastLog("R-C-"+ShapeColor.LookupResult(GlobalShape.RECTANGLE, GlobalColor.CYAN), false, false); ToastLog("R-P-"+ShapeColor.LookupResult(GlobalShape.RECTANGLE, GlobalColor.PURPLE), false, false); ToastLog("R-W-"+ShapeColor.LookupResult(GlobalShape.RECTANGLE, GlobalColor.WHITE), false, false); ToastLog("R-Y-"+ShapeColor.LookupResult(GlobalShape.RECTANGLE, GlobalColor.YELLOW), false, false); ToastLog("T-R-"+ShapeColor.LookupResult(GlobalShape.TRIANGLE, GlobalColor.RED), false, false); ToastLog("T-BL-"+ShapeColor.LookupResult(GlobalShape.TRIANGLE, GlobalColor.BLACK), false, false); ToastLog("T-G-"+ShapeColor.LookupResult(GlobalShape.TRIANGLE, GlobalColor.GREEN), false, false); ToastLog("T-BU-"+ShapeColor.LookupResult(GlobalShape.TRIANGLE, GlobalColor.BLUE), false, false); ToastLog("T-C-"+ShapeColor.LookupResult(GlobalShape.TRIANGLE, GlobalColor.CYAN), false, false); ToastLog("T-P-"+ShapeColor.LookupResult(GlobalShape.TRIANGLE, GlobalColor.PURPLE), false, false); ToastLog("T-W-"+ShapeColor.LookupResult(GlobalShape.TRIANGLE, GlobalColor.WHITE), false, false); ToastLog("T-Y-"+ShapeColor.LookupResult(GlobalShape.TRIANGLE, GlobalColor.YELLOW), false, false);*/ return encoder.GenerateCommand(Commands.COLOR_SHAPE_SUCCESS, a, b, c); } } //识别车牌 private void RecognizeCarID() { CommandEncoder encoder = new CommandEncoder(); // CarLicense.Result result = CarLicense.Recognize(currImage); //通过模板匹配识别车牌 // CarLicense.Result result = CarLicense.RecognizeByOCR(currImage); //通过OCR识别车牌 CarLicense.Result result = CarLicense.RecognizeByAI(currImage, this); //通过AI模型识别车牌 if (!result.Success()) { //OCR识别的自动重试功能 /*final int OCR_MAX_RETRY = 5; int retry_time = 0; do { result = CarLicense.RecognizeByOCR(currImage); Sleep(100); retry_time++; }while (result.isEmpty() && (retry_time <= OCR_MAX_RETRY)); if(retry_time > OCR_MAX_RETRY) dtc_client.Send(encoder.GenerateCommand(Commands.CAR_ID_FAILED, (byte) 0, (byte) 0, (byte) 0)); else { encoder.AddMainCommand(Commands.CAR_ID_SUCCESS_FIRST); encoder.AddData(result.GetFirstThreeBits()); dtc_client.Send(encoder.GenerateCommand()); Sleep(500); encoder.Clear(); encoder.AddMainCommand(Commands.CAR_ID_SUCCESS_SECOND); encoder.AddData(result.GetLastThreeBits()); dtc_client.Send(encoder.GenerateCommand()); }*/ dtc_client.Send(encoder.GenerateCommand(Commands.CAR_ID_FAILED, (byte) 0, (byte) 0, (byte) 0)); } else { //车牌信息分两次发送 encoder.AddMainCommand(Commands.CAR_ID_SUCCESS_FIRST); encoder.AddData(result.GetFirstThreeBits()); dtc_client.Send(encoder.GenerateCommand()); Sleep(500); encoder.Clear(); encoder.AddMainCommand(Commands.CAR_ID_SUCCESS_SECOND); encoder.AddData(result.GetLastThreeBits()); dtc_client.Send(encoder.GenerateCommand()); } } //识别交通标志 private byte[] RecognizeTrafficSign() { CommandEncoder encoder = new CommandEncoder(); GlobalSignType type = TrafficSign.SignRecognize(currImage); if (type == GlobalSignType.Failure) return encoder.GenerateCommand(Commands.TRAFFIC_SIGN_FAILED, (byte) 0, (byte) 0, (byte) 0); else { encoder.AddMainCommand(Commands.TRAFFIC_SIGN_SUCCESS); switch (type) { case NoEntry: encoder.AddData(Commands.TRAFFIC_SIGN_TYPE_NO_ENTRY, (byte) 0, (byte) 0); break; case StraightProhibited: encoder.AddData(Commands.TRAFFIC_SIGN_TYPE_NO_STRAIGHT, (byte) 0, (byte) 0); break; case TurnLeft: encoder.AddData(Commands.TRAFFIC_SIGN_TYPE_TURN_LEFT, (byte) 0, (byte) 0); break; case TurnRight: encoder.AddData(Commands.TRAFFIC_SIGN_TYPE_TURN_RIGHT, (byte) 0, (byte) 0); break; case GoStraight: encoder.AddData(Commands.TRAFFIC_SIGN_TYPE_STRAIGHT, (byte) 0, (byte) 0); break; case U_Turn: encoder.AddData(Commands.TRAFFIC_SIGN_TYPE_U_TURN, (byte) 0, (byte) 0); break; } return encoder.GenerateCommand(); } } //识别静态文本 private void OCRRecognizeText() { TextFilter filter = new TextFilter(); String str = filter.RemoveEmptyCharacter(OCR.DecodeImage(currImage)); ToastLog("OCR Result: [" + str + "]", false, true); byte[] b_str; try { b_str = str.getBytes("GBK"); } catch (UnsupportedEncodingException e) { ToastLog("GBK Encoding is Not Supported", false, true); CommandEncoder encoder = new CommandEncoder(); dtc_client.Send(encoder.GenerateCommand(Commands.OCR_TEXT_FAILED, (byte) 0x00, (byte) 0x00, (byte) 0x00)); return; } CommandEncoder encoder = new CommandEncoder(); dtc_client.Send(encoder.GenerateCommand(Commands.OCR_TEXT_SUCCESS, (byte) 0x00, (byte) 0x00, (byte) 0x00)); Sleep(900); dtc_client.Send(encoder.GenerateCommand(Commands.OCR_TEXT_LENGTH, (byte) b_str.length, (byte) 0x00, (byte) b_str.length)); for (int i = 0; i < b_str.length; i += 2) { Sleep(500); byte data_2 = ((i + 1) >= b_str.length ? 0x00 : b_str[i + 1]); byte checksum = (byte) ((b_str[i] + data_2) % 0xFF); byte main = ((i + 2) < b_str.length ? Commands.OCR_TEXT_DATA : Commands.OCR_TEXT_FINISH); if (!dtc_client.SendEx(encoder.GenerateCommand(main, b_str[i], data_2, checksum), Commands.RECEIVE_OCR_DATA_OK, 2000)) { dtc_client.Send(encoder.GenerateCommand(Commands.OCR_TEXT_FAILED, (byte) 0x00, (byte) 0x00, (byte) 0x00)); break; } } } //数组转字符串,仅用于调试输出 private String ByteArray2String(byte[] arr) { StringBuilder msg_str = new StringBuilder(); for (byte b : arr) msg_str.append(byte_str[b & 0xff]).append(" "); return msg_str.toString(); } //初始化图形界面 private void InitGUI() { pic_received = findViewById(R.id.camera_image); text_toast = findViewById(R.id.text_toast); text_toast.setMovementMethod(ScrollingMovementMethod.getInstance()); findViewById(R.id.btn_debug_send).setOnClickListener(view -> { byte[] data = new byte[]{0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07}; dtc_client.ThreadSend(data); }); findViewById(R.id.btn_camera_up).setOnClickListener(view -> { Thread th_send = new Thread(() -> cameraCommandUtil.postHttp(IPCamera, Flags.CAMERA_UP, 5)); th_send.start(); }); findViewById(R.id.btn_camera_down).setOnClickListener(view -> { Thread th_send = new Thread(() -> cameraCommandUtil.postHttp(IPCamera, Flags.CAMERA_DOWN, 5)); th_send.start(); }); findViewById(R.id.btn_camera_left).setOnClickListener(view -> { Thread th_send = new Thread(() -> cameraCommandUtil.postHttp(IPCamera, Flags.CAMERA_LEFT, 5)); th_send.start(); }); findViewById(R.id.btn_camera_right).setOnClickListener(view -> { Thread th_send = new Thread(() -> cameraCommandUtil.postHttp(IPCamera, Flags.CAMERA_RIGHT, 5)); th_send.start(); }); findViewById(R.id.btn_send).setOnClickListener(view -> { try { byte cmd0 = (byte) Integer.parseInt(((EditText) findViewById(R.id.edit_cmd0)).getText().toString(), 16); byte cmd1 = (byte) Integer.parseInt(((EditText) findViewById(R.id.edit_cmd1)).getText().toString(), 16); byte cmd2 = (byte) Integer.parseInt(((EditText) findViewById(R.id.edit_cmd2)).getText().toString(), 16); byte cmd3 = (byte) Integer.parseInt(((EditText) findViewById(R.id.edit_cmd3)).getText().toString(), 16); CommandEncoder encoder = new CommandEncoder(); byte[] cmd = encoder.GenerateCommand(cmd0, cmd1, cmd2, cmd3); dtc_client.ThreadSend(cmd); //print debug information Message.obtain(recvHandler, Flags.PRINT_DATA_ARRAY, cmd).sendToTarget(); } catch (Exception e) { ToastLog("Input Data Invalidate", true, false); } }); findViewById(R.id.btn_start_qr).setOnClickListener(view -> { ToastLog("QR Code Started", false, false); ToastLog("QR Result: " + ByteArray2String(RecognizeQrCode()), false, false); }); findViewById(R.id.btn_start_light).setOnClickListener(view -> { ToastLog("Traffic Light Started", false, false); ToastLog("TL Result: " + ByteArray2String(RecognizeTrafficLight()), false, false); }); findViewById(R.id.btn_start_color_shape).setOnClickListener(view -> { ToastLog("Color Shape Started", false, false); ToastLog("CS Result: " + ByteArray2String(RecognizeShapeColor()), false, false); }); findViewById(R.id.btn_start_car_id).setOnClickListener(view -> { ToastLog("Car ID Started", false, false); Thread th_debug = new Thread(this::RecognizeCarID); th_debug.start(); ToastLog("CID Finished", false, false); }); findViewById(R.id.btn_start_sign).setOnClickListener(view -> { ToastLog("Traffic Sign Started", false, false); ToastLog("TS Result: " + ByteArray2String(RecognizeTrafficSign()), false, false); }); findViewById(R.id.btn_start_ocr).setOnClickListener(view -> { ToastLog("OCR Started", false, false); /*ToastLog("OCR Result: " + OCR.DecodeImage(currImage), false, false);*/ Thread th_debug = new Thread(this::OCRRecognizeText); th_debug.start(); }); findViewById(R.id.btn_tft_page_down).setOnClickListener(view -> { CommandEncoder encoder = new CommandEncoder(); dtc_client.ThreadSend(encoder.GenerateCommand(Commands.TFT_PAGE_DOWN, (byte) 0, (byte) 0, (byte) 0)); ToastLog("TFT Page Down Command Send.", false, true); }); findViewById(R.id.btn_movement_control).setOnClickListener(view -> { startActivity(new Intent(this, MovementController.class)); }); findViewById(R.id.btn_crash).setOnClickListener(view -> { //崩溃按钮的作用:频繁调试时省去手动退出程序,清理后台的操作,节省时间。 dtc_client.DisableAutoReconnect(); dtc_client.CloseConnection(); //关闭通信 throw new NullPointerException(); //通过异常来崩溃。 }); findViewById(R.id.text_toast).setOnLongClickListener(view -> { ToastLog("Log Cleared", true, false); ((TextView) view).setText(""); return true; }); findViewById(R.id.camera_image).setOnLongClickListener(view -> { String time = String.valueOf(System.currentTimeMillis()); if (SaveImage(currImage, time)) ToastLog("Image Saved", true, false); else ToastLog("Image Save Failure", true, false); return true; }); } //打印日志 @SuppressLint("SetTextI18n") private void ToastLog(String text, boolean real_toast, boolean on_thread) { if (text_toast == null) text_toast = findViewById(R.id.text_toast); if (real_toast) Toast.makeText(this, text, Toast.LENGTH_SHORT).show(); Log.i("ToastBackup", text); if (on_thread) Message.obtain(recvHandler, Flags.PRINT_SYSTEM_LOG, text); else text_toast.setText(text_toast.getText().toString() + "\n" + text); } //等待一段时间 private void Sleep(long ms) { try { Thread.sleep(ms); } catch (InterruptedException ignored) { } } //启动寻找摄像头的线程 private void StartCameraImageUpdate(int duration) { Thread th_image = new Thread(() -> { while (true) { currImage = cameraCommandUtil.httpForImage(IPCamera); recvHandler.sendEmptyMessage(Flags.RECEIVED_IMAGE); Sleep(duration); } }); th_image.start(); ToastLog("Camera Update Thread: " + th_image.getState(), false, true); } @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); Objects.requireNonNull(getSupportActionBar()).setTitle("主车远端服务程序"); //初始化图形用户界面 InitGUI(); ToastLog("GUI Init Finished.", false, false); //检查NDK及引用库 ToastLog(EnvTest.TestNDK(), false, false); ToastLog(EnvTest.TestOpenCV(), false, false); ToastLog(EnvTest.TestTrafficLightReco(), false, false); ToastLog(EnvTest.TestImageProcessor(), false, false); ToastLog(EnvTest.TestColorReco(), false, false); ToastLog(EnvTest.TestShapeReco(), false, false); ToastLog(EnvTest.TestShapeColorReco(), false, false); ToastLog(EnvTest.TestCarLicenseReco(), false, false); ToastLog(EnvTest.TestTrafficSignReco(), false, false); ToastLog(EnvTest.TestOCRText(), false, false); ToastLog(EnvTest.TestMainCarAES(), false, false); byte[] demo = MainCarAES.CalcAES("ABCDEFGHabcdefgh"); if (demo == null) ToastLog("AES Status: Error", false, false); else ToastLog("AES Status: " + ByteArray2String(demo), false, false); //二维码扫描自检 ToastLog(QRDecoder.SelfTest(BitmapFactory.decodeResource(getResources(), R.drawable.qr_decode_test)), false, false); //获取主车IP地址 wifiManager = (WifiManager) getApplicationContext().getSystemService(Context.WIFI_SERVICE); dhcpInfo = wifiManager.getDhcpInfo(); IPCar = Formatter.formatIpAddress(dhcpInfo.gateway); ToastLog("DHCP Server Address: " + IPCar, false, false); //建立连接 if (CommunicationUsingWifi) dtc_client = new WifiTransferCore(IPCar, 60000, recvHandler); else dtc_client = new SerialPortTransferCore(SerialPortPath, 115200, recvHandler); Thread th_connect = new Thread(() -> { if (dtc_client.Connect()) ToastLog("Client Connected", false, true); else ToastLog("Client Connect Failed", false, true); }); th_connect.start(); while (th_connect.isAlive()) Sleep(10); //Wait for Connection Thread dtc_client.EnableAutoReconnect(); //启动自动重连 //初始化摄像头控制 cameraCommandUtil = new CameraCommandUtil(); ToastLog("CameraCommandUtil Ready.", false, false); //寻找摄像头,获取其IP地址 Thread camera_thread = new Thread(() -> { IPCamera = null; ToastLog("CameraSearchThread: Camera Thread Start", false, true); while (IPCamera == null || IPCamera.equals("")) { searchCameraUtil = new SearchCameraUtil(); try { IPCamera = searchCameraUtil.send(); } catch (NullPointerException e) { IPCamera = null; } } ToastLog("CameraSearchThread: Camera Found. IP: " + IPCamera, false, true); IPCamera = IPCamera + ":81"; ToastLog("Camera Address: " + IPCamera, false, true); StartCameraImageUpdate(50); //这里是程序初始化的最后一步,能到达此处标志着自检通过 SystemStatus = true; }); camera_thread.start(); //获取外部存储权限并释放识别使用的标准图和OCR的训练模型 Intent permission_page = new Intent(this, PermissionGetter.class); startActivityForResult(permission_page, permission_request_code); } @Override protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) { super.onActivityResult(requestCode, resultCode, data); if (requestCode == permission_request_code) { if (resultCode == RESULT_OK) { ImageReleaser releaser = new ImageReleaser(this); OCRDataReleaser releaser_ocr = new OCRDataReleaser(this); FileStatus = (releaser.ReleaseAllImage() && releaser_ocr.ReleaseAllFiles()); ToastLog(releaser.toString(), false, false); ToastLog(releaser_ocr.toString(), false, false); if (FileStatus) ToastLog(OCR.SelfTest(this), false, false); //OCR光学字符识别自检 } else FileStatus = false; } } @Override protected void onDestroy() { super.onDestroy(); //Activity销毁时关闭通信 dtc_client.DisableAutoReconnect(); dtc_client.CloseConnection(); } }