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 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); } }