[JAVA] J'ai essayé d'implémenter une fonction équivalente à Felica Lite avec HCE-F d'Android

introduction

J'ai implémenté une fonction équivalente à Felica Lite avec HCE-F d'Android. Cependant, par souci de simplicité, contrairement à Felica Lite, un seul bloc est accepté lors de la lecture. De plus, comme je ne pouvais pas reproduire la scène où le sondage a repris, je n'ai pas non plus implémenté le sondage.

IDm est supposé être aléatoire, donc il réagit comme une carte de cet IDm indépendamment de l'IDm. (Il existe des restrictions. Pour plus de détails, reportez-vous aux ** Directives d'émulation de carte basée sur l'hôte pour le développement d'applications NFC-F de Sony **.)

image.png

Source de service

Veuillez consulter ce qui suit pour les parties autres que HCEFService.java. Notes et exemple de source HCE-F pour Android

** Cliquez ici pour une utilisation plus simple **

HCEFService.java


/*
zlib License
Copyright (c) 2018 GPS_NMEA_JP

This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages arising from the use of this software.
Permission is granted to anyone to use this software for any purpose, including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/

package com.example.gpsnmeajp.hce_test;

import android.nfc.cardemulation.HostNfcFService;
import android.os.Bundle;
import android.util.Log;
import android.widget.Toast;

public class HCEFService extends HostNfcFService {

    final int PACKET_LENGTH_POS = 0;
    final int PACKET_LENGTH_SIZE = 1;

    final int COMMAND_TYPE_POS = 1;
    final int COMMAND_TYPE_SIZE = 1;

    final int IDM_POS = 2;
    final int IDM_SIZE = 8;

    final int RESPONSE_SIZE = 1;
    final int STATUS_FLAG1_SIZE = 1;
    final int STATUS_FLAG2_SIZE = 1;

    final int BLOCK_NUM_SIZE = 1;
    final int BLOCK_SIZE = 16;

    final int ONE_BLOCK = 1;

    //---
    final byte CMD_POLLING = (byte)0x04;
    final byte RES_POLLING = (byte)0x05;
    final byte CMD_READ_WITHOUT_ENCRYPTION = (byte)0x06;
    final byte RES_READ_WITHOUT_ENCRYPTION = (byte)0x07;
    final byte CMD_WRITE_WITHOUT_ENCRYPTION = (byte)0x08;
    final byte RES_WRITE_WITHOUT_ENCRYPTION = (byte)0x09;

    //---
    final byte STATUS_FLAG1_SUCCESS = (byte)0x00;
    final byte STATUS_FLAG1_FAILED = (byte)0xFF;
    final byte STATUS_FLAG1_FELICA_LITE_ERROR = (byte)0x01;

    final byte STATUS_FLAG2_SUCCESS = (byte)0x00;
    final byte STATUS_FLAG2_READ_ERROR = (byte)0x70;
    final byte STATUS_FLAG2_READONLY = (byte)0xA8;
    final byte STATUS_FLAG2_NEED_AUTH = (byte)0xB1;
    final byte STATUS_FLAG2_SERVICE_NUM_ERROR = (byte)0xA1;
    final byte STATUS_FLAG2_BLOCK_NUM_ERROR = (byte)0xA2;
    final byte STATUS_FLAG2_SERVICE_CODE = (byte)0xA6;
    final byte STATUS_FLAG2_ACCESS_MODE = (byte)0xA7;

    final byte SERVICE_CODE_READ_ONLY = 0x000B;
    final byte SERVICE_CODE_READ_WRITE = 0x0009;


    @Override
    public void onCreate() {
        Log.d("HCEFService(NFCF)","onCreate");
        super.onCreate();
        Toast.makeText(this, "onCreate", Toast.LENGTH_LONG).show();
    }

    @Override
    public void onDestroy() {
        Log.d("HCEFService(NFCF)","onDestroy");
        super.onDestroy();
    }
    //onBind ne peut pas être créé

    @Override
    public byte[] processNfcFPacket(byte[] commandPacket, Bundle extras)
    {
        Log.d("HCEFService(NFCF)","processNfcFPacket: Received NFCF");
        Toast.makeText(this, "processNfcFPacket", Toast.LENGTH_LONG).show();

        //Erreur si moins que les informations requises
        if (commandPacket.length < (PACKET_LENGTH_SIZE+COMMAND_TYPE_SIZE+IDM_SIZE)) {
            Log.e("HCEFService(NFCF)","processNfcFPacket: Packet size too short");
            return null;
        }

        byte commandType = commandPacket[COMMAND_TYPE_POS];
        switch(commandType)
        {
            case CMD_POLLING: return null;//stub
            case CMD_WRITE_WITHOUT_ENCRYPTION: return WriteWithoutEncryption(commandPacket);//stub
            case CMD_READ_WITHOUT_ENCRYPTION: return ReadWithoutEncryption(commandPacket);//stub
            default: return null; //Aucune commande correspondante
        }
    }

    @Override
    public void onDeactivated(int reason) { //Lorsque RF est déconnecté
        if(reason == DEACTIVATION_LINK_LOSS)
        {
            Log.d("HCEFService(NFCF)","onDeactivated: DEACTIVATION_LINK_LOSS");
        }else{
            Log.d("HCEFService(NFCF)","onDeactivated: Unknown reason");
        }
    }

    private byte[] WriteWithoutEncryption(byte[] commandPacket)
    {
        Log.d("HCEFService(NFCF)","WriteWithoutEncryption");
        //response
        int len = PACKET_LENGTH_SIZE + RESPONSE_SIZE + IDM_SIZE + STATUS_FLAG1_SIZE + STATUS_FLAG2_SIZE;
        byte[] responsePacket = new byte[len];
        responsePacket[PACKET_LENGTH_POS] = (byte)len;
        responsePacket[COMMAND_TYPE_POS] = RES_WRITE_WITHOUT_ENCRYPTION;
        responsePacket[len-2] = STATUS_FLAG1_SUCCESS;
        responsePacket[len-1] = STATUS_FLAG2_SUCCESS;

        //Définir IDm
        responsePacket = setIDmToPacket(responsePacket,getIDm(commandPacket));

        //analyze
        int serviceNum = commandPacket[10]&0xFF;
        if(serviceNum != 1)
        {
            responsePacket[len-2] = STATUS_FLAG1_FAILED;
            responsePacket[len-1] = STATUS_FLAG2_SERVICE_NUM_ERROR;
            Log.d("HCEFService(NFCF)","SERVICE_NUM_ERROR");
            return responsePacket; //ERROR RES
        }

        int serviceCode = (commandPacket[11]&0xFF) | ((commandPacket[12]&0xFF)<<8);
        Log.d("HCEFService(NFCF)",String.format("Service code : %04X,",serviceCode));

        if(serviceCode != SERVICE_CODE_READ_WRITE )
        {
            responsePacket[len-2] = STATUS_FLAG1_FELICA_LITE_ERROR;
            responsePacket[len-1] = STATUS_FLAG2_SERVICE_CODE;
            Log.d("HCEFService(NFCF)","STATUS_FLAG2_SERVICE_CODE");
            return responsePacket; //ERROR RES
        }

        int blockNum = commandPacket[13]&0xFF;
        if(blockNum != 1)
        {
            responsePacket[len-2] = STATUS_FLAG1_FAILED;
            responsePacket[len-1] = STATUS_FLAG2_BLOCK_NUM_ERROR;
            Log.d("HCEFService(NFCF)","BLOCK_NUM_ERROR");
            return responsePacket; //ERROR RES
        }

        int blockAddress = -1;
        int blockHeadPos = -1;
        int blocklist_1 = commandPacket[14]&0xFF;
        if(blocklist_1 == 0x80)
        {
            //1byte
            blockAddress = commandPacket[15]&0xFF;
            blockHeadPos = 16;
        }else if(blocklist_1 == 0x00)
        {
            //2byte
            blockAddress = (commandPacket[15]&0xFF) | ((commandPacket[16]&0xFF)<<8);
            blockHeadPos = 17;
        }else{
            responsePacket[len-2] = STATUS_FLAG1_FAILED;
            responsePacket[len-1] = STATUS_FLAG2_ACCESS_MODE;
            Log.d("HCEFService(NFCF)","SERVICE_NUM_ERROR");
            return responsePacket; //ERROR RES
        }

        Log.d("HCEFService(NFCF)",String.format("Block Address : %04X,",blockAddress));

        byte data[] = new byte[BLOCK_SIZE];
        System.arraycopy(commandPacket, blockHeadPos,data , 0, BLOCK_SIZE);

        String debug="";
        for(int i=0;i<data.length;i++)
        {
            debug += String.format("%02X,",data[i]);
        }
        Log.d("HCEFService(NFCF)",debug);
        Log.d("HCEFService(NFCF)","SUCCESS");
        return responsePacket; //SUCCESS
    }
    private byte[] ReadWithoutEncryption(byte[] commandPacket)
    {
        Log.d("HCEFService(NFCF)","ReadWithoutEncryption");
        //response
        int len = PACKET_LENGTH_SIZE + RESPONSE_SIZE + IDM_SIZE + STATUS_FLAG1_SIZE + STATUS_FLAG2_SIZE + BLOCK_NUM_SIZE + BLOCK_SIZE;
        int headLen = PACKET_LENGTH_SIZE + RESPONSE_SIZE + IDM_SIZE + STATUS_FLAG1_SIZE + STATUS_FLAG2_SIZE;
        byte[] responsePacket = new byte[len];
        responsePacket[PACKET_LENGTH_POS] = (byte)len;
        responsePacket[COMMAND_TYPE_POS] = RES_READ_WITHOUT_ENCRYPTION;
        responsePacket[headLen-2] = STATUS_FLAG1_SUCCESS;
        responsePacket[headLen-1] = STATUS_FLAG2_SUCCESS;
        responsePacket[headLen] = ONE_BLOCK;

        //Définir IDm
        responsePacket = setIDmToPacket(responsePacket,getIDm(commandPacket));

        //analyze
        int serviceNum = commandPacket[10]&0xFF;
        if(serviceNum != 1)
        {
            responsePacket[len-2] = STATUS_FLAG1_FAILED;
            responsePacket[len-1] = STATUS_FLAG2_SERVICE_NUM_ERROR;
            Log.d("HCEFService(NFCF)","SERVICE_NUM_ERROR");
            return responsePacket; //ERROR RES
        }

        int serviceCode = (commandPacket[11]&0xFF) | ((commandPacket[12]&0xFF)<<8);
        Log.d("HCEFService(NFCF)",String.format("Service code : %04X,",serviceCode));

        if(serviceCode != SERVICE_CODE_READ_WRITE && serviceCode != SERVICE_CODE_READ_ONLY)
        {
            responsePacket[len-2] = STATUS_FLAG1_FELICA_LITE_ERROR;
            responsePacket[len-1] = STATUS_FLAG2_SERVICE_CODE;
            Log.d("HCEFService(NFCF)","STATUS_FLAG2_SERVICE_CODE");
            return responsePacket; //ERROR RES
        }

        int blockNum = commandPacket[13]&0xFF;
        if(blockNum != 1)
        {
            responsePacket[len-2] = STATUS_FLAG1_FAILED;
            responsePacket[len-1] = STATUS_FLAG2_BLOCK_NUM_ERROR;
            Log.d("HCEFService(NFCF)","BLOCK_NUM_ERROR");
            return responsePacket; //ERROR RES
        }

        int blockAddress = -1;
        int blocklist_1 = commandPacket[14]&0xFF;
        if(blocklist_1 == 0x80)
        {
            //1byte
            blockAddress = commandPacket[15]&0xFF;
        }else if(blocklist_1 == 0x00)
        {
            //2byte
            blockAddress = (commandPacket[15]&0xFF) | ((commandPacket[16]&0xFF)<<8);
        }else{
            responsePacket[len-2] = STATUS_FLAG1_FAILED;
            responsePacket[len-1] = STATUS_FLAG2_ACCESS_MODE;
            Log.d("HCEFService(NFCF)","SERVICE_NUM_ERROR");
            return responsePacket; //ERROR RES
        }

        Log.d("HCEFService(NFCF)",String.format("Block Address : %04X,",blockAddress));

        byte data[] = {(byte)0x00,(byte)0x01,(byte)0x02,(byte)0x03,(byte)0x04,(byte)0x05,(byte)0x06,(byte)0x07,(byte)0x08,(byte)0x09,(byte)0x0A,(byte)0x0B,(byte)0x0C,(byte)0x0D,(byte)0x0E,(byte)0x0F};
        System.arraycopy(data, 0,responsePacket , headLen + BLOCK_NUM_SIZE, BLOCK_SIZE);

        String debug="";
        for(int i=0;i<responsePacket.length;i++)
        {
            debug += String.format("%02X,",responsePacket[i]);
        }
        Log.d("HCEFService(NFCF)",debug);
        Log.d("HCEFService(NFCF)","SUCCESS");

        return responsePacket;
    }

    private byte[] getIDm(byte[] commandPacket)
    {
        byte[] IDm = new byte[8];
        System.arraycopy(commandPacket,2, IDm, 0, 8);

        return IDm;
    }

    private  byte[] setIDmToPacket(byte[] packet,byte[] IDm)
    {
        System.arraycopy(IDm, 0, packet, IDM_POS, IDM_SIZE);// NFCID2
        return packet;
    }
}


Services séparés et traitement à l'aide de LocalBroadCast

hcef_service.java


package jp.ne.sakura.sabowl.gpsnmeajp.intent_hce;

import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.nfc.cardemulation.HostNfcFService;
import android.os.Bundle;
import android.support.v4.content.LocalBroadcastManager;
import android.util.Log;

public class hcef_service extends HostNfcFService {
    @Override
    public void onCreate() {
        super.onCreate();
        Log.d("HCEFService(NFCF)","onCreate");
        LocalBroadcastManager.getInstance(this).registerReceiver(mSendResponsePacketReceiver,
                new IntentFilter("sendResponsePacket"));
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        Log.d("HCEFService(NFCF)","onDestroy");
        LocalBroadcastManager.getInstance(this).unregisterReceiver(mSendResponsePacketReceiver);
    }

    @Override
    public byte[] processNfcFPacket(byte[] commandPacket, Bundle extras)
    {
        Log.d("HCEFService(NFCF)","processNfcFPacket: Received NFCF");

        //Forward
        Intent intent = new Intent("processNfcFPacket");
        intent.putExtra("packet", commandPacket);
        LocalBroadcastManager.getInstance(this).sendBroadcast(intent);
        return null;
    }

    @Override
    public void onDeactivated(int reason) { //Lorsque RF est déconnecté
        Log.d("HCEFService(NFCF)","onDeactivated");

        //Forward
        Intent intent = new Intent("onDeactivated");
        intent.putExtra("reason", reason);
        LocalBroadcastManager.getInstance(this).sendBroadcast(intent);
    }

    private BroadcastReceiver mSendResponsePacketReceiver = new BroadcastReceiver() {
        @Override
        public void onReceive(Context context, Intent intent) {
            byte responsePacket[] = intent.getByteArrayExtra("packet");
            sendResponsePacket(responsePacket);
            Log.d("HCEFService(NFCF)","sendResponsePacket");
        }
    };
}

MainActivity.java


package jp.ne.sakura.sabowl.gpsnmeajp.intent_hce;

import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.pm.PackageManager;
import android.nfc.NfcAdapter;
import android.nfc.cardemulation.NfcFCardEmulation;
import android.os.Bundle;
import android.support.v4.content.LocalBroadcastManager;
import android.support.v7.app.AppCompatActivity;

import android.util.Log;
import android.widget.Toast;

public class MainActivity extends AppCompatActivity{
    private String debugMsgTitle = "NFCF-TEST";

    private NfcAdapter nfcAdapter;
    private NfcFCardEmulation nfcFCardEmulation;
    private ComponentName componentName;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        Log.d(debugMsgTitle, "Create");
        setContentView(R.layout.activity_main);

        //------- HCE-F -------
        LocalBroadcastManager.getInstance(this).registerReceiver(mProcessNfcFPacketReceiver,
                new IntentFilter("processNfcFPacket"));
        LocalBroadcastManager.getInstance(this).registerReceiver(mOnDeactivatedReceiver,
                new IntentFilter("onDeactivated"));

        PackageManager pm = getPackageManager();
        if (!pm.hasSystemFeature(PackageManager.FEATURE_NFC_HOST_CARD_EMULATION_NFCF)) {
            Log.e(debugMsgTitle,"This device not supports HCE-F.");
            finish();
        }else {
            Log.d(debugMsgTitle, "This device supports HCE-F.");
        }

        nfcAdapter = NfcAdapter.getDefaultAdapter(this);
        nfcFCardEmulation = NfcFCardEmulation.getInstance(nfcAdapter);
        componentName = new ComponentName(
                "jp.ne.sakura.sabowl.gpsnmeajp.intent_hce", //Nom du package propre
                "jp.ne.sakura.sabowl.gpsnmeajp.intent_hce.hcef_service"); //Nom propre du service
    }

    @Override
    protected void onResume() {
        super.onResume();
        Log.d(debugMsgTitle,"Resume");

        Log.d(debugMsgTitle,"Enable service");
        nfcFCardEmulation.enableService(this, componentName);
    }

    @Override
    protected void onPause() {
        super.onPause();
        Log.d(debugMsgTitle,"Pause");

        Log.d(debugMsgTitle,"Disable service");
        nfcFCardEmulation.disableService(this);
    }

    //------------------------------------------------

    final int PACKET_LENGTH_POS = 0;
    final int PACKET_LENGTH_SIZE = 1;

    final int COMMAND_TYPE_POS = 1;
    final int COMMAND_TYPE_SIZE = 1;

    final int IDM_POS = 2;
    final int IDM_SIZE = 8;

    final int RESPONSE_SIZE = 1;
    final int STATUS_FLAG1_SIZE = 1;
    final int STATUS_FLAG2_SIZE = 1;

    final int BLOCK_NUM_SIZE = 1;
    final int BLOCK_SIZE = 16;

    final int ONE_BLOCK = 1;

    //---
    final byte CMD_POLLING = (byte)0x04;
    final byte RES_POLLING = (byte)0x05;
    final byte CMD_READ_WITHOUT_ENCRYPTION = (byte)0x06;
    final byte RES_READ_WITHOUT_ENCRYPTION = (byte)0x07;
    final byte CMD_WRITE_WITHOUT_ENCRYPTION = (byte)0x08;
    final byte RES_WRITE_WITHOUT_ENCRYPTION = (byte)0x09;

    //---
    final byte STATUS_FLAG1_SUCCESS = (byte)0x00;
    final byte STATUS_FLAG1_FAILED = (byte)0xFF;
    final byte STATUS_FLAG1_FELICA_LITE_ERROR = (byte)0x01;

    final byte STATUS_FLAG2_SUCCESS = (byte)0x00;
    final byte STATUS_FLAG2_READ_ERROR = (byte)0x70;
    final byte STATUS_FLAG2_READONLY = (byte)0xA8;
    final byte STATUS_FLAG2_NEED_AUTH = (byte)0xB1;
    final byte STATUS_FLAG2_SERVICE_NUM_ERROR = (byte)0xA1;
    final byte STATUS_FLAG2_BLOCK_NUM_ERROR = (byte)0xA2;
    final byte STATUS_FLAG2_SERVICE_CODE = (byte)0xA6;
    final byte STATUS_FLAG2_ACCESS_MODE = (byte)0xA7;

    final byte SERVICE_CODE_READ_ONLY = 0x000B;
    final byte SERVICE_CODE_READ_WRITE = 0x0009;

    private BroadcastReceiver mProcessNfcFPacketReceiver = new BroadcastReceiver() {
        @Override
        public void onReceive(Context context, Intent intent) {
            byte commandPacket[] = intent.getByteArrayExtra("packet");
            Log.d(debugMsgTitle,"processNfcFPacket");

            byte responsePacket[] = processNfcFPacket(commandPacket);
            //Forward
            Intent responceIntent = new Intent("sendResponsePacket");
            responceIntent.putExtra("packet", responsePacket);
            LocalBroadcastManager.getInstance(context).sendBroadcast(responceIntent);
        }
    };

    private BroadcastReceiver mOnDeactivatedReceiver = new BroadcastReceiver() {
        @Override
        public void onReceive(Context context, Intent intent) {
            int reason = intent.getIntExtra("reason",0);
            Log.d(debugMsgTitle,"onDeactivated");
        }
    };

    public byte[] processNfcFPacket(byte[] commandPacket)
    {
        Log.d(debugMsgTitle,"processNfcFPacket: Received NFCF");
        Toast.makeText(this, "processNfcFPacket", Toast.LENGTH_LONG).show();

        Intent intent = new Intent("custom-event-name");
        intent.putExtra("message", "This is my message!");
        LocalBroadcastManager.getInstance(this).sendBroadcast(intent);


        //Erreur si moins que les informations requises
        if (commandPacket.length < (PACKET_LENGTH_SIZE+COMMAND_TYPE_SIZE+IDM_SIZE)) {
            Log.e(debugMsgTitle,"processNfcFPacket: Packet size too short");
            return null;
        }

        byte commandType = commandPacket[COMMAND_TYPE_POS];
        switch(commandType)
        {
            case CMD_POLLING: return null;//stub
            case CMD_WRITE_WITHOUT_ENCRYPTION: return WriteWithoutEncryption(commandPacket);//stub
            case CMD_READ_WITHOUT_ENCRYPTION: return ReadWithoutEncryption(commandPacket);//stub
            default: return null; //Aucune commande correspondante
        }
    }

    private byte[] WriteWithoutEncryption(byte[] commandPacket)
    {
        Log.d(debugMsgTitle,"WriteWithoutEncryption");
        //response
        int len = PACKET_LENGTH_SIZE + RESPONSE_SIZE + IDM_SIZE + STATUS_FLAG1_SIZE + STATUS_FLAG2_SIZE;
        byte[] responsePacket = new byte[len];
        responsePacket[PACKET_LENGTH_POS] = (byte)len;
        responsePacket[COMMAND_TYPE_POS] = RES_WRITE_WITHOUT_ENCRYPTION;
        responsePacket[len-2] = STATUS_FLAG1_SUCCESS;
        responsePacket[len-1] = STATUS_FLAG2_SUCCESS;

        //Définir IDm
        responsePacket = setIDmToPacket(responsePacket,getIDm(commandPacket));

        //analyze
        int serviceNum = commandPacket[10]&0xFF;
        if(serviceNum != 1)
        {
            responsePacket[len-2] = STATUS_FLAG1_FAILED;
            responsePacket[len-1] = STATUS_FLAG2_SERVICE_NUM_ERROR;
            Log.d(debugMsgTitle,"SERVICE_NUM_ERROR");
            return responsePacket; //ERROR RES
        }

        int serviceCode = (commandPacket[11]&0xFF) | ((commandPacket[12]&0xFF)<<8);
        Log.d(debugMsgTitle,String.format("Service code : %04X,",serviceCode));

        if(serviceCode != SERVICE_CODE_READ_WRITE )
        {
            responsePacket[len-2] = STATUS_FLAG1_FELICA_LITE_ERROR;
            responsePacket[len-1] = STATUS_FLAG2_SERVICE_CODE;
            Log.d(debugMsgTitle,"STATUS_FLAG2_SERVICE_CODE");
            return responsePacket; //ERROR RES
        }

        int blockNum = commandPacket[13]&0xFF;
        if(blockNum != 1)
        {
            responsePacket[len-2] = STATUS_FLAG1_FAILED;
            responsePacket[len-1] = STATUS_FLAG2_BLOCK_NUM_ERROR;
            Log.d(debugMsgTitle,"BLOCK_NUM_ERROR");
            return responsePacket; //ERROR RES
        }

        int blockAddress = -1;
        int blockHeadPos = -1;
        int blocklist_1 = commandPacket[14]&0xFF;
        if(blocklist_1 == 0x80)
        {
            //1byte
            blockAddress = commandPacket[15]&0xFF;
            blockHeadPos = 16;
        }else if(blocklist_1 == 0x00)
        {
            //2byte
            blockAddress = (commandPacket[15]&0xFF) | ((commandPacket[16]&0xFF)<<8);
            blockHeadPos = 17;
        }else{
            responsePacket[len-2] = STATUS_FLAG1_FAILED;
            responsePacket[len-1] = STATUS_FLAG2_ACCESS_MODE;
            Log.d(debugMsgTitle,"SERVICE_NUM_ERROR");
            return responsePacket; //ERROR RES
        }

        Log.d(debugMsgTitle,String.format("Block Address : %04X,",blockAddress));

        byte data[] = new byte[BLOCK_SIZE];
        System.arraycopy(commandPacket, blockHeadPos,data , 0, BLOCK_SIZE);

        String debug="";
        for(int i=0;i<data.length;i++)
        {
            debug += String.format("%02X,",data[i]);
        }
        Log.d(debugMsgTitle,debug);
        Log.d(debugMsgTitle,"SUCCESS");
        return responsePacket; //SUCCESS
    }
    private byte[] ReadWithoutEncryption(byte[] commandPacket)
    {
        Log.d(debugMsgTitle,"ReadWithoutEncryption");
        //response
        int len = PACKET_LENGTH_SIZE + RESPONSE_SIZE + IDM_SIZE + STATUS_FLAG1_SIZE + STATUS_FLAG2_SIZE + BLOCK_NUM_SIZE + BLOCK_SIZE;
        int headLen = PACKET_LENGTH_SIZE + RESPONSE_SIZE + IDM_SIZE + STATUS_FLAG1_SIZE + STATUS_FLAG2_SIZE;
        byte[] responsePacket = new byte[len];
        responsePacket[PACKET_LENGTH_POS] = (byte)len;
        responsePacket[COMMAND_TYPE_POS] = RES_READ_WITHOUT_ENCRYPTION;
        responsePacket[headLen-2] = STATUS_FLAG1_SUCCESS;
        responsePacket[headLen-1] = STATUS_FLAG2_SUCCESS;
        responsePacket[headLen] = ONE_BLOCK;

        //Définir IDm
        responsePacket = setIDmToPacket(responsePacket,getIDm(commandPacket));

        //analyze
        int serviceNum = commandPacket[10]&0xFF;
        if(serviceNum != 1)
        {
            responsePacket[len-2] = STATUS_FLAG1_FAILED;
            responsePacket[len-1] = STATUS_FLAG2_SERVICE_NUM_ERROR;
            Log.d(debugMsgTitle,"SERVICE_NUM_ERROR");
            return responsePacket; //ERROR RES
        }

        int serviceCode = (commandPacket[11]&0xFF) | ((commandPacket[12]&0xFF)<<8);
        Log.d(debugMsgTitle,String.format("Service code : %04X,",serviceCode));

        if(serviceCode != SERVICE_CODE_READ_WRITE && serviceCode != SERVICE_CODE_READ_ONLY)
        {
            responsePacket[len-2] = STATUS_FLAG1_FELICA_LITE_ERROR;
            responsePacket[len-1] = STATUS_FLAG2_SERVICE_CODE;
            Log.d(debugMsgTitle,"STATUS_FLAG2_SERVICE_CODE");
            return responsePacket; //ERROR RES
        }

        int blockNum = commandPacket[13]&0xFF;
        if(blockNum != 1)
        {
            responsePacket[len-2] = STATUS_FLAG1_FAILED;
            responsePacket[len-1] = STATUS_FLAG2_BLOCK_NUM_ERROR;
            Log.d(debugMsgTitle,"BLOCK_NUM_ERROR");
            return responsePacket; //ERROR RES
        }

        int blockAddress = -1;
        int blocklist_1 = commandPacket[14]&0xFF;
        if(blocklist_1 == 0x80)
        {
            //1byte
            blockAddress = commandPacket[15]&0xFF;
        }else if(blocklist_1 == 0x00)
        {
            //2byte
            blockAddress = (commandPacket[15]&0xFF) | ((commandPacket[16]&0xFF)<<8);
        }else{
            responsePacket[len-2] = STATUS_FLAG1_FAILED;
            responsePacket[len-1] = STATUS_FLAG2_ACCESS_MODE;
            Log.d(debugMsgTitle,"SERVICE_NUM_ERROR");
            return responsePacket; //ERROR RES
        }

        Log.d(debugMsgTitle,String.format("Block Address : %04X,",blockAddress));

        byte data[] = {(byte)0x00,(byte)0x01,(byte)0x02,(byte)0x03,(byte)0x04,(byte)0x05,(byte)0x06,(byte)0x07,(byte)0x08,(byte)0x09,(byte)0x0A,(byte)0x0B,(byte)0x0C,(byte)0x0D,(byte)0x0E,(byte)0x0F};
        System.arraycopy(data, 0,responsePacket , headLen + BLOCK_NUM_SIZE, BLOCK_SIZE);

        String debug="";
        for(int i=0;i<responsePacket.length;i++)
        {
            debug += String.format("%02X,",responsePacket[i]);
        }
        Log.d(debugMsgTitle,debug);
        Log.d(debugMsgTitle,"SUCCESS");

        return responsePacket;
    }

    private byte[] getIDm(byte[] commandPacket)
    {
        byte[] IDm = new byte[8];
        System.arraycopy(commandPacket,2, IDm, 0, 8);

        return IDm;
    }

    private  byte[] setIDmToPacket(byte[] packet,byte[] IDm)
    {
        System.arraycopy(IDm, 0, packet, IDM_POS, IDM_SIZE);// NFCID2
        return packet;
    }
}

Recommended Posts

J'ai essayé d'implémenter une fonction équivalente à Felica Lite avec HCE-F d'Android
J'ai essayé d'implémenter le traitement Ajax de la fonction similaire dans Rails
J'ai essayé d'implémenter la fonction de prévisualisation d'image avec Rails / jQuery
J'ai essayé de créer une fonction de groupe (babillard) avec Rails
[Rails] Implémentation de la fonction de catégorie multicouche en utilisant l'ascendance "J'ai essayé de créer une fenêtre avec Bootstrap 3"
[Android] Implémentez rapidement la fonction pour afficher le mot de passe
J'ai essayé d'implémenter un serveur en utilisant Netty
J'ai essayé de casser le bloc avec java (1)
[Android] J'ai créé un écran de liste de matériaux avec ListView + Bottom Sheet
J'ai essayé de cloner une application Web pleine de bugs avec Spring Boot
J'ai essayé d'implémenter le téléchargement de fichiers avec Spring MVC
J'ai essayé d'implémenter TCP / IP + BIO avec JAVA
J'ai essayé de créer une fonction de connexion avec Java
J'ai essayé d'implémenter Sterling Sort avec Java Collector
J'ai essayé de créer une fonction / écran d'administrateur de site commercial avec Java et Spring
J'ai essayé de créer une fonction de message de l'extension Rails Tutorial (Partie 1): Créer un modèle
Implémentons une fonction pour limiter le nombre d'accès à l'API avec SpringBoot + Redis
J'ai essayé de créer un environnement de développement java8 avec Chocolatey
J'ai essayé d'ajouter une ligne de séparation à TabLayout sur Android
J'ai essayé de moderniser une application Java EE avec OpenShift.
[Rails] J'ai essayé de créer une mini application avec FullCalendar
Je souhaite implémenter une fonction d'édition des informations produit ~ part1 ~
Je veux créer une fonction avec kotlin et java!
[Rails] J'ai essayé d'implémenter le traitement par lots avec la tâche Rake
J'ai essayé d'implémenter une application web pleine de bugs avec Kotlin
J'ai créé un client RESAS-API en Java
J'ai essayé de créer un environnement de développement padrino avec Docker
J'ai essayé de faire une fonction de réponse de l'extension Rails Tutorial (Partie 3): Correction d'un malentendu des spécifications
J'ai essayé de créer une fonction de message pour l'extension Rails Tutorial (Partie 2): Créer un écran à afficher
J'ai essayé d'interagir avec Java
J'ai essayé de créer une application cartographique simple dans Android Studio
J'ai essayé d'exécuter une application d'échange de cartes de crédit avec Corda 1
Je souhaite ajouter une fonction de navigation avec ruby on rails
J'ai essayé de créer un environnement de serveur UML Plant avec Docker
J'ai essayé d'implémenter un mappage OU flexible avec MyBatis Dynamic SQL
J'ai essayé de créer une application Android avec MVC maintenant (Java)
J'ai essayé de vérifier le fonctionnement du serveur gRPC avec grpcurl
J'ai essayé d'exprimer les résultats avant et après de la classe Date avec une ligne droite numérique
J'ai créé une application d'apprentissage automatique avec Dash (+ Docker) part2 ~ Façon basique d'écrire Dash ~
J'ai essayé de créer une classe parent d'objet de valeur dans Ruby
[Rails] J'ai essayé d'implémenter une transaction qui combine plusieurs processus DB
Je voulais écrire un processus équivalent à une instruction while avec l'API Java 8 Stream
J'ai essayé de démarrer avec Web Assembly
[iOS] J'ai essayé de créer une application de traitement de type insta avec Swift
J'ai essayé de créer une API Web qui se connecte à DB avec Quarkus
Essayez d'implémenter une fonction de connexion avec Spring-Boot
Je voulais mettre en place un diaporama de manière à la mode avec slick.
J'ai essayé d'implémenter le modèle Iterator
J'ai essayé de jouer un peu avec BottomNavigationView ①
Comment implémenter TextInputLayout avec la fonction de validation
J'ai essayé de visualiser l'accès de Lambda → Athena avec AWS X-Ray
J'ai créé une application Janken avec Android
"Professeur, je souhaite implémenter une fonction de connexion au printemps" ① Hello World
J'ai essayé de mesurer et de comparer la vitesse de Graal VM avec JMH
J'ai essayé de créer un portefeuille avec AWS, Docker, CircleCI, Laravel [avec lien de référence]
J'ai créé une application d'apprentissage automatique avec Dash (+ Docker) part3 ~ Practice ~