|
package com.example.serial;
|
|
import androidx.activity.EdgeToEdge;
|
import androidx.appcompat.app.AppCompatActivity;
|
|
import android.graphics.Color;
|
import android.graphics.Paint;
|
import android.os.Bundle;
|
import android.text.method.ScrollingMovementMethod;
|
import android.util.Log;
|
import android.view.View;
|
import android.widget.AdapterView;
|
import android.widget.ArrayAdapter;
|
import android.widget.Button;
|
import android.widget.EditText;
|
import android.widget.Spinner;
|
import android.widget.TextView;
|
import android.widget.Toast;
|
|
import com.example.serial.databinding.ActivityMainBinding;
|
|
import java.text.SimpleDateFormat;
|
import java.util.Date;
|
import java.util.TimeZone;
|
|
|
public class RS485Activity extends AppCompatActivity {
|
|
// Used to load the 'serial' library on application startup.
|
static {
|
System.loadLibrary("serial");
|
}
|
|
// 与串口参数相关的组件
|
private ActivityMainBinding binding;
|
private Spinner mSpBaud;
|
private Spinner mSpSerial;
|
private Spinner mSpData;
|
private Spinner mSpStop;
|
private Spinner mSpParity;
|
private Spinner mSpFlow;
|
|
// 和发送信息相关的控件
|
private Button mBtnClearSend;
|
private Button mBtnSend;
|
private EditText mEtSend;
|
// 和接收信息相关的控件
|
private Button mBtnClearRev;
|
private TextView mTvRev;
|
private TextView mTvShow;
|
private Button mBtnRecv;
|
|
// 打开串口&关闭串口
|
private Button mBtnOpen;
|
private Button mBtnClose;
|
private Button mBtnSendState;
|
private Button mBtnRecvState;
|
|
|
// 设置串口的参数
|
private String serial;
|
private long baudRate;
|
private int dataBits;
|
private double stopBits;
|
private int parity;
|
private int flowControl; // 0:None, 1:RTS/CTS, 2:XON/XOFF
|
|
// 获取已经设定的值
|
String[] serialArray;
|
String[] baudArray;
|
String[] dataArray;
|
String[] stopArray;
|
String[] parityArray;
|
String[] flowArray;
|
String sendData;
|
String currenState = null;
|
int sendOnTime;
|
int state = -1;
|
private static final int MSG_SEND_DATA = 1;
|
|
boolean turnFlag = false;
|
private RS485Control RS485Control;
|
Runnable runnable;
|
|
|
@Override
|
protected void onCreate(Bundle savedInstanceState) {
|
super.onCreate(savedInstanceState);
|
EdgeToEdge.enable(this);
|
setContentView(R.layout.activity_rs485);
|
|
RS485Control = new RS485Control();
|
// 找到控件
|
mSpSerial = findViewById(R.id.sp_serial);
|
mSpBaud = findViewById(R.id.sp_baud);
|
mSpData = findViewById(R.id.sp_data);
|
mSpStop = findViewById(R.id.sp_stop);
|
mSpParity = findViewById(R.id.sp_parity);
|
mSpFlow = findViewById(R.id.sp_flow);
|
|
mBtnOpen = findViewById(R.id.btn_open);
|
mBtnClose = findViewById(R.id.btn_close);
|
mBtnClearRev = findViewById(R.id.btn_clear_rev);
|
mBtnClearSend = findViewById(R.id.btn_clear_send);
|
mBtnSend = findViewById(R.id.btn_send);
|
mEtSend = findViewById(R.id.et_send);
|
mTvRev = findViewById(R.id.txt_rev);
|
mTvShow = findViewById(R.id.txt_show);
|
mBtnRecv = findViewById(R.id.btn_recv);
|
mBtnRecvState = findViewById(R.id.btn_recv_state);
|
mBtnSendState = findViewById(R.id.btn_send_state);
|
|
// 还没有连接串口时,显示not connected
|
mTvShow.setTextColor(Color.parseColor("#FF0000"));
|
mTvShow.setText("NOT CONNECTED");
|
mTvShow.setPaintFlags(mTvShow.getPaintFlags() | Paint.ANTI_ALIAS_FLAG);
|
// 设置并监听下拉列表
|
setSpinner(mSpSerial);
|
setSpinner(mSpBaud);
|
setSpinner(mSpData);
|
setSpinner(mSpStop);
|
setSpinner(mSpParity);
|
setSpinner(mSpFlow);
|
|
mTvRev.setMovementMethod(ScrollingMovementMethod.getInstance());
|
|
// 监听所有的button
|
setListener();
|
|
}
|
|
@Override
|
protected void onDestroy() {
|
super.onDestroy();
|
RS485Control.closeSerialPort();
|
}
|
|
private void setSpinner(Spinner spinner){
|
ArrayAdapter<CharSequence> adapter;
|
int id = spinner.getId();
|
|
if (id == R.id.sp_serial){
|
adapter = ArrayAdapter.createFromResource(RS485Activity.this, R.array.serial_name, android.R.layout.simple_spinner_item);
|
}else if (id == R.id.sp_baud) {
|
adapter = ArrayAdapter.createFromResource(RS485Activity.this, R.array.baud_rate, android.R.layout.simple_spinner_item);
|
} else if (id == R.id.sp_data) {
|
adapter = ArrayAdapter.createFromResource(RS485Activity.this, R.array.data_bits, android.R.layout.simple_spinner_item);
|
} else if (id == R.id.sp_stop) {
|
adapter = ArrayAdapter.createFromResource(RS485Activity.this, R.array.stop_bits, android.R.layout.simple_spinner_item);
|
} else if (id == R.id.sp_parity) {
|
adapter = ArrayAdapter.createFromResource(RS485Activity.this, R.array.parity, android.R.layout.simple_spinner_item);
|
} else if (id == R.id.sp_flow) {
|
adapter = ArrayAdapter.createFromResource(RS485Activity.this, R.array.flow_control, android.R.layout.simple_spinner_item);
|
} else {
|
throw new IllegalStateException("Unexpected value: " + spinner.getId());
|
}
|
adapter.setDropDownViewResource(android.R.layout.simple_spinner_item);
|
spinner.setAdapter(adapter);
|
|
spinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
|
@Override
|
public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
|
int spinnerId = spinner.getId();
|
|
if (spinnerId == R.id.sp_serial) {
|
serialArray = getResources().getStringArray(R.array.serial_name);
|
serial = serialArray[position];
|
// Toast.makeText(MainActivity.this, "串口:" + serial, Toast.LENGTH_SHORT).show();
|
} else if (spinnerId == R.id.sp_baud) {
|
baudArray = getResources().getStringArray(R.array.baud_rate);
|
baudRate = Integer.parseInt(baudArray[position]);
|
// Toast.makeText(MainActivity.this, "波特率:" + baudRate, Toast.LENGTH_SHORT).show();
|
} else if (spinnerId == R.id.sp_data) {
|
dataArray = getResources().getStringArray(R.array.data_bits);
|
dataBits = Integer.parseInt(dataArray[position]);
|
// Toast.makeText(MainActivity.this, "数据位:" + dataBits, Toast.LENGTH_SHORT).show();
|
} else if (spinnerId == R.id.sp_stop) {
|
stopArray = getResources().getStringArray(R.array.stop_bits);
|
stopBits = Double.parseDouble(stopArray[position]);
|
// Toast.makeText(MainActivity.this, "停止位:" + stopBits, Toast.LENGTH_SHORT).show();
|
} else if (spinnerId == R.id.sp_parity) {
|
parityArray = getResources().getStringArray(R.array.parity);
|
if (parityArray[position].equals("偶校验"))
|
parity = 2;
|
else if (parityArray[position].equals("奇校验"))
|
parity = 1;
|
else if (parityArray[position].equals("None"))
|
parity = 0;
|
// Toast.makeText(MainActivity.this, "校验位:" + parityArray[position], Toast.LENGTH_SHORT).show();
|
} else if (spinnerId == R.id.sp_flow) {
|
flowArray = getResources().getStringArray(R.array.flow_control);
|
flowControl = position;
|
} else {
|
throw new IllegalStateException("Unexpected value: " + spinner.getId());
|
}
|
}
|
@Override
|
public void onNothingSelected(AdapterView<?> parent) {
|
}
|
});
|
}
|
|
private void setListener(){
|
OnClick onClick = new OnClick();
|
mBtnOpen.setOnClickListener(onClick);
|
mBtnClose.setOnClickListener(onClick);
|
mBtnClearRev.setOnClickListener(onClick);
|
mBtnClearSend.setOnClickListener(onClick);
|
mBtnSend.setOnClickListener(onClick);
|
mBtnRecvState.setOnClickListener(onClick);
|
mBtnSendState.setOnClickListener(onClick);
|
mBtnRecv.setOnClickListener(onClick);
|
}
|
private class OnClick implements View.OnClickListener{
|
|
@Override
|
public void onClick(View v) {
|
int id = v.getId();
|
if (id == R.id.btn_open) {
|
if (turnFlag) {
|
Toast.makeText(RS485Activity.this, "串口已打开, 不能重复打开", Toast.LENGTH_SHORT).show();
|
}else {
|
int rv = RS485Control.openSerialPort(serial, (int) baudRate, dataBits, parity, (int) stopBits, flowControl);
|
if(rv == 1){
|
Toast.makeText(RS485Activity.this, "请添加"+serial+"的权限", Toast.LENGTH_SHORT).show();
|
}else if (rv < 0) {
|
Toast.makeText(RS485Activity.this, "打开串口失败", Toast.LENGTH_SHORT).show();
|
} else {
|
turnFlag = true;
|
// startReceiving(); // 串口打开后默认开始读
|
serialOpened();
|
Toast.makeText(RS485Activity.this, "成功打开串口", Toast.LENGTH_SHORT).show();
|
}
|
}
|
} else if (id == R.id.btn_close){
|
if (!turnFlag) {
|
Toast.makeText(RS485Activity.this, "串口已关闭,不能重复关闭", Toast.LENGTH_SHORT).show();
|
}else {
|
// 关闭串口
|
int rv = RS485Control.closeSerialPort();
|
// Toast.makeText(MainActivity.this, "close", Toast.LENGTH_SHORT).show();
|
if (rv < 0) {
|
Toast.makeText(RS485Activity.this, "关闭串口失败", Toast.LENGTH_SHORT).show();
|
} else {
|
turnFlag = false;
|
serialClosed();
|
Toast.makeText(RS485Activity.this, "关闭串口", Toast.LENGTH_SHORT).show();
|
}
|
}
|
} else if (id == R.id.btn_clear_rev) {
|
// 清空接收区数据
|
mTvRev.setText("");
|
} else if (id == R.id.btn_clear_send) {
|
// 清空发送区内的数据
|
mEtSend.getText().clear();
|
} else if (id == R.id.btn_send) {
|
// 读取发送区中的数据
|
sendData = mEtSend.getText().toString();
|
|
// 判断是否已连接串口, 如果没有连接串口则需先连接串口
|
if( !turnFlag ){
|
Toast.makeText(RS485Activity.this, "串口未打开,请打开串口!", Toast.LENGTH_SHORT).show();
|
}else if(sendData.isEmpty()){
|
// 判断发送区是否为空,如果为空则弹出提示
|
Toast.makeText(RS485Activity.this, "发送区为空,请输入数据!", Toast.LENGTH_SHORT).show();
|
} else if (state != 0) {
|
Toast.makeText(RS485Activity.this, "串口未处于发送状态,不能发送数据!", Toast.LENGTH_SHORT).show();
|
} else {
|
int rv = RS485Control.sendToPort(sendData, sendData.length());
|
if( rv < 0 )
|
{
|
Toast.makeText(RS485Activity.this, "发送数据失败!", Toast.LENGTH_SHORT).show();
|
}
|
Toast.makeText(RS485Activity.this, "发送数据成功", Toast.LENGTH_SHORT).show();
|
|
}
|
} else if (id == R.id.btn_send_state) {
|
// 当gpio4-io26为0时,处于发送模式
|
if( RS485Control.changeState(0) < 0 ){
|
Log.e("Change State for send", "Change State as send failed");
|
}else {
|
state = 0;
|
if (turnFlag)
|
serialOpened();
|
else
|
serialClosed();
|
}
|
} else if (id == R.id.btn_recv_state) {
|
// 当gpio4-io26为1时,处于接收模式
|
if (RS485Control.changeState(1) < 0) {
|
Log.e("Change State for recv", "Change State as recv failed");
|
} else {
|
state = 1;
|
if (turnFlag)
|
serialOpened();
|
else
|
serialClosed();
|
}
|
} else if (id == R.id.btn_recv) {
|
// 当按下按钮后接收一次数据
|
int len = 1024;
|
int timeout = 10;
|
SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
|
df.setTimeZone(TimeZone.getTimeZone("GMT+8"));
|
String date = df.format(new Date());
|
String buf = RS485Control.recvFromPort(len, timeout); // 超时时间设置为 1000 ms
|
if (buf != null) {
|
String revData = date + "\t" + buf;
|
String currentText = mTvRev.getText().toString();
|
String newText = currentText + "\n" + revData; // 追加新数据
|
// mTvRev.setText(newText);
|
mTvRev.append("\n" + revData);
|
mTvRev.invalidate();
|
mTvRev.requestLayout();
|
} else if (buf == null) {
|
System.err.println("Error receiving data.");
|
}
|
}
|
}
|
}
|
|
private void serialClosed(){
|
mTvShow.setTextColor(Color.parseColor("#FF0000"));
|
if(currenState == null){
|
mTvShow.setText("NOT CONNECTED");
|
} else if (currenState.equals("recv"))
|
mTvShow.setText("NOT CONNECTED"+"接收模式");
|
else if (currenState.equals("send")) {
|
mTvShow.setText("NOT CONNECTED"+"发送模式");
|
}
|
mTvShow.setPaintFlags(mTvShow.getPaintFlags() | Paint.ANTI_ALIAS_FLAG);
|
}
|
|
private void serialOpened(){
|
mTvShow.setTextColor(Color.parseColor("#1FA324"));
|
if (state == 1)
|
mTvShow.setText(serial+" OPENED, "+baudRate+", "+dataBits+", "+stopBits+", "+parity+", "+"接收模式");
|
else if (state == 0) {
|
mTvShow.setText(serial+" OPENED, "+baudRate+", "+dataBits+", "+stopBits+", "+parity+", "+"发送模式");
|
}else{
|
mTvShow.setText(serial+" OPENED, "+baudRate+", "+dataBits+", "+stopBits+", "+parity);
|
}
|
|
mTvShow.setPaintFlags(mTvShow.getPaintFlags() | Paint.ANTI_ALIAS_FLAG);
|
}
|
}
|