実現したいこと
Androidデバイスにて、SONY Pasori RC-S380を接続し、IDmの情報をディスプレイに表示するアプリケーションを作成したいです。
前提
質問させていただきます。
NFC非対応端末にて、NFCカードリーダーから情報を読み書きするアプリケーションを開発したいと考えております。
すでに実在するアプリもありますが、今後構想中のアプリに実装したいと考えているためテストや勉強のため、まずは情報を読み込む簡易的なアプリを作っています。
完全な初心者のため、インターネットで調べて情報を集めながら作成し、S380が接続されたら左上にONと表示するところまで実装しましたが、肝心のIDmを表示するということがうまく実現できておりません。
初歩的で申し訳ございませんが、ご教授いただけますと幸いです。
挑戦したフロー
1.webを参考にしながら作成したが、IDmが表示されない。
2.S380を認識していないなど、手前のエラーを確認するため、接続されたらON 未接続でOFFという表示を追加し、表示に成功。
3.テキスト表示ではなく、toastやsnackbarでの表示を試みるが失敗。
該当のソースコード
kotlin
1package com.example.myapplication 2 3import android.app.Activity 4import android.app.PendingIntent 5import android.content.BroadcastReceiver 6import android.content.Context 7import android.content.Intent 8import android.content.IntentFilter 9import android.hardware.usb.* 10import android.os.Bundle 11import android.os.Handler 12import android.os.Looper 13import android.util.Log 14import android.widget.TextView 15import android.widget.Toast 16import com.google.android.material.snackbar.Snackbar 17 18class MainActivity : Activity() { 19 private val TAG = "debug" 20 private val ACTION_USB_PERMISSION = "com.example.myapplication.USB_PERMISSION" 21 22 private var manager: UsbManager? = null 23 private var rcs380: UsbDevice? = null 24 private var ep_in: UsbEndpoint? = null 25 private var ep_out: UsbEndpoint? = null 26 private var con: UsbDeviceConnection? = null 27 private lateinit var textView: TextView 28 private lateinit var usbPermissionIntent: PendingIntent 29 private lateinit var usbPermissionReceiver: BroadcastReceiver 30 private lateinit var deviceStatusTextView: TextView 31 32 override fun onCreate(savedInstanceState: Bundle?) { 33 super.onCreate(savedInstanceState) 34 setContentView(R.layout.activity_main) 35 36 textView = findViewById(R.id.text_view) 37 manager = getSystemService(Context.USB_SERVICE) as UsbManager 38 39 usbPermissionIntent = PendingIntent.getBroadcast( 40 this, 0, Intent(ACTION_USB_PERMISSION), 41 PendingIntent.FLAG_IMMUTABLE or PendingIntent.FLAG_UPDATE_CURRENT 42 ) 43 44 usbPermissionReceiver = object : BroadcastReceiver() { 45 override fun onReceive(context: Context, intent: Intent) { 46 if (ACTION_USB_PERMISSION == intent.action) { 47 synchronized(this) { 48 val device: UsbDevice? = intent.getParcelableExtra<UsbDevice>(UsbManager.EXTRA_DEVICE) 49 50 if (intent.getBooleanExtra(UsbManager.EXTRA_PERMISSION_GRANTED, false)) { 51 device?.apply { 52 connectDevice(this) 53 } 54 } else { 55 Log.d(TAG, "Permission denied for device $device") 56 } 57 } 58 } 59 } 60 } 61 62 val filter = IntentFilter(ACTION_USB_PERMISSION) 63 registerReceiver(usbPermissionReceiver, filter) 64 65 discoverDevices() 66 67 // デバイスの接続状態を表示するTextViewを初期化 68 deviceStatusTextView = findViewById(R.id.deviceStatusTextView) 69 70 // USBデバイスの接続・切断を監視するBroadcastReceiverを設定 71 setupUsbDeviceBroadcastReceiver() 72 } 73 74 //ここから追加 75 private fun setupUsbDeviceBroadcastReceiver() { 76 val usbDeviceFilter = IntentFilter().apply { 77 addAction(UsbManager.ACTION_USB_DEVICE_ATTACHED) 78 addAction(UsbManager.ACTION_USB_DEVICE_DETACHED) 79 } 80 registerReceiver(usbDeviceBroadcastReceiver, usbDeviceFilter) 81 } 82 83 private val usbDeviceBroadcastReceiver = object : BroadcastReceiver() { 84 override fun onReceive(context: Context, intent: Intent) { 85 when (intent.action) { 86 UsbManager.ACTION_USB_DEVICE_ATTACHED -> checkDeviceAndDisplayStatus() 87 UsbManager.ACTION_USB_DEVICE_DETACHED -> checkDeviceAndDisplayStatus() 88 } 89 } 90 } 91 92 private fun checkDeviceAndDisplayStatus() { 93 val isRcs380Connected = manager?.deviceList?.values?.any { it.vendorId == 0x054C && it.productId == 0x06C3 } == true 94 deviceStatusTextView.text = if (isRcs380Connected) "ON" else "OFF" 95 } 96 //ここまで 97 98 private fun discoverDevices() { 99 val deviceList = manager?.deviceList 100 deviceList?.values?.forEach { device -> 101 if (device.productId == 0x06C3 && device.vendorId == 0x054C) { 102 rcs380 = device 103 if (!manager!!.hasPermission(device)) { 104 manager?.requestPermission(device, usbPermissionIntent) 105 } else { 106 connectDevice(device) 107 } 108 } 109 } 110 } 111 112 private fun connectDevice(device: UsbDevice) { 113 con = manager?.openDevice(device) 114 if (con == null) { 115 Log.d(TAG, "Connection is null") 116 return 117 } 118 119 con?.apply { 120 if (!claimInterface(device.getInterface(0), true)) { 121 Log.d(TAG, "Cannot claim interface") 122 close() 123 return 124 } 125 126 device.getInterface(0)?.apply { 127 for (i in 0 until endpointCount) { 128 val ep = getEndpoint(i) 129 if (ep.direction == UsbConstants.USB_DIR_IN && ep.type == UsbConstants.USB_ENDPOINT_XFER_BULK) { 130 ep_in = ep 131 } else if (ep.direction == UsbConstants.USB_DIR_OUT && ep.type == UsbConstants.USB_ENDPOINT_XFER_BULK) { 132 ep_out = ep 133 } 134 } 135 } 136 } 137 138 readFelica() 139 } 140 141 // IDmを読み取り、結果をToastで表示するメソッド 142 private fun readFelica() { 143 // InListPassiveTarget Felica 144 val cmd = byteArrayOf(0xd4.toByte(), 0x4a, 0x1, 0x1, 0x0, 0xff.toByte(), 0xff.toByte(), 0x1, 0x0) 145 146 // rwCommandメソッドを呼び出してコマンドを送信し、成功したかどうかをチェック 147 val isSuccess = rwCommand(cmd, cmd.size) 148 149 // 実行結果に基づいてToastメッセージを表示 150 // 成功した場合はrwCommandメソッド内でIDmが表示されるので、ここでは何もしない 151 // 失敗した場合はToastメッセージで通知 152 if (!isSuccess) { 153 showToast("IDmの読み取りに失敗しました") 154 } 155 156 // 定期的に読み取りを繰り返す場合 157 Handler(Looper.getMainLooper()).postDelayed({ readFelica() }, 250) 158 } 159 160 private fun showSnackbar(message: String) { 161 runOnUiThread { 162 Snackbar.make(findViewById(android.R.id.content), message, Snackbar.LENGTH_LONG).show() 163 } 164 } 165 166 private fun rwCommand(cmd: ByteArray, cmd_len: Int): Boolean { 167 // 応答を受け取るためのバッファ 168 val tmp = ByteArray(64) 169 170 var buf = ByteArray(cmd_len + 7) 171 val dcs = calcDCS(cmd, cmd_len) 172 173 buf[0] = 0x0 174 buf[1] = 0x0 175 buf[2] = 0xff.toByte() 176 buf[3] = cmd_len.and(0xff).toByte() 177 buf[4] = (0x100 - buf[3]).and(0xff).toByte() 178 179 var co = 5 180 for (i in 0 until cmd_len) { 181 buf[co] = cmd[i] 182 co++ 183 } 184 185 buf[co] = dcs 186 co++ 187 buf[co] = 0x0 188 189 if (con?.bulkTransfer(ep_out, buf, buf.size, 100) != buf.size) { 190 Log.d(TAG, "Error USB Send") 191 return false 192 } 193 194 // USBデバイスから応答を受け取る 195 val responseLength = con?.bulkTransfer(ep_in, tmp, tmp.size, 100) 196 197 if (responseLength == null || responseLength < 0) { 198 Log.d(TAG, "応答に失敗しました") 199 return false 200 } 201 202 // 応答からIDmを取得する処理 203 if (tmp[5] == 0xd5.toByte() && tmp[6] == 0x4b.toByte() && tmp[7] == 0x1.toByte()) { 204 if (tmp[8] == 0x1.toByte()) { 205 var idm = "" 206 for (i in 11..18) { 207 idm += "%02x".format(tmp[i]) 208 } 209 showToast("IDm: $idm") 210 return true 211 } 212 } 213 214 showToast("IDmの読み取りに失敗しました") 215 return false 216 } 217 218 private fun showToast(message: String) { 219 runOnUiThread { 220 Toast.makeText(this, message, Toast.LENGTH_SHORT).show() 221 } 222 } 223 224 225 226 227 // calcDCSメソッドをここに定義 228 private fun calcDCS(datas: ByteArray, size: Int): Byte { 229 var sum = 0 230 for (i in 0 until size) { 231 sum += datas[i].toInt() and 0xFF 232 } 233 return ((0x100 - sum) and 0xFF).toByte() 234 } 235 override fun onDestroy() { 236 super.onDestroy() 237 // BroadcastReceiverの登録を解除 238 unregisterReceiver(usbDeviceBroadcastReceiver) 239 } 240 241 242 243} 244
試したこと
・toastやsnackbarでの表示
・カードリーダーの抜き差し、カードリーダーの交換
・すでに実装されたandroidアプリケーションでS380を接続、認識と動作をすることを確認
補足情報(FW/ツールのバージョンなど)
Android端末: FireHD 10 Plus 第11世代(このデバイスを使う必要があり、このデバイス以外で動作させることはありません)
FW:Fire OS 7.3.2.9
参考にさせていただいたURL
https://github.com/nagai-takayuki/Android/tree/master/FCFReaderForPasori
https://qiita.com/KazuyukiEguchi/items/8ed62198561449e4d64a
http://www.cc.kumamoto-u.ac.jp/nagai/apps/FCFReaderForPaSoRi
http://www.cc.kumamoto-u.ac.jp/sites/default/files/H3-2.pdf

回答1件
あなたの回答
tips
プレビュー