Commit 2e585391 by pye52

Merge branch 'develop' into uat

parents 3048f2b2 e5889123
...@@ -58,6 +58,10 @@ android { ...@@ -58,6 +58,10 @@ android {
} }
} }
} }
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
} }
dependencies { dependencies {
...@@ -68,13 +72,13 @@ dependencies { ...@@ -68,13 +72,13 @@ dependencies {
implementation "org.java-websocket:Java-WebSocket:1.4.0" implementation "org.java-websocket:Java-WebSocket:1.4.0"
implementation 'org.greenrobot:eventbus:3.1.1' implementation 'org.greenrobot:eventbus:3.1.1'
implementation 'com.github.salomonbrys.kotson:kotson:2.5.0' implementation 'com.github.salomonbrys.kotson:kotson:2.5.0'
implementation 'com.blankj:utilcode:1.25.9' implementation 'com.blankj:utilcode:1.26.0'
implementation 'com.squareup.okhttp3:okhttp:3.12.1' implementation 'com.squareup.okhttp3:okhttp:3.12.10'
implementation 'com.squareup.okhttp3:logging-interceptor:3.10.0' implementation 'com.squareup.okhttp3:logging-interceptor:3.12.10'
implementation 'com.squareup.retrofit2:retrofit:2.6.2' implementation 'com.squareup.retrofit2:retrofit:2.7.1'
implementation 'com.squareup.retrofit2:converter-gson:2.6.0' implementation 'com.squareup.retrofit2:converter-gson:2.7.1'
implementation 'com.squareup.retrofit2:converter-scalars:2.6.0' implementation 'com.squareup.retrofit2:converter-scalars:2.7.1'
testImplementation 'junit:junit:4.12' testImplementation 'junit:junit:4.13'
androidTestImplementation 'com.android.support.test:runner:1.0.2' androidTestImplementation 'com.android.support.test:runner:1.0.2'
androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2' androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2'
} }
package android_serialport_api;
import java.io.File;
import java.io.FileDescriptor;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.OutputStream;
/**
* Google官方代码
* 此类的作用为,JNI的调用,用来加载.so文件的
* 获取串口输入输出流
*/
public class SerialPort {
private static final String TAG = "SerialPort";
public static SerialPort build(File device, int baudrate, int flags) {
/* Check access permission */
if (!device.canRead() || !device.canWrite()) {
try {
/* Missing read/write permission, trying to chmod the file */
Process su;
su = Runtime.getRuntime().exec("/system/bin/su");
String cmd = "chmod 666 " + device.getAbsolutePath() + "\n" + "exit\n";
su.getOutputStream().write(cmd.getBytes());
if ((su.waitFor() != 0) || !device.canRead() || !device.canWrite()) {
return null;
}
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
System.out.println(device.getAbsolutePath() + "==============================");
FileDescriptor fd = open(device.getAbsolutePath(), baudrate, flags);
if (fd == null) return null;
return new SerialPort(fd);
}
/*
* Do not remove or rename the field mFd: it is used by native method
* close();
*/
private FileDescriptor mFd;
private FileInputStream mFileInputStream;
private FileOutputStream mFileOutputStream;
private SerialPort(FileDescriptor fd) {
mFd = fd;
mFileInputStream = new FileInputStream(mFd);
mFileOutputStream = new FileOutputStream(mFd);
}
// Getters and setters
public InputStream getInputStream() {
return mFileInputStream;
}
public OutputStream getOutputStream() {
return mFileOutputStream;
}
// JNI
private native static FileDescriptor open(String path, int baudrate, int flags);
public native void close();
static {
System.out.println("==============================");
System.loadLibrary("serial_port");
System.out.println("********************************");
}
}
package android_serialport_api;
import android.util.Log;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.io.LineNumberReader;
import java.util.Iterator;
import java.util.Vector;
/**
* Google官方代码
* 此类的作用为,寻找得到有效的串口的物理地址。
* 如果你本身就知道串口的地址如:ttyS1、ttyS2,那么这个类就可以不用了。
*
*/
public class SerialPortFinder {
public class Driver {
public Driver(String name, String root) {
mDriverName = name;
mDeviceRoot = root;
}
private String mDriverName;
private String mDeviceRoot;
Vector<File> mDevices = null;
public Vector<File> getDevices() {
if (mDevices == null) {
mDevices = new Vector<File>();
File dev = new File("/dev");
File[] files = dev.listFiles();
int i;
for (i=0; i<files.length; i++) {
if (files[i].getAbsolutePath().startsWith(mDeviceRoot)) {
Log.d(TAG, "Found new device: " + files[i]);
mDevices.add(files[i]);
}
}
}
return mDevices;
}
public String getName() {
return mDriverName;
}
}
private static final String TAG = "SerialPort";
private Vector<Driver> mDrivers = null;
Vector<Driver> getDrivers() throws IOException {
if (mDrivers == null) {
mDrivers = new Vector<Driver>();
LineNumberReader r = new LineNumberReader(new FileReader("/proc/tty/drivers"));
String l;
while((l = r.readLine()) != null) {
// Issue 3:
// Since driver name may contain spaces, we do not extract driver name with split()
String drivername = l.substring(0, 0x15).trim();
String[] w = l.split(" +");
if ((w.length >= 5) && (w[w.length-1].equals("serial"))) {
Log.d(TAG, "Found new driver " + drivername + " on " + w[w.length-4]);
mDrivers.add(new Driver(drivername, w[w.length-4]));
}
}
r.close();
}
return mDrivers;
}
public String[] getAllDevices() {
Vector<String> devices = new Vector<String>();
// Parse each driver
Iterator<Driver> itdriv;
try {
itdriv = getDrivers().iterator();
while(itdriv.hasNext()) {
Driver driver = itdriv.next();
Iterator<File> itdev = driver.getDevices().iterator();
while(itdev.hasNext()) {
String device = itdev.next().getName();
String value = String.format("%s (%s)", device, driver.getName());
devices.add(value);
}
}
} catch (IOException e) {
e.printStackTrace();
}
return devices.toArray(new String[devices.size()]);
}
public String[] getAllDevicesPath() {
Vector<String> devices = new Vector<String>();
// Parse each driver
Iterator<Driver> itdriv;
try {
itdriv = getDrivers().iterator();
while(itdriv.hasNext()) {
Driver driver = itdriv.next();
Iterator<File> itdev = driver.getDevices().iterator();
while(itdev.hasNext()) {
String device = itdev.next().getAbsolutePath();
devices.add(device);
}
}
} catch (IOException e) {
e.printStackTrace();
}
return devices.toArray(new String[devices.size()]);
}
}
package com.bgycc.smartcanteen package com.bgycc.smartcanteen
import android.Manifest
import android.app.ActivityManager import android.app.ActivityManager
import android.app.Application import android.app.Application
import android.content.Context import android.content.Context
...@@ -10,18 +9,20 @@ import com.bgycc.smartcanteen.helper.TTSHelper ...@@ -10,18 +9,20 @@ import com.bgycc.smartcanteen.helper.TTSHelper
import com.bgycc.smartcanteen.helper.TimerHelper import com.bgycc.smartcanteen.helper.TimerHelper
import com.bgycc.smartcanteen.helper.WifiHelpler import com.bgycc.smartcanteen.helper.WifiHelpler
import com.bgycc.smartcanteen.manager.NetworkManager import com.bgycc.smartcanteen.manager.NetworkManager
import com.bgycc.smartcanteen.util.LogUtil
import com.bgycc.smartcanteen.module.Device import com.bgycc.smartcanteen.module.Device
import com.bgycc.smartcanteen.util.LogUtil
import com.blankj.utilcode.constant.PermissionConstants import com.blankj.utilcode.constant.PermissionConstants
import com.blankj.utilcode.util.CrashUtils
import com.blankj.utilcode.util.LogUtils import com.blankj.utilcode.util.LogUtils
import com.blankj.utilcode.util.PermissionUtils import com.blankj.utilcode.util.PermissionUtils
import java.lang.Exception import java.io.File
import kotlin.system.exitProcess import kotlin.system.exitProcess
class App : Application() { class App : Application() {
companion object { companion object {
private lateinit var sDefault: App private lateinit var sDefault: App
private const val LOG_DIR = "log"
private val sInstances = HashMap<String, App>() private val sInstances = HashMap<String, App>()
private var sVersionName = "0.0.0" private var sVersionName = "0.0.0"
private var sVersionCode = 0 private var sVersionCode = 0
...@@ -96,7 +97,12 @@ class App : Application() { ...@@ -96,7 +97,12 @@ class App : Application() {
private fun initLog() { private fun initLog() {
LogUtil.setEnable(BuildConfig.DEBUG) LogUtil.setEnable(BuildConfig.DEBUG)
val config = LogUtils.getConfig() val logDir: String = applicationContext.filesDir.absolutePath + File.separator + LOG_DIR
config.saveDays = 7 CrashUtils.init(logDir)
LogUtils.getConfig()
.setDir(logDir)
.setLog2FileSwitch(true)
.setBorderSwitch(false)
.saveDays = 7
} }
} }
\ No newline at end of file
...@@ -46,7 +46,7 @@ object LogAction : Action(ActionEnum.LOG_PULL.name) { ...@@ -46,7 +46,7 @@ object LogAction : Action(ActionEnum.LOG_PULL.name) {
val logZipFile = File(PathUtils.getExternalAppCachePath(), "upload/log.zip") val logZipFile = File(PathUtils.getExternalAppCachePath(), "upload/log.zip")
val logUploadDir = File(PathUtils.getExternalAppCachePath(), "upload/log") val logUploadDir = File(PathUtils.getExternalAppCachePath(), "upload/log")
FileUtils.delete(logZipFile) FileUtils.delete(logZipFile)
FileUtils.deleteDir(logUploadDir) FileUtils.delete(logUploadDir)
logUploadDir.mkdirs() logUploadDir.mkdirs()
val logDir = when (type) { val logDir = when (type) {
...@@ -56,11 +56,11 @@ object LogAction : Action(ActionEnum.LOG_PULL.name) { ...@@ -56,11 +56,11 @@ object LogAction : Action(ActionEnum.LOG_PULL.name) {
FileUtils.listFilesInDir(logDir)?.forEach { FileUtils.listFilesInDir(logDir)?.forEach {
val date = Date(it.lastModified()) val date = Date(it.lastModified())
if (date >= startTime && date <= endTime) { if (date >= startTime && date <= endTime) {
FileUtils.copyFile(it, File(logUploadDir, it.name)) FileUtils.copy(it, File(logUploadDir, it.name))
} }
} }
ZipUtils.zipFile(logUploadDir, logZipFile) ZipUtils.zipFile(logUploadDir, logZipFile)
FileUtils.deleteDir(logUploadDir) FileUtils.delete(logUploadDir)
MainHttpClient.uploadLog(logZipFile, "$type${formatSrc.format(startTime)}${formatSrc.format(endTime)}${App.getDeviceSN()}.zip") MainHttpClient.uploadLog(logZipFile, "$type${formatSrc.format(startTime)}${formatSrc.format(endTime)}${App.getDeviceSN()}.zip")
} catch (e: Exception) {} } catch (e: Exception) {}
state = State.INITED state = State.INITED
......
...@@ -48,54 +48,83 @@ public class MainWebSocket extends WebSocketClient { ...@@ -48,54 +48,83 @@ public class MainWebSocket extends WebSocketClient {
public static final String CODE_FAIL = "-1"; public static final String CODE_FAIL = "-1";
private static MainWebSocket sInstance; private static MainWebSocket sInstance;
private static long lastLoopId = -1;
private static String sDeviceSN; private static String sDeviceSN;
private static int sReconnectTimes = 0; private static int sReconnectTimes = 0;
private static int sAutoCheckCount = 0; private static int sAutoCheckCount = 0;
public static void initialize() { public static void initialize() {
if (sInstance == null) { if (sInstance != null) {
try { return;
sDeviceSN = App.Companion.getDeviceSN(); }
if (sDeviceSN.isEmpty()) return; sDeviceSN = App.Companion.getDeviceSN();
if (sDeviceSN.isEmpty()) {
EventBus.getDefault().post(new ConnectStateEvent(ConnectStateEvent.CONNECTING)); LogUtils.file(TAG, "device id is empty");
sInstance = new MainWebSocket(new URI(AppConfig.INSTANCE.getMainWebSocketServerUrl(sDeviceSN, BuildConfig.VERSION_NAME))); return;
sInstance.setConnectionLostTimeout(10); }
sInstance.connect();
TimerHelper.INSTANCE.loop(new TimerHelper.LoopTask() { EventBus.getDefault().post(new ConnectStateEvent(ConnectStateEvent.CONNECTING));
@Override String host = AppConfig.INSTANCE.getMainWebSocketServerUrl(sDeviceSN, BuildConfig.VERSION_NAME);
public void run(long id, boolean isLastTime) { LogUtil.i(TAG, "try connecting to host: " + host);
if (sInstance.isClosed()) { try {
if (sReconnectTimes < 2) { sInstance = new MainWebSocket(new URI(host));
sReconnectTimes++; } catch (URISyntaxException e) {
sInstance.reconnect(); LogUtil.i(TAG, "invalidate host: " + host, e);
EventBus.getDefault().post(new ConnectStateEvent(ConnectStateEvent.RECONNECTING)); }
} else { sInstance.setConnectionLostTimeout(10);
sReconnectTimes = 0; sInstance.connect();
NetworkManager.INSTANCE.switchNetwork(); // 保证只有一个loop在运行
EventBus.getDefault().post(new ConnectStateEvent(ConnectStateEvent.CHANGE_NETWORK)); if (lastLoopId != -1) {
} TimerHelper.INSTANCE.cancel(lastLoopId);
sAutoCheckCount = 0; }
} else { lastLoopId = TimerHelper.INSTANCE.loop(new TimerHelper.LoopTask() {
// 每10分钟发一次心跳包给后端 @Override
sAutoCheckCount -= 2; public void run(long id, boolean isLastTime) {
if (sAutoCheckCount < 0) { try {
sAutoCheckCount = 10 * 60; if (sInstance == null) {
try { LogUtils.file(TAG, "instance of socket could not be null!!!");
JSONObject data = new JSONObject(); initialize();
data.put(FieldEnum.equipmentId.name(), sDeviceSN); return;
action(ActionEnum.AUTO_CHECK_DEVICE.name(), data, null); }
} catch (Exception e) { if (sInstance.isClosed()) {
LogUtil.e(TAG, "action error: " + e.getMessage(), e); doReconnect();
} } else {
} doHeartbeat();
} }
} catch (Exception e) {
LogUtils.file(TAG, "fatal error: " + e.getMessage());
}
}
private void doReconnect() {
if (sReconnectTimes < 2) {
sReconnectTimes++;
sInstance.reconnect();
EventBus.getDefault().post(new ConnectStateEvent(ConnectStateEvent.RECONNECTING));
} else {
sReconnectTimes = 0;
NetworkManager.INSTANCE.switchNetwork();
EventBus.getDefault().post(new ConnectStateEvent(ConnectStateEvent.CHANGE_NETWORK));
}
sAutoCheckCount = 0;
}
private void doHeartbeat() {
// 每3分钟发一次心跳包给后端
// 原为10分钟一次,现改为3分钟一次以方便后台预警功能
sAutoCheckCount -= 2;
if (sAutoCheckCount < 0) {
sAutoCheckCount = 3 * 60;
try {
JSONObject data = new JSONObject();
data.put(FieldEnum.equipmentId.name(), sDeviceSN);
action(ActionEnum.AUTO_CHECK_DEVICE.name(), data, null);
} catch (Exception e) {
LogUtil.e(TAG, "action error: " + e.getMessage(), e);
} }
}, 2000, -1, 2000); }
} catch (URISyntaxException e) {
LogUtils.file(TAG, "fatal error: " + e.getMessage());
} }
} }, 2000, -1, 2000);
} }
public static boolean isInited() { public static boolean isInited() {
......
package com.bgycc.smartcanteen.task; package com.bgycc.smartcanteen.task;
import android_serialport_api.SerialPort;
import com.bgycc.smartcanteen.App; import com.bgycc.smartcanteen.App;
import com.bgycc.smartcanteen.Storage.PayStorage; import com.bgycc.smartcanteen.Storage.PayStorage;
import com.bgycc.smartcanteen.event.QRCodeEvent; import com.bgycc.smartcanteen.event.QRCodeEvent;
...@@ -11,10 +10,11 @@ import com.bgycc.smartcanteen.helper.TimerHelper; ...@@ -11,10 +10,11 @@ import com.bgycc.smartcanteen.helper.TimerHelper;
import com.bgycc.smartcanteen.server.websocket.MainWebSocket; import com.bgycc.smartcanteen.server.websocket.MainWebSocket;
import com.bgycc.smartcanteen.util.ByteUtil; import com.bgycc.smartcanteen.util.ByteUtil;
import com.blankj.utilcode.util.LogUtils; import com.blankj.utilcode.util.LogUtils;
import com.telpo.tps550.api.serial.Serial;
import org.greenrobot.eventbus.EventBus; import org.greenrobot.eventbus.EventBus;
import org.json.JSONObject; import org.json.JSONObject;
import java.io.File;
import java.util.Arrays; import java.util.Arrays;
import java.util.regex.Pattern; import java.util.regex.Pattern;
...@@ -36,7 +36,7 @@ public class QRCodeTask { ...@@ -36,7 +36,7 @@ public class QRCodeTask {
} }
private ScanAsyncTask mScanAsyncTask; private ScanAsyncTask mScanAsyncTask;
private SerialPort mSerial; private Serial mSerial;
private long mTimerId = -1; private long mTimerId = -1;
private long mOfflineTimerId = -1; private long mOfflineTimerId = -1;
private long mOfflineUpdateDelay = 0; private long mOfflineUpdateDelay = 0;
...@@ -51,7 +51,11 @@ public class QRCodeTask { ...@@ -51,7 +51,11 @@ public class QRCodeTask {
if (!support()) return; if (!support()) return;
if (mScanAsyncTask == null) { if (mScanAsyncTask == null) {
mSerial = SerialPort.build(new File("/dev/ttyS6"), 115200, 0); try {
mSerial = new Serial("/dev/ttyS0", 115200, 0);
} catch (Exception e) {
LogUtils.file("串口初始化失败");
}
mScanAsyncTask = new ScanAsyncTask(); mScanAsyncTask = new ScanAsyncTask();
mTimerId = TimerHelper.INSTANCE.loop(new TimerHelper.LoopTask() { mTimerId = TimerHelper.INSTANCE.loop(new TimerHelper.LoopTask() {
@Override @Override
......
...@@ -3,11 +3,11 @@ ...@@ -3,11 +3,11 @@
buildscript { buildscript {
ext.kotlin_version = '1.3.61' ext.kotlin_version = '1.3.61'
repositories { repositories {
maven { url 'https://maven.aliyun.com/repository/google' } jcenter()
maven { url 'https://maven.aliyun.com/repository/jcenter' } google()
} }
dependencies { dependencies {
classpath 'com.android.tools.build:gradle:3.4.2' classpath 'com.android.tools.build:gradle:3.6.1'
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
classpath "org.jetbrains.kotlin:kotlin-android-extensions:$kotlin_version" classpath "org.jetbrains.kotlin:kotlin-android-extensions:$kotlin_version"
// NOTE: Do not place your application dependencies here; they belong // NOTE: Do not place your application dependencies here; they belong
...@@ -17,8 +17,8 @@ buildscript { ...@@ -17,8 +17,8 @@ buildscript {
allprojects { allprojects {
repositories { repositories {
maven { url 'https://maven.aliyun.com/repository/google' } jcenter()
maven { url 'https://maven.aliyun.com/repository/jcenter' } google()
} }
} }
......
...@@ -3,4 +3,4 @@ distributionBase=GRADLE_USER_HOME ...@@ -3,4 +3,4 @@ distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists zipStorePath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-5.1.1-all.zip distributionUrl=https\://services.gradle.org/distributions/gradle-5.6.4-all.zip
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or sign in to comment