工程项目CPU卡读取数据信息。

这个博客详细介绍了如何在Android应用中实现CPU卡数据的读取操作。通过创建服务和广播接收者,实现了串口通信,设备初始化,以及读取数据的线程管理。在读取过程中,应用根据接收到的响应数据进行解析,获取数据长度,并按需多次读取以处理超过200字节的数据。此外,还展示了如何处理读取数据后的保存操作。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

/**
 * 设备服务,用于在后台运行,发送命令和接收数据
 * 在服务初始化时,执行串口打开,设备电源开启,
 * 获取串口输入输出流
 * 启动读数据线程
 *DeviceService 类

【布局文件】

<?xml version="1.0" encoding="UTF-8"?>

<!-- 非接触cpu卡 -->
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/cpu_card"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:orientation="vertical" >


    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_alignParentLeft="true"
        android:layout_alignParentTop="true"
        android:layout_marginTop="30dp"
        android:orientation="vertical" >
        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_marginTop="10dp"
            android:orientation="horizontal" >
            <TextView
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="@string/send_data" />
            <EditText
                android:id="@+id/ucpu_send_data"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:singleLine="true" />
        </LinearLayout>


        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_marginTop="10dp"
            android:orientation="horizontal" >
            <TextView
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="@string/receive_data" />
            <EditText
                android:id="@+id/ucpu_receive_data"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                 />
        </LinearLayout>
<LinearLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_marginTop="20dp"
            android:orientation="horizontal" >
            <TextView
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="定义读取数据后保存名称为:" />
            <EditText
                android:id="@+id/fileName"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:singleLine="true" />
        </LinearLayout>     
    </LinearLayout>
    <TableLayout
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:layout_alignParentBottom="true"
        android:layout_centerHorizontal="true" >
        <TableRow
            android:layout_width="fill_parent"
            android:layout_height="wrap_content"
            android:layout_weight="2" >
            <Button
                android:id="@+id/ucpu_active_card"
                android:layout_width="0dp"
                android:layout_height="wrap_content"
                android:layout_weight="1"
                android:text="@string/active_card" />
           <Button
                android:id="@+id/ucpu_selectLenEF1"
                android:layout_width="0dp"
                android:layout_height="wrap_content"
                android:layout_weight="1"
                android:text="选择EF1"           
                />  
                  <Button
                android:id="@+id/ucpu_selectLenEF2"
                android:layout_width="0dp"
                android:layout_height="wrap_content"
                android:layout_weight="1"
                android:text="选择EF2"               
                />  
           <Button
                android:id="@+id/ucpu_readLen"
                android:layout_width="0dp"
                android:layout_height="wrap_content"
                android:layout_weight="1"
                android:text="读长度"                 
                />                  
        </TableRow>
        <TableRow
            android:layout_width="fill_parent"
            android:layout_height="wrap_content"
            android:layout_weight="2" >                        
             <Button
                android:id="@+id/ucpu_read"
                android:layout_width="0dp"
                android:layout_height="wrap_content"
                android:layout_weight="1"
                android:text="读文件" />                           
        </TableRow>
         <TableRow
            android:layout_width="fill_parent"
            android:layout_height="wrap_content"
            android:layout_weight="2" >          
              <Button
                android:id="@+id/ucpu_send_cmd"
                android:layout_width="0dp"
                android:layout_height="wrap_content"
                android:layout_weight="1"
                android:text="发送指令" />
             <Button
                android:id="@+id/ucpu_close_card"
                android:layout_width="0dp"
                android:layout_height="wrap_content"
                android:layout_weight="1"
                android:text="@string/close_card"                 
                />                
        </TableRow>
    </TableLayout>

</RelativeLayout>

【读取类】


package com.example.psam_demo;


import java.io.File;
import java.io.FileOutputStream;
import java.text.DecimalFormat;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Semaphore;


import com.android.rfid.PSAM;
import com.android.rfid.Tools;
import com.example.service.DeviceService;


import android.app.Activity;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.Bundle;
import android.os.Environment;
import android.os.Looper;
import android.util.Log;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.EditText;
import android.widget.Toast;


public class UcpuSplitReadActivity extends Activity implements OnClickListener {
private EditText receive_data,send_data,fileName;
private Button active_card,cpu_read,ucpu_readLen,close_card,send_cmd;
private Button ucpu_selectLenEF1,ucpu_selectLenEF2;
private MyBroadcast myReceiver;  //广播接收者
private PSAM mpsam;
private String TAG = "读取类";
private String activity = "com.example.psam_demo.UcpuSplitReadActivity";
public int cmd_flag = 0; 
    ExecutorService readexec = Executors.newCachedThreadPool(); // 只能1个线程同时访问
    final Semaphore readsemp = new Semaphore(1);
  
//接收数组  
long ff=0;
boolean isread=false;
List<byte[]>  byteList=new ArrayList<byte[]>() ;
long EF_len=0;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_ucpu_split_read);
              //初始化
init();
}


private void init() {
fileName= (EditText) findViewById(R.id.fileName);
send_data = (EditText) findViewById(R.id.ucpu_send_data);
receive_data = (EditText) findViewById(R.id.ucpu_receive_data);
active_card = (Button) findViewById(R.id.ucpu_active_card);
close_card = (Button) findViewById(R.id.ucpu_close_card);
send_cmd = (Button) findViewById(R.id.ucpu_send_cmd);
ucpu_selectLenEF1=(Button) findViewById(R.id.ucpu_selectLenEF1);
ucpu_selectLenEF2=(Button) findViewById(R.id.ucpu_selectLenEF2);
ucpu_readLen= (Button) findViewById(R.id.ucpu_readLen);
cpu_read = (Button) findViewById(R.id.ucpu_read);

active_card.setOnClickListener(this);
ucpu_selectLenEF1.setOnClickListener(this);
ucpu_selectLenEF2.setOnClickListener(this);
ucpu_readLen.setOnClickListener(this);
cpu_read.setOnClickListener(this);
send_cmd.setOnClickListener(this);
close_card.setOnClickListener(this);
}
@Override
protected void onResume() {
myReceiver = new MyBroadcast();
mpsam = new PSAM();//实例化mpsam,用于调用协议封装命令
IntentFilter filter = new IntentFilter();
filter.addAction(activity);
registerReceiver(myReceiver, filter); //注册广播接收者
super.onResume();


}


@Override
protected void onPause() {
unregisterReceiver(myReceiver);  //卸载广播接收者
cmd_flag = 0;
super.onPause();
}
private class ReadThread extends Thread {


long ff=0;//一次读取200字节,要读多少个200的长度数据,算出要 读的次数
long yu=0;
public ReadThread(long ff, long yu) {
this.ff=ff;
this.yu=yu;
}
@Override
public void run() {
super.run();
Looper.prepare();
 
 
 byte[] mycmd=null;
 
 synchronized (this) {
 for(int a=1;a<=(ff+1);a++){//首次读取200字节,位置从3开始, ff+1读不足200的余数据
 

 try {
readsemp.acquire();
Thread.sleep((long) (Math.random() * 3000));
} catch (InterruptedException e) {
e.printStackTrace();
}
 
 Intent myservice = new Intent(UcpuSplitReadActivity.this,DeviceService.class);  //用于发送指令
    int offset=(200*(a-1)+3);//+3=前三字节为数据长度,后面的才是数据
String offsetHexString=Integer.toHexString(offset);//读取偏移量
String cmdHead="";//根据偏移量改变P1P2命令头
if(offsetHexString.length()==1){
cmdHead="00B0000"+offsetHexString+"C8";
}else if(offsetHexString.length()==2){
cmdHead="00B000"+offsetHexString+"C8";
}else if(offsetHexString.length()==3){
cmdHead="00B00"+offsetHexString+"C8";
}else{
cmdHead="00B0"+offsetHexString+"C8";
}
//Log.e("读取==偏移量", offsetHexString+"=="+"");
if(a!=(ff+1)){
 mycmd = mpsam.ucpu_send_cmd(Tools.HexString2Bytes(cmdHead));


//读取
cmd_flag = 25;
// byte[] mycmd = mpsam.ucpu_send_cmd(Tools.HexString2Bytes(cmdHead));
 myservice.putExtra("cmd", mycmd); 
 UcpuSplitReadActivity.this.startService(myservice); 
           Log.e("my发送read: " +a +"==", cmdHead+"=="+"");
           try {
Thread.sleep( 3000);
} catch (InterruptedException e) {
e.printStackTrace();
}//




}else{//ff+1读余数据 yu==0不发送
if(yu!=0){
String lastDataLength=Integer.toHexString((int)yu);//最后一次要读的数据长度


// cmdHead.replace("C8", lastDataLength);
String yuHead="";
if(offsetHexString.length()==1){
yuHead="00B0000"+offsetHexString;
}else if(offsetHexString.length()==2){
yuHead="00B000"+offsetHexString;
}else if(offsetHexString.length()==3){
yuHead="00B00"+offsetHexString;
}else{
yuHead="00B0"+offsetHexString;
}
if(lastDataLength.length()==1){
cmdHead=yuHead+"0"+lastDataLength;
}else if(lastDataLength.length()==2){
cmdHead=yuHead+lastDataLength;
}
 
 
// Log.e("my替换: "+cmdHead,"");
mycmd = mpsam.ucpu_send_cmd(Tools.HexString2Bytes(cmdHead));




//读取
cmd_flag = 25;
// byte[] mycmd = mpsam.ucpu_send_cmd(Tools.HexString2Bytes(cmdHead));
 myservice.putExtra("cmd", mycmd); 
 UcpuSplitReadActivity.this.startService(myservice); 
           Log.e("后my发送read: " +a +"==", cmdHead+"=="+"");
         
           readexec.shutdownNow();//


}

}
 
 


 
 
}//for
 }//syn
 
 
Looper.loop();
}
}




@Override
public void onClick(View v) {
// 给服务发送广播,内容为com.example.psam_demo.M1CardActivity
Intent ac = new Intent();
ac.setAction("com.example.service.DeviceService");
ac.putExtra("activity", activity);
sendBroadcast(ac);
Log.e(TAG, "send broadcast");

receive_data.setText(""); //清空数据
byte[] cmd = null; // 用于存放指令
Intent sendToservice = new Intent(UcpuSplitReadActivity.this,DeviceService.class);  //用于发送指令

switch (v.getId()) {
case R.id.ucpu_active_card:  //激活卡片
cmd_flag = 1;
cmd = mpsam.ucpu_open();
if(cmd != null){
Log.e(TAG, Tools.Bytes2HexString(cmd, cmd.length));
}else{

}
break;
case R.id.ucpu_selectLenEF1://选择文件 获取读取数据长度
cmd_flag = 2;
cmd = mpsam.ucpu_send_cmd(Tools.HexString2Bytes("00A4000002200100"));
if(cmd != null){                                 
Log.e(TAG, Tools.Bytes2HexString(cmd, cmd.length));
}else{

}
break;
case R.id.ucpu_selectLenEF2://选择文件 获取读取数据长度
cmd_flag = 2;
cmd = mpsam.ucpu_send_cmd(Tools.HexString2Bytes("00A4000002200200"));
if(cmd != null){                                 
Log.e(TAG, Tools.Bytes2HexString(cmd, cmd.length));
}else{

}
break;
case R.id.ucpu_readLen://读取cpu卡某文件的前3字节6位长度数据,以获得该文件长度。3字节6位数据中,长度是数字,不足6位补C.
cmd_flag = 3;
cmd = mpsam.ucpu_send_cmd(Tools.HexString2Bytes("00B0000003"));
if(cmd != null){                                 
Log.e(TAG, Tools.Bytes2HexString(cmd, cmd.length));
}else{

}
break;
case R.id.ucpu_read://
if(EF_len>200){//数据信息大于200,循环读取
double pi =EF_len/200;// 
String nn=new DecimalFormat("0000").format(pi);
ff= Long.parseLong(nn);//一次写200字节,写图片的长度数据,算出要 写的次数
long yu=EF_len%200;
Log.e(nn+"获取图片模板"+EF_len+"==", ff+"==ff==yu"+yu);
if(!isread){
synchronized(this){
if(byteList.size()>0&&byteList!=null){
       byteList.clear();
       }
  ReadThread mReadThread = new ReadThread(ff,yu);
  mReadThread.start();
}
}else{
Toast.makeText(getApplicationContext(), "请等待读取完毕!", Toast.LENGTH_SHORT).show();
}
}else{//数据信息小于200,直接读取偏移量03
String readLen=Integer.toHexString((int)EF_len);//读取长度转16进制
String cmdHead="";//根据偏移量改变P1P2命令头
if(readLen.length()==1){
cmdHead="00B000030"+readLen;
}else if(readLen.length()==2){
cmdHead="00B00003"+readLen;
}


 cmd_flag = 25;
 cmd = mpsam.ucpu_send_cmd(Tools.HexString2Bytes(cmdHead));

 Log.e("直接读取不足200的文件"+EF_len+"==", "");

}
break;
case R.id.ucpu_send_cmd:// 发送命令
cmd_flag = 5;
String data = send_data.getText().toString();
cmd = mpsam.ucpu_send_cmd(Tools.HexString2Bytes(data));
if(cmd != null){
Log.e(TAG, Tools.Bytes2HexString(cmd, cmd.length));
}else{

}
break;
case R.id.ucpu_close_card:   //关闭卡片
cmd_flag = 6;
cmd = mpsam.ucpu_close();
if(cmd != null){
Log.e(TAG, Tools.Bytes2HexString(cmd, cmd.length));
}else{

}


break;


default:
break;
}
sendToservice.putExtra("cmd", cmd);
UcpuSplitReadActivity.this.startService(sendToservice);  //发送指令给
}



/**
*  广播接收者,接收服务发送过来的数据,并更新UI
* @author Administrator
*
*/
private class MyBroadcast extends BroadcastReceiver {


@Override
public void onReceive(Context context, Intent intent) {

String receivedata = intent.getStringExtra("result"); // 服务返回的数据
if (receivedata != null) {
switch (cmd_flag) {
case 1:
byte []active_buffer1 = Tools.HexString2Bytes(receivedata);
byte []active_data1 = mpsam.resolveDataFromDevice(active_buffer1);
if(active_data1 != null){
receive_data.setText(Tools.Bytes2HexString(active_data1, active_data1.length));
//Toast.makeText(getApplicationContext(), "激活卡片成功", Toast.LENGTH_SHORT).show();
}else{
Toast.makeText(getApplicationContext(), "激活卡片失败", Toast.LENGTH_SHORT).show();
}
break;
case 2://select EF1
byte []active_buffer2 = Tools.HexString2Bytes(receivedata);
byte []active_data2 = mpsam.resolveDataFromDevice(active_buffer2);
if(active_data2 != null){
receive_data.setText(Tools.Bytes2HexString(active_data2, active_data2.length));
}else{
}
break;
case 3://read EF1 length
byte []active_buffer3 = Tools.HexString2Bytes(receivedata);
byte []active_data3 = mpsam.resolveDataFromDevice(active_buffer3);
if(active_data3 != null){
String response=Tools.Bytes2HexString(active_data3, active_data3.length);
String len=response.substring(0, response.indexOf("C"));//要读的数据长度,3字节6位。如读取数据位:08CCCC 说明长度为08,CCCC是补足部分,对数据进行截取,以C首次出现的位置做接束,即可获得后续3字节之后的信息数据长度是多少。然后根据EF_len依次读取200,算出要的的次数。EF_len+1等于要读的不足200的部分既多读一次。
EF_len=Long.parseLong(len);
receive_data.setText(EF_len+"");
Log.e("rrrrrrr=="+len, "sssssssss"+EF_len);

}else{
}
break;
case 4://select EF2
byte []active_buffer4 = Tools.HexString2Bytes(receivedata);
byte []active_data4 = mpsam.resolveDataFromDevice(active_buffer4);
if(active_data4 != null){
receive_data.setText(Tools.Bytes2HexString(active_data4, active_data4.length));

}else{
}
break;
case 5://cmd
byte []uu = Tools.HexString2Bytes(receivedata);
byte []data = mpsam.resolveDataFromDevice(uu);
if(data != null){
receive_data.setText(Tools.Bytes2HexString(data, data.length));
}else{
}
break;
case 6://close
byte []close_buffer = Tools.HexString2Bytes(receivedata);
int close_data = mpsam.rf_check_data(close_buffer);
if(close_data != 0){
Toast.makeText(getApplicationContext(), "关闭卡片失败", Toast.LENGTH_SHORT).show();
}else{
Toast.makeText(getApplicationContext(), "关闭卡片成功", Toast.LENGTH_SHORT).show();
}
break;
case 25: //read EF2 data
synchronized(this){
String hh=receivedata.substring(12, receivedata.length()-8);
byte [] JJ = Tools.HexString2Bytes(hh);
// byte [] JJ = Tools.HexString2Bytes(receivedata);

Log.e("读25文件返回数据==", Tools.Bytes2HexString(JJ, JJ.length));

if(JJ != null){
byteList.add(JJ);

}
readsemp.release();

 
 
if(fileName.getText().toString()!=null&&!fileName.getText().toString().equals("")){
String name= fileName.getText().toString();
   try {  
    String pathMoban=MyApplication.filePath+"/"+name;
// String pathMoban=Environment.getExternalStorageDirectory()+"/KHDZ_Device/"+name;
File file = new File(pathMoban);  
file.createNewFile();
       FileOutputStream fos = new FileOutputStream(file,false);  
       Log.e("拆分写入=="+pathMoban,"==");
       for (int i = 0; i < byteList.size(); i++) { 
        Log.e("aa22集合数据=="+i+"=="+ff, Tools.Bytes2HexString(byteList.get(i), byteList.get(i).length)+"");
        fos.write(byteList.get(i));  

       if(i==ff){//接收次数==写入的次数   说明读取完毕。
        receive_data.setText("read over !");
        isread=false;
        break;
       }else{
        isread=true;
        receive_data.setText("reading !");
       }
       
       } 
     
       fos.close();
       } catch (Exception e) {  
        receive_data.setText("Exception !");
        // Log.e("写入yi==","=="+e);
           e.printStackTrace();  
       } 
}else{
 Toast.makeText(getApplicationContext(), "请输入文件要保存的名称!", Toast.LENGTH_SHORT).show();
}
 
 
    break;


default:
break;




}
}
}


}
}


评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值