Android CounDownTimer.cancel() 不工作
Android CounDownTimer.cancel() not working
我正在尝试为 Android 进行串行 IEC 通信,我需要检查设备是否发送了一些数据。我在通信开始时启动了一个计时器,并在收到一些数据时将其重置。重置传入数据有效,但在保存数据之前取消无效。我不明白为什么。
这是我的 MainActivity.java 代码
package cz.trisko.jan.amr;
import android.content.Context;
import android.media.MediaPlayer;
import android.os.Bundle;
import android.os.CountDownTimer;
import android.os.Environment;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;
import android.view.View;
import android.widget.ProgressBar;
import android.widget.RadioButton;
import android.widget.RadioGroup;
import android.widget.TextView;
import android.widget.Toast;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.math.BigInteger;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.Map;
import java.util.regex.Pattern;
import java.util.regex.Matcher;
import android.hardware.usb.UsbDevice;
import android.hardware.usb.UsbManager;
import android.hardware.usb.UsbDeviceConnection;
import com.felhr.usbserial.UsbSerialDevice;
import com.felhr.usbserial.UsbSerialInterface;
import static java.lang.Integer.parseInt;
public class MainActivity extends AppCompatActivity {
private static final String TAG = "AMR";
private UsbManager usbManager;
private UsbDevice device;
private UsbDeviceConnection connection;
private UsbSerialDevice serialDevice;
private String handshake = "/?!\r\n";
MediaPlayer errSnd; // chyba
MediaPlayer bdSnd; // registry
MediaPlayer lpSnd; // profil
MediaPlayer infoSnd; // info
ProgressBar progressBar;
RadioGroup rg;
RadioButton rb;
TextView registryNam; // textview pro nazev registru
TextView registryVal; // textview pro hodnotu registru a stavova hlaseni
String regName; // nazev registru
String regValue; // hodnota registru
boolean readRegs; // typy odectu
boolean readLastMonth;
boolean readThisMonth;
Calendar calendar = Calendar.getInstance();
DateFormat dateFormat = new SimpleDateFormat("yyMMdd");
int currentMonth;
int currentYear;
Date today;
Date tomorrow;
String tomorrowAsString;
String lastMonthInterval;
String thisMonthInterval;
String lpInterval;
int startMonth;
int startYear;
int endMonth;
int endYear;
private static final Pattern communicationSpeedIndexPattern
= Pattern.compile("^.*(/)(\w{3})(\d{1})(.*)$"); // [0] - komplet, [1] - /, [2] - vyrobce, [3] - baudrate, [4] - model
private static final Pattern CRpat = Pattern.compile("^(\r)$"); // CR
private static final Pattern LFpat = Pattern.compile("^(\n)$"); // LF
private static final Pattern STXpat = Pattern.compile("^(\x02)$"); // STX
private static final Pattern ETXpat = Pattern.compile("^(\x03)$"); // ETX
private static final Pattern DLEpat = Pattern.compile("^(\x10)$"); // DLE
private static final Pattern ETBpat = Pattern.compile("^(\x17)$"); // ETB
private static final Pattern regNameValuePattern
= Pattern.compile("([^\(\)]*)\(([^\(\)]*)\)"); // [0] - komplet, [1] - Registr, [2] - hodnota
boolean CRLF; // konec radku prijimanych dat
boolean isCR;
boolean isLF;
boolean firstLine;
boolean isETX;
String data; // prichozi data na USB
String dataLine; // radek s prichozimi daty
String tmpDataLine; // radek prichozich dat, ktery je zpracovavan po znacich
//String tmpDataLine2; // radek prichozich dat, ktery je zpracovavan po znacich
String buffer; // buffer pro vystup do souboru
//String tmpBuffer = "";
int dataLength;
private int[] baudrateList = {300, 600, 1200, 2400, 4800, 9600, 19200};
String meterId;
Pattern meterIdPattern = Pattern.compile("0\.0\.0|0\.0|0|C\.1|C\.1\.0|0\.0\.1|0\.0\.2|0\.0\.3|C\.1\.1|C\.90\.1");
int speed; // komunikacni rychlost seriove link - pocatek 300 Bd
int readedSpeed; // maximalni komunikacni rychlost v zarizeni
String askData; // retezec pro odeslani pozadavku dat
char valueSOHchar = 0x01; // SOH
String SOH = String.valueOf(valueSOHchar);
char valueSTXchar = 0x02; // STX
String STX = String.valueOf(valueSTXchar);
char valueETXchar = 0x03; // ETX
String ETX = String.valueOf(valueETXchar);
char valueACKchar = 0x06; // ACK
String ACK = String.valueOf(valueACKchar);
char valueDLEchar = 0x10; // DLE
String DLE = String.valueOf(valueDLEchar);
char valueNAKchar = 0x15; // NAK
String NAK = String.valueOf(valueNAKchar);
char valueETBchar = 0x17; // ETB
String ETB = String.valueOf(valueETBchar);
int etxIndex; // pocet prichozich ETX
boolean registryReceived;
String filename;
String filepath;
File myExternalFile;
boolean successCreateDir;
boolean outputDirOk;
boolean meterEchoes;
//String debugStringValue = "";
long startTime;
long currentTime;
long timeLeft;
MyTimer responseTimeCounter;
@Override
protected void onCreate(Bundle savedInstanceState) {
Log.d(TAG, "-------------- APP START --------------");
setDates(); // nastavime intervaly odectu
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
progressBar = findViewById(R.id.progressBar);
errSnd = MediaPlayer.create(this, R.raw.wrong);
bdSnd = MediaPlayer.create(this, R.raw.case_closed);
lpSnd = MediaPlayer.create(this, R.raw.beep_beep_beep);
infoSnd = MediaPlayer.create(this, R.raw.smack_that_bitch);
rg = findViewById(R.id.readoutType);
registryNam = findViewById(R.id.registryNames);
registryVal = findViewById(R.id.registryValues);
usbManager = (UsbManager) getSystemService(Context.USB_SERVICE);
// casovac pro prodlevu na vstupu
responseTimeCounter = new MyTimer(5000,1);
}
public void setDefaultValues() {
// nastaveni vychozich polozek pro odecet
regName = "";
regValue = "";
readRegs = false;
readLastMonth = false;
readThisMonth = false;
CRLF = false; // konec radku prijimanych dat
isCR = false;
isLF = false;
firstLine = true; // nacitani prvniho radku dat
isETX = false;
data = null; // prichozi data na USB
dataLine = ""; // radek s prichozimi daty
tmpDataLine = ""; // radek prichozich dat, ktery je zpracovavan po znacich
buffer = ""; // buffer pro vystup do souboru
dataLength = 0;
meterId = "";
speed = 300; // komunikacni rychlost - pocatek 300 Bd
readedSpeed = 0; // index komunikacni rychlosti nacteny ze zarizeni
askData = ""; // retezec pro odeslani pozadavku dat
tvSetContent(registryNam, "");
tvSetContent(registryVal, "");
meterEchoes = false;
registryReceived = false;
etxIndex = 0;
}
public String toHex(String arg) {
return String.format("%012x", new BigInteger(1, arg.getBytes()));
}
public void setDates() {
// vypocet dat pro interval odectu
String leadingStartMonthZero = "";
String leadingEndMonthZero = "";
String startDate;
String endDate;
currentMonth = calendar.get(Calendar.MONTH) + 1;
currentYear = calendar.get(Calendar.YEAR) % 100;
// dnes / today
today = calendar.getTime();
// zitra / tomorrow
calendar.add(Calendar.DAY_OF_YEAR, 1);
tomorrow = calendar.getTime();
dateFormat = new SimpleDateFormat("yyMMdd");
tomorrowAsString = dateFormat.format(tomorrow);
// interval pro odecet pri vymene - od 1. tohoto mesice do zitra / this month
if (currentMonth < 10) {
leadingStartMonthZero = "0";
}
startDate = "0" + currentYear + leadingStartMonthZero + currentMonth + "010000";
endDate = "0" + tomorrowAsString + "0000";
thisMonthInterval = startDate + ";" + endDate;
// interval pro std odecet - od 1. minuleho mesice do 1. tohoto mesice / last month
startYear = currentYear;
endYear = currentYear;
startMonth = currentMonth - 1;
endMonth = currentMonth;
if (currentMonth == 1) {
startYear = currentYear - 1;
startMonth = 12;
endYear = currentYear;
endMonth = currentMonth;
}
if (endMonth < 10) {
leadingEndMonthZero = "0";
}
if (startMonth < 10) {
leadingStartMonthZero = "0";
}
startDate = "0" + startYear + leadingStartMonthZero + startMonth + "010000";
endDate = "0" + endYear + leadingEndMonthZero + endMonth + "010000";
lastMonthInterval = startDate + ";" + endDate;
}
private boolean checkUSBdevice() {
boolean pass = false;
Map<String, UsbDevice> deviceList = usbManager.getDeviceList();
if (deviceList.isEmpty()) {
pass = false;
} else {
for (Map.Entry<String, UsbDevice> entry : deviceList.entrySet()) {
device = entry.getValue();
if (usbManager.hasPermission(device)) {
Log.d(TAG, "USB has permission");
pass = true;
} else {
Toast.makeText(getApplicationContext(), "Není oprávnění pro přístup k USB zařízení", Toast.LENGTH_LONG).show();
errSnd.start(); // chck OK
Log.d(TAG, "USB have not permission");
pass = false;
}
}
}
if (pass) {
return true;
} else {
return false;
}
}
public boolean isExternalStorageWritable() {
String state = Environment.getExternalStorageState();
if (Environment.MEDIA_MOUNTED.equals(state)) {
return true;
} else {
return false;
}
}
public void getReadoutType() {
String selectedtext = (String) rb.getText();
int radioButtonID = rg.getCheckedRadioButtonId();
View radioButton = rg.findViewById(radioButtonID);
int rbIndex = rg.indexOfChild(radioButton);
switch (rbIndex) {
case 0: // odecet jen registru
readRegs = true;
readLastMonth = false;
readThisMonth = false;
break;
case 1: // odecet registru a LP za minuly mesic
readRegs = true;
readLastMonth = true;
readThisMonth = false;
break;
case 2: // odecet registru a LP za tent mesic
readRegs = true;
readLastMonth = false;
readThisMonth = true;
break;
}
Log.d(TAG, "Index radiobuttonu: " + rbIndex + " - " + selectedtext);
Log.d(TAG, "readRegs = " + readRegs);
Log.d(TAG, "readLastMonth = " + readLastMonth);
Log.d(TAG, "readThisMonth = " + readThisMonth);
}
private void tvSetContent(TextView tv, CharSequence text) {
final TextView ftv = tv;
final CharSequence ftext = text;
runOnUiThread(new Runnable() {
@Override public void run() {
ftv.setText(ftext);
}
});
}
public void getSpeed() throws InterruptedException {
// nacteni rychlostniho indexu z identifikacniho retezce / get device max speed
Matcher speedIndex = communicationSpeedIndexPattern.matcher(tmpDataLine);
Log.d(TAG, "getSpeed processing");
if (speedIndex.find()) {
readedSpeed = parseInt(speedIndex.group(3));
Log.d(TAG, "Speed index " + readedSpeed);
speed = baudrateList[readedSpeed];
Log.d(TAG, "New speed will be " + speed + " Bd");
tvSetContent(registryVal, "Komunikace na " + speed + " Bd");
if (readThisMonth || readLastMonth) {
askData = ACK + "0" + readedSpeed + "1\r\n";
Log.d(TAG, "Profile ACK");
} else {
askData = ACK + "0" + readedSpeed + "0\r\n";
Log.d(TAG, "Registry ACK");
}
Log.d(TAG, "Waiting 300 ms");
Thread.sleep(300);
Log.d(TAG, "Send to serial " + askData + "|" + toHex(askData));
serialDevice.write(askData.getBytes());
Log.d(TAG, "Waiting 300 ms");
Thread.sleep(300);
Log.d(TAG, "Serial line switching to " + speed + " Bd");
serialDevice.setBaudRate(speed);
Log.d(TAG, "Speed switched");
} else {
Log.d(TAG, "No speed index found");
}
}
public void showValues() {
// rozlozeni na nazev a hodnotu registru / show registry name and value
Matcher regNamVal = regNameValuePattern.matcher(tmpDataLine);
if (regNamVal.find()) {
regName = regNamVal.group(1).toString();
regValue = regNamVal.group(2).toString();
tvSetContent(registryNam, regName);
tvSetContent(registryVal, regValue);
if (meterId == "") {
// hledame cislo elektromeru / looking for meter ID
Matcher metId = meterIdPattern.matcher(regName);
if (metId.matches()) {
meterId = regValue;
Log.d(TAG, "meterId = " + meterId);
}
}
} else {
tvSetContent(registryVal, tmpDataLine);
Log.d(TAG, "Pickup registry and value fail");
tvSetContent(registryNam, "");
tvSetContent(registryVal, "");
}
}
public void chkDirectories() {
// kontrola/vytvoreni adresaru pro vystup a konfiguraci / chck output dir
outputDirOk = false;
File dirDocuments = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOCUMENTS);
String dirDocumentsPath = dirDocuments.getPath();
File dirAmr = new File(dirDocumentsPath+"/AMR");
filepath = dirAmr.getAbsolutePath();
if (!dirAmr.exists()) {
// adresar pro vystup neexistuje, vytvorime ho
successCreateDir = dirAmr.mkdir();
if (successCreateDir) {
Log.d(TAG,"Directory " + filepath + " created successfully");
} else {
Log.d(TAG,"Creating od directory " + filepath + " FAILED!");
}
} else {
Log.d(TAG,"AMR directory OK");
File dirReadouts = new File(filepath + "/Readouts");
filepath = dirReadouts.getAbsolutePath();
if (!dirReadouts.exists()) {
successCreateDir = dirReadouts.mkdir();
if (successCreateDir) {
outputDirOk = true;
Log.d(TAG,"Directory " + filepath + " created successfully");
} else {
Log.d(TAG,"Creating od directory " + filepath + " FAILED!");
}
} else {
outputDirOk = true;
Log.d(TAG,"Readouts directory OK");
}
}
Log.d(TAG,"Readouts output directory: " + filepath);
}
public void saveFile() {
// ukladame na SD kartu / saving to SD
try {
tvSetContent(registryVal, "Ukládám data" + filename);
Log.d(TAG, "Timer pred ukladanim: " + timeLeft);
responseTimeCounter.cancel(); // zastavime casovac odezvy elektromeru / cancel timer
/* THIS CANCEL DID NOT WORKING - WHY???????????????????????? */
Log.d(TAG, "Timer po jeho preruseni: " + timeLeft);
filename = meterId.trim() + ".rd";
myExternalFile = new File(filepath, filename);
Log.d(TAG,"Output stream start " + myExternalFile.getAbsolutePath());
FileOutputStream fos = new FileOutputStream(myExternalFile);
Log.d(TAG, "Start writting data");
fos.write(buffer.getBytes());
Log.d(TAG, "Closing file - saved to " + myExternalFile.getAbsolutePath());
fos.close();
tvSetContent(registryVal, "Uloženo do " + filename);
Log.d(TAG, "Closing serial communication");
connection.close();
bdSnd.start();
} catch (IOException e) {
e.printStackTrace();
}
// ukladame do interniho uloziste / saving in to internal storage
/*
try {
filename = meterId.trim() + ".rd";
BufferedWriter bufferedWriter = new BufferedWriter(new FileWriter(new
File(getFilesDir()+File.separator+filename)));
bufferedWriter.write(buffer);
bufferedWriter.close();
tvSetContent(registryVal, "Uloženo do " + filename);
//setDefaultValues();
bdSnd.start();
} catch (IOException e) {
e.printStackTrace();
}
*/
}
public void processData() throws InterruptedException {
// prochazeni prichozich dat po znacich
for (dataLength = 0; dataLength < data.length(); dataLength++) {
//Process char
char c = data.charAt(dataLength);
String charToString = c + "";
Log.d(TAG, "R <- " + charToString + " hex:" + toHex(charToString));
Matcher incomingOneChar = STXpat.matcher(charToString);
if (incomingOneChar.matches()) {
Log.d(TAG, "\n\nSTX found - dropping it\n\n");
charToString = ""; // drop STX char
}
Matcher nextIncomingOneChar = ETXpat.matcher(charToString);
if (nextIncomingOneChar.matches()) {
Log.d(TAG, "\n\nETX found - dropping it and next data\n\n");
charToString = ""; // drop ETX char a vsechno za tim
isETX = true;
etxIndex += 1;
dataLength = data.length(); // ukonci cyklus driv
registryReceived = true;
responseTimeCounter.cancel();
saveFile();
}
// je prichozi znak CR?
Matcher incomingCharCR = CRpat.matcher(charToString);
if (incomingCharCR.matches()) {
//tvAppend(textView, "CR");
isCR = true;
//Log.d(TAG, "CR");
} else {
// je prichozi znak LF?
Matcher incomingCharLF = LFpat.matcher(charToString);
if (incomingCharLF.matches()) {
//tvAppend(textView, "LF");
isLF = true;
//Log.d(TAG, "LF");
}
}
tmpDataLine += charToString; // pridame nacteny znak do radku
// reset casovace na vstupu
responseTimeCounter.cancel();
responseTimeCounter.start();
/* THIS TIMER RESET WORKING */
if (isCR && isLF) {
// je konec radku?
CRLF = true;
}
if (CRLF) {
// mame cely radek, zpracujeme jej / processing completed data row
//Log.d(TAG, "CRLF");
if (firstLine) {
// v prvnim radku je identifikace s indexem rychlosti
Log.d(TAG, "First line completed - " + tmpDataLine);
if (tmpDataLine.equals(handshake)) {
// test na echo
meterEchoes = true;
tmpDataLine = ""; // drop radku s echem
Log.d(TAG, "Meter send echo");
} else {
getSpeed();
firstLine = false;
Log.d(TAG, "First line operated");
}
}
if (meterEchoes && tmpDataLine.equals(askData)) {
// pokud elektromer vraci echo, drop data
tmpDataLine = "";
}
buffer += tmpDataLine;
Log.d(TAG, "tmpDataLine: " + tmpDataLine);
if (!tmpDataLine.equals("")) {
// pokud nejaka data jsou, zobraz je
showValues();
}
dataLine = ""; // vymazeme obsah radku
CRLF = false;
isCR = false;
isLF = false;
tmpDataLine = "";
}
}
}
UsbSerialInterface.UsbReadCallback mCallback = new UsbSerialInterface.UsbReadCallback() {
//Defining a Callback which triggers whenever data is read.
//@TargetApi(Build.VERSION_CODES.KITKAT)
//@RequiresApi(api = Build.VERSION_CODES.KITKAT)
@Override
public void onReceivedData(byte[] arg0) {
//String data = null;
try {
data = new String(arg0);
//Log.d(TAG, "R <- " + data);
Log.d(TAG, "Timer pri vstupu dat na USB: " + timeLeft);
processData();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
};
private void startSerialConnection(UsbDevice device) {
Log.i(TAG, "Ready to open USB device connection");
connection = usbManager.openDevice(device);
serialDevice = UsbSerialDevice.createUsbSerialDevice(device, connection);
if (serialDevice != null) {
if (serialDevice.open()) {
serialDevice.setBaudRate(speed);
serialDevice.setDataBits(UsbSerialInterface.DATA_BITS_7);
serialDevice.setStopBits(UsbSerialInterface.STOP_BITS_1);
serialDevice.setParity(UsbSerialInterface.PARITY_EVEN);
serialDevice.setFlowControl(UsbSerialInterface.FLOW_CONTROL_OFF);
Log.d(TAG, "mCallback Called");
serialDevice.read(mCallback);
Log.d(TAG, "Serial connection opened at " + speed + " Bd");
} else {
Log.d(TAG, "Cannot open serial connection");
tvSetContent(registryVal, "Nefunguje COM port");
Toast.makeText(getApplicationContext(), "Nefunguje COM port", Toast.LENGTH_LONG).show();
infoSnd.start();
}
} else {
Log.d(TAG, "Could not create USB Serial Device");
}
}
public class MyTimer extends CountDownTimer {
public MyTimer(long millisInFuture, long countDownInterval) {
super(millisInFuture, countDownInterval);
}
@Override
public void onTick(long millisUntilFinished) {
tvSetContent(registryNam, String.valueOf(millisUntilFinished));
}
@Override
public void onFinish() {
errSnd.start();
tvSetContent(registryVal, "Elektroměr neodpovídá"); // device did not respond
connection.close();
}
}
public void doReadout(View view) {
setDefaultValues();
chkDirectories();
int radioButtonId = rg.getCheckedRadioButtonId();
rb = findViewById(radioButtonId);
Log.d(TAG, "Do Readout pressed");
if (!isExternalStorageWritable()) {
Toast.makeText(getApplicationContext(), "Externí úložiště není k dispozici.", Toast.LENGTH_LONG).show();
errSnd.start();
}
// pro zapis na SD kartu
if (!outputDirOk) {
Toast.makeText(getApplicationContext(), "Adresář pro výstup není k dispozici.", Toast.LENGTH_LONG).show();
errSnd.start();
}
if (checkUSBdevice() && isExternalStorageWritable() && outputDirOk) {
startSerialConnection(device);
if (device != null) {
//tvSetContent(registryVal, "Sériová komunikace spuštěna");
Log.d(TAG, "Serial communication opened");
} else {
Log.d(TAG, "Serial communication opening FAIL");
}
if (rb == null) {
Toast.makeText(getApplicationContext(), "Není vybrán typ odečtu!", Toast.LENGTH_LONG).show();
Log.d(TAG, "No readout type selected");
errSnd.start();
} else {
getReadoutType();
tvSetContent(registryVal, "Posílam handshake");
serialDevice.write(handshake.getBytes());
Log.d(TAG, "Handshake sent " + toHex(handshake));
responseTimeCounter.start();
Log.d(TAG, "Response timer started");
}
} else {
// nepripojene USB nedelame nic
errSnd.start();
Toast.makeText(getApplicationContext(), "Není připojena USB optická sonda." ,Toast.LENGTH_LONG).show();
Log.d(TAG, "No USB device connected");
}
}
}
这取决于您是否希望调用 onFinish() 覆盖 - 通常它不会在 cancel() 上调用(但可能会在 start() 上调用)所以如果您想要关闭连接,请调用 onFinish( ) 取消后()
我找到原因了,为什么一个计时器不想被取消。在错误的地方调用了 .cancel() 和 .start()。它们在循环中被调用,其中输入是一个字符一个字符地处理,并且在短时间内取消和启动的次数太多,这可能会使计时器感到困惑。将计时器重新启动移出此循环解决了我的问题。
我正在尝试为 Android 进行串行 IEC 通信,我需要检查设备是否发送了一些数据。我在通信开始时启动了一个计时器,并在收到一些数据时将其重置。重置传入数据有效,但在保存数据之前取消无效。我不明白为什么。
这是我的 MainActivity.java 代码
package cz.trisko.jan.amr;
import android.content.Context;
import android.media.MediaPlayer;
import android.os.Bundle;
import android.os.CountDownTimer;
import android.os.Environment;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;
import android.view.View;
import android.widget.ProgressBar;
import android.widget.RadioButton;
import android.widget.RadioGroup;
import android.widget.TextView;
import android.widget.Toast;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.math.BigInteger;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.Map;
import java.util.regex.Pattern;
import java.util.regex.Matcher;
import android.hardware.usb.UsbDevice;
import android.hardware.usb.UsbManager;
import android.hardware.usb.UsbDeviceConnection;
import com.felhr.usbserial.UsbSerialDevice;
import com.felhr.usbserial.UsbSerialInterface;
import static java.lang.Integer.parseInt;
public class MainActivity extends AppCompatActivity {
private static final String TAG = "AMR";
private UsbManager usbManager;
private UsbDevice device;
private UsbDeviceConnection connection;
private UsbSerialDevice serialDevice;
private String handshake = "/?!\r\n";
MediaPlayer errSnd; // chyba
MediaPlayer bdSnd; // registry
MediaPlayer lpSnd; // profil
MediaPlayer infoSnd; // info
ProgressBar progressBar;
RadioGroup rg;
RadioButton rb;
TextView registryNam; // textview pro nazev registru
TextView registryVal; // textview pro hodnotu registru a stavova hlaseni
String regName; // nazev registru
String regValue; // hodnota registru
boolean readRegs; // typy odectu
boolean readLastMonth;
boolean readThisMonth;
Calendar calendar = Calendar.getInstance();
DateFormat dateFormat = new SimpleDateFormat("yyMMdd");
int currentMonth;
int currentYear;
Date today;
Date tomorrow;
String tomorrowAsString;
String lastMonthInterval;
String thisMonthInterval;
String lpInterval;
int startMonth;
int startYear;
int endMonth;
int endYear;
private static final Pattern communicationSpeedIndexPattern
= Pattern.compile("^.*(/)(\w{3})(\d{1})(.*)$"); // [0] - komplet, [1] - /, [2] - vyrobce, [3] - baudrate, [4] - model
private static final Pattern CRpat = Pattern.compile("^(\r)$"); // CR
private static final Pattern LFpat = Pattern.compile("^(\n)$"); // LF
private static final Pattern STXpat = Pattern.compile("^(\x02)$"); // STX
private static final Pattern ETXpat = Pattern.compile("^(\x03)$"); // ETX
private static final Pattern DLEpat = Pattern.compile("^(\x10)$"); // DLE
private static final Pattern ETBpat = Pattern.compile("^(\x17)$"); // ETB
private static final Pattern regNameValuePattern
= Pattern.compile("([^\(\)]*)\(([^\(\)]*)\)"); // [0] - komplet, [1] - Registr, [2] - hodnota
boolean CRLF; // konec radku prijimanych dat
boolean isCR;
boolean isLF;
boolean firstLine;
boolean isETX;
String data; // prichozi data na USB
String dataLine; // radek s prichozimi daty
String tmpDataLine; // radek prichozich dat, ktery je zpracovavan po znacich
//String tmpDataLine2; // radek prichozich dat, ktery je zpracovavan po znacich
String buffer; // buffer pro vystup do souboru
//String tmpBuffer = "";
int dataLength;
private int[] baudrateList = {300, 600, 1200, 2400, 4800, 9600, 19200};
String meterId;
Pattern meterIdPattern = Pattern.compile("0\.0\.0|0\.0|0|C\.1|C\.1\.0|0\.0\.1|0\.0\.2|0\.0\.3|C\.1\.1|C\.90\.1");
int speed; // komunikacni rychlost seriove link - pocatek 300 Bd
int readedSpeed; // maximalni komunikacni rychlost v zarizeni
String askData; // retezec pro odeslani pozadavku dat
char valueSOHchar = 0x01; // SOH
String SOH = String.valueOf(valueSOHchar);
char valueSTXchar = 0x02; // STX
String STX = String.valueOf(valueSTXchar);
char valueETXchar = 0x03; // ETX
String ETX = String.valueOf(valueETXchar);
char valueACKchar = 0x06; // ACK
String ACK = String.valueOf(valueACKchar);
char valueDLEchar = 0x10; // DLE
String DLE = String.valueOf(valueDLEchar);
char valueNAKchar = 0x15; // NAK
String NAK = String.valueOf(valueNAKchar);
char valueETBchar = 0x17; // ETB
String ETB = String.valueOf(valueETBchar);
int etxIndex; // pocet prichozich ETX
boolean registryReceived;
String filename;
String filepath;
File myExternalFile;
boolean successCreateDir;
boolean outputDirOk;
boolean meterEchoes;
//String debugStringValue = "";
long startTime;
long currentTime;
long timeLeft;
MyTimer responseTimeCounter;
@Override
protected void onCreate(Bundle savedInstanceState) {
Log.d(TAG, "-------------- APP START --------------");
setDates(); // nastavime intervaly odectu
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
progressBar = findViewById(R.id.progressBar);
errSnd = MediaPlayer.create(this, R.raw.wrong);
bdSnd = MediaPlayer.create(this, R.raw.case_closed);
lpSnd = MediaPlayer.create(this, R.raw.beep_beep_beep);
infoSnd = MediaPlayer.create(this, R.raw.smack_that_bitch);
rg = findViewById(R.id.readoutType);
registryNam = findViewById(R.id.registryNames);
registryVal = findViewById(R.id.registryValues);
usbManager = (UsbManager) getSystemService(Context.USB_SERVICE);
// casovac pro prodlevu na vstupu
responseTimeCounter = new MyTimer(5000,1);
}
public void setDefaultValues() {
// nastaveni vychozich polozek pro odecet
regName = "";
regValue = "";
readRegs = false;
readLastMonth = false;
readThisMonth = false;
CRLF = false; // konec radku prijimanych dat
isCR = false;
isLF = false;
firstLine = true; // nacitani prvniho radku dat
isETX = false;
data = null; // prichozi data na USB
dataLine = ""; // radek s prichozimi daty
tmpDataLine = ""; // radek prichozich dat, ktery je zpracovavan po znacich
buffer = ""; // buffer pro vystup do souboru
dataLength = 0;
meterId = "";
speed = 300; // komunikacni rychlost - pocatek 300 Bd
readedSpeed = 0; // index komunikacni rychlosti nacteny ze zarizeni
askData = ""; // retezec pro odeslani pozadavku dat
tvSetContent(registryNam, "");
tvSetContent(registryVal, "");
meterEchoes = false;
registryReceived = false;
etxIndex = 0;
}
public String toHex(String arg) {
return String.format("%012x", new BigInteger(1, arg.getBytes()));
}
public void setDates() {
// vypocet dat pro interval odectu
String leadingStartMonthZero = "";
String leadingEndMonthZero = "";
String startDate;
String endDate;
currentMonth = calendar.get(Calendar.MONTH) + 1;
currentYear = calendar.get(Calendar.YEAR) % 100;
// dnes / today
today = calendar.getTime();
// zitra / tomorrow
calendar.add(Calendar.DAY_OF_YEAR, 1);
tomorrow = calendar.getTime();
dateFormat = new SimpleDateFormat("yyMMdd");
tomorrowAsString = dateFormat.format(tomorrow);
// interval pro odecet pri vymene - od 1. tohoto mesice do zitra / this month
if (currentMonth < 10) {
leadingStartMonthZero = "0";
}
startDate = "0" + currentYear + leadingStartMonthZero + currentMonth + "010000";
endDate = "0" + tomorrowAsString + "0000";
thisMonthInterval = startDate + ";" + endDate;
// interval pro std odecet - od 1. minuleho mesice do 1. tohoto mesice / last month
startYear = currentYear;
endYear = currentYear;
startMonth = currentMonth - 1;
endMonth = currentMonth;
if (currentMonth == 1) {
startYear = currentYear - 1;
startMonth = 12;
endYear = currentYear;
endMonth = currentMonth;
}
if (endMonth < 10) {
leadingEndMonthZero = "0";
}
if (startMonth < 10) {
leadingStartMonthZero = "0";
}
startDate = "0" + startYear + leadingStartMonthZero + startMonth + "010000";
endDate = "0" + endYear + leadingEndMonthZero + endMonth + "010000";
lastMonthInterval = startDate + ";" + endDate;
}
private boolean checkUSBdevice() {
boolean pass = false;
Map<String, UsbDevice> deviceList = usbManager.getDeviceList();
if (deviceList.isEmpty()) {
pass = false;
} else {
for (Map.Entry<String, UsbDevice> entry : deviceList.entrySet()) {
device = entry.getValue();
if (usbManager.hasPermission(device)) {
Log.d(TAG, "USB has permission");
pass = true;
} else {
Toast.makeText(getApplicationContext(), "Není oprávnění pro přístup k USB zařízení", Toast.LENGTH_LONG).show();
errSnd.start(); // chck OK
Log.d(TAG, "USB have not permission");
pass = false;
}
}
}
if (pass) {
return true;
} else {
return false;
}
}
public boolean isExternalStorageWritable() {
String state = Environment.getExternalStorageState();
if (Environment.MEDIA_MOUNTED.equals(state)) {
return true;
} else {
return false;
}
}
public void getReadoutType() {
String selectedtext = (String) rb.getText();
int radioButtonID = rg.getCheckedRadioButtonId();
View radioButton = rg.findViewById(radioButtonID);
int rbIndex = rg.indexOfChild(radioButton);
switch (rbIndex) {
case 0: // odecet jen registru
readRegs = true;
readLastMonth = false;
readThisMonth = false;
break;
case 1: // odecet registru a LP za minuly mesic
readRegs = true;
readLastMonth = true;
readThisMonth = false;
break;
case 2: // odecet registru a LP za tent mesic
readRegs = true;
readLastMonth = false;
readThisMonth = true;
break;
}
Log.d(TAG, "Index radiobuttonu: " + rbIndex + " - " + selectedtext);
Log.d(TAG, "readRegs = " + readRegs);
Log.d(TAG, "readLastMonth = " + readLastMonth);
Log.d(TAG, "readThisMonth = " + readThisMonth);
}
private void tvSetContent(TextView tv, CharSequence text) {
final TextView ftv = tv;
final CharSequence ftext = text;
runOnUiThread(new Runnable() {
@Override public void run() {
ftv.setText(ftext);
}
});
}
public void getSpeed() throws InterruptedException {
// nacteni rychlostniho indexu z identifikacniho retezce / get device max speed
Matcher speedIndex = communicationSpeedIndexPattern.matcher(tmpDataLine);
Log.d(TAG, "getSpeed processing");
if (speedIndex.find()) {
readedSpeed = parseInt(speedIndex.group(3));
Log.d(TAG, "Speed index " + readedSpeed);
speed = baudrateList[readedSpeed];
Log.d(TAG, "New speed will be " + speed + " Bd");
tvSetContent(registryVal, "Komunikace na " + speed + " Bd");
if (readThisMonth || readLastMonth) {
askData = ACK + "0" + readedSpeed + "1\r\n";
Log.d(TAG, "Profile ACK");
} else {
askData = ACK + "0" + readedSpeed + "0\r\n";
Log.d(TAG, "Registry ACK");
}
Log.d(TAG, "Waiting 300 ms");
Thread.sleep(300);
Log.d(TAG, "Send to serial " + askData + "|" + toHex(askData));
serialDevice.write(askData.getBytes());
Log.d(TAG, "Waiting 300 ms");
Thread.sleep(300);
Log.d(TAG, "Serial line switching to " + speed + " Bd");
serialDevice.setBaudRate(speed);
Log.d(TAG, "Speed switched");
} else {
Log.d(TAG, "No speed index found");
}
}
public void showValues() {
// rozlozeni na nazev a hodnotu registru / show registry name and value
Matcher regNamVal = regNameValuePattern.matcher(tmpDataLine);
if (regNamVal.find()) {
regName = regNamVal.group(1).toString();
regValue = regNamVal.group(2).toString();
tvSetContent(registryNam, regName);
tvSetContent(registryVal, regValue);
if (meterId == "") {
// hledame cislo elektromeru / looking for meter ID
Matcher metId = meterIdPattern.matcher(regName);
if (metId.matches()) {
meterId = regValue;
Log.d(TAG, "meterId = " + meterId);
}
}
} else {
tvSetContent(registryVal, tmpDataLine);
Log.d(TAG, "Pickup registry and value fail");
tvSetContent(registryNam, "");
tvSetContent(registryVal, "");
}
}
public void chkDirectories() {
// kontrola/vytvoreni adresaru pro vystup a konfiguraci / chck output dir
outputDirOk = false;
File dirDocuments = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOCUMENTS);
String dirDocumentsPath = dirDocuments.getPath();
File dirAmr = new File(dirDocumentsPath+"/AMR");
filepath = dirAmr.getAbsolutePath();
if (!dirAmr.exists()) {
// adresar pro vystup neexistuje, vytvorime ho
successCreateDir = dirAmr.mkdir();
if (successCreateDir) {
Log.d(TAG,"Directory " + filepath + " created successfully");
} else {
Log.d(TAG,"Creating od directory " + filepath + " FAILED!");
}
} else {
Log.d(TAG,"AMR directory OK");
File dirReadouts = new File(filepath + "/Readouts");
filepath = dirReadouts.getAbsolutePath();
if (!dirReadouts.exists()) {
successCreateDir = dirReadouts.mkdir();
if (successCreateDir) {
outputDirOk = true;
Log.d(TAG,"Directory " + filepath + " created successfully");
} else {
Log.d(TAG,"Creating od directory " + filepath + " FAILED!");
}
} else {
outputDirOk = true;
Log.d(TAG,"Readouts directory OK");
}
}
Log.d(TAG,"Readouts output directory: " + filepath);
}
public void saveFile() {
// ukladame na SD kartu / saving to SD
try {
tvSetContent(registryVal, "Ukládám data" + filename);
Log.d(TAG, "Timer pred ukladanim: " + timeLeft);
responseTimeCounter.cancel(); // zastavime casovac odezvy elektromeru / cancel timer
/* THIS CANCEL DID NOT WORKING - WHY???????????????????????? */
Log.d(TAG, "Timer po jeho preruseni: " + timeLeft);
filename = meterId.trim() + ".rd";
myExternalFile = new File(filepath, filename);
Log.d(TAG,"Output stream start " + myExternalFile.getAbsolutePath());
FileOutputStream fos = new FileOutputStream(myExternalFile);
Log.d(TAG, "Start writting data");
fos.write(buffer.getBytes());
Log.d(TAG, "Closing file - saved to " + myExternalFile.getAbsolutePath());
fos.close();
tvSetContent(registryVal, "Uloženo do " + filename);
Log.d(TAG, "Closing serial communication");
connection.close();
bdSnd.start();
} catch (IOException e) {
e.printStackTrace();
}
// ukladame do interniho uloziste / saving in to internal storage
/*
try {
filename = meterId.trim() + ".rd";
BufferedWriter bufferedWriter = new BufferedWriter(new FileWriter(new
File(getFilesDir()+File.separator+filename)));
bufferedWriter.write(buffer);
bufferedWriter.close();
tvSetContent(registryVal, "Uloženo do " + filename);
//setDefaultValues();
bdSnd.start();
} catch (IOException e) {
e.printStackTrace();
}
*/
}
public void processData() throws InterruptedException {
// prochazeni prichozich dat po znacich
for (dataLength = 0; dataLength < data.length(); dataLength++) {
//Process char
char c = data.charAt(dataLength);
String charToString = c + "";
Log.d(TAG, "R <- " + charToString + " hex:" + toHex(charToString));
Matcher incomingOneChar = STXpat.matcher(charToString);
if (incomingOneChar.matches()) {
Log.d(TAG, "\n\nSTX found - dropping it\n\n");
charToString = ""; // drop STX char
}
Matcher nextIncomingOneChar = ETXpat.matcher(charToString);
if (nextIncomingOneChar.matches()) {
Log.d(TAG, "\n\nETX found - dropping it and next data\n\n");
charToString = ""; // drop ETX char a vsechno za tim
isETX = true;
etxIndex += 1;
dataLength = data.length(); // ukonci cyklus driv
registryReceived = true;
responseTimeCounter.cancel();
saveFile();
}
// je prichozi znak CR?
Matcher incomingCharCR = CRpat.matcher(charToString);
if (incomingCharCR.matches()) {
//tvAppend(textView, "CR");
isCR = true;
//Log.d(TAG, "CR");
} else {
// je prichozi znak LF?
Matcher incomingCharLF = LFpat.matcher(charToString);
if (incomingCharLF.matches()) {
//tvAppend(textView, "LF");
isLF = true;
//Log.d(TAG, "LF");
}
}
tmpDataLine += charToString; // pridame nacteny znak do radku
// reset casovace na vstupu
responseTimeCounter.cancel();
responseTimeCounter.start();
/* THIS TIMER RESET WORKING */
if (isCR && isLF) {
// je konec radku?
CRLF = true;
}
if (CRLF) {
// mame cely radek, zpracujeme jej / processing completed data row
//Log.d(TAG, "CRLF");
if (firstLine) {
// v prvnim radku je identifikace s indexem rychlosti
Log.d(TAG, "First line completed - " + tmpDataLine);
if (tmpDataLine.equals(handshake)) {
// test na echo
meterEchoes = true;
tmpDataLine = ""; // drop radku s echem
Log.d(TAG, "Meter send echo");
} else {
getSpeed();
firstLine = false;
Log.d(TAG, "First line operated");
}
}
if (meterEchoes && tmpDataLine.equals(askData)) {
// pokud elektromer vraci echo, drop data
tmpDataLine = "";
}
buffer += tmpDataLine;
Log.d(TAG, "tmpDataLine: " + tmpDataLine);
if (!tmpDataLine.equals("")) {
// pokud nejaka data jsou, zobraz je
showValues();
}
dataLine = ""; // vymazeme obsah radku
CRLF = false;
isCR = false;
isLF = false;
tmpDataLine = "";
}
}
}
UsbSerialInterface.UsbReadCallback mCallback = new UsbSerialInterface.UsbReadCallback() {
//Defining a Callback which triggers whenever data is read.
//@TargetApi(Build.VERSION_CODES.KITKAT)
//@RequiresApi(api = Build.VERSION_CODES.KITKAT)
@Override
public void onReceivedData(byte[] arg0) {
//String data = null;
try {
data = new String(arg0);
//Log.d(TAG, "R <- " + data);
Log.d(TAG, "Timer pri vstupu dat na USB: " + timeLeft);
processData();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
};
private void startSerialConnection(UsbDevice device) {
Log.i(TAG, "Ready to open USB device connection");
connection = usbManager.openDevice(device);
serialDevice = UsbSerialDevice.createUsbSerialDevice(device, connection);
if (serialDevice != null) {
if (serialDevice.open()) {
serialDevice.setBaudRate(speed);
serialDevice.setDataBits(UsbSerialInterface.DATA_BITS_7);
serialDevice.setStopBits(UsbSerialInterface.STOP_BITS_1);
serialDevice.setParity(UsbSerialInterface.PARITY_EVEN);
serialDevice.setFlowControl(UsbSerialInterface.FLOW_CONTROL_OFF);
Log.d(TAG, "mCallback Called");
serialDevice.read(mCallback);
Log.d(TAG, "Serial connection opened at " + speed + " Bd");
} else {
Log.d(TAG, "Cannot open serial connection");
tvSetContent(registryVal, "Nefunguje COM port");
Toast.makeText(getApplicationContext(), "Nefunguje COM port", Toast.LENGTH_LONG).show();
infoSnd.start();
}
} else {
Log.d(TAG, "Could not create USB Serial Device");
}
}
public class MyTimer extends CountDownTimer {
public MyTimer(long millisInFuture, long countDownInterval) {
super(millisInFuture, countDownInterval);
}
@Override
public void onTick(long millisUntilFinished) {
tvSetContent(registryNam, String.valueOf(millisUntilFinished));
}
@Override
public void onFinish() {
errSnd.start();
tvSetContent(registryVal, "Elektroměr neodpovídá"); // device did not respond
connection.close();
}
}
public void doReadout(View view) {
setDefaultValues();
chkDirectories();
int radioButtonId = rg.getCheckedRadioButtonId();
rb = findViewById(radioButtonId);
Log.d(TAG, "Do Readout pressed");
if (!isExternalStorageWritable()) {
Toast.makeText(getApplicationContext(), "Externí úložiště není k dispozici.", Toast.LENGTH_LONG).show();
errSnd.start();
}
// pro zapis na SD kartu
if (!outputDirOk) {
Toast.makeText(getApplicationContext(), "Adresář pro výstup není k dispozici.", Toast.LENGTH_LONG).show();
errSnd.start();
}
if (checkUSBdevice() && isExternalStorageWritable() && outputDirOk) {
startSerialConnection(device);
if (device != null) {
//tvSetContent(registryVal, "Sériová komunikace spuštěna");
Log.d(TAG, "Serial communication opened");
} else {
Log.d(TAG, "Serial communication opening FAIL");
}
if (rb == null) {
Toast.makeText(getApplicationContext(), "Není vybrán typ odečtu!", Toast.LENGTH_LONG).show();
Log.d(TAG, "No readout type selected");
errSnd.start();
} else {
getReadoutType();
tvSetContent(registryVal, "Posílam handshake");
serialDevice.write(handshake.getBytes());
Log.d(TAG, "Handshake sent " + toHex(handshake));
responseTimeCounter.start();
Log.d(TAG, "Response timer started");
}
} else {
// nepripojene USB nedelame nic
errSnd.start();
Toast.makeText(getApplicationContext(), "Není připojena USB optická sonda." ,Toast.LENGTH_LONG).show();
Log.d(TAG, "No USB device connected");
}
}
}
这取决于您是否希望调用 onFinish() 覆盖 - 通常它不会在 cancel() 上调用(但可能会在 start() 上调用)所以如果您想要关闭连接,请调用 onFinish( ) 取消后()
我找到原因了,为什么一个计时器不想被取消。在错误的地方调用了 .cancel() 和 .start()。它们在循环中被调用,其中输入是一个字符一个字符地处理,并且在短时间内取消和启动的次数太多,这可能会使计时器感到困惑。将计时器重新启动移出此循环解决了我的问题。