SONY製のNFCカードリーダ RC-S620/S をイニシエータとして使用し、NFC Type-A/Bと通信するライブラリです。FeliCaとは通信できません。(This library can't communicate with FeliCa! Only for NFC Type-A/B.)

Dependents:   DLC_STARTER

Revision:
0:16a4197a4dfb
Child:
1:98c4a45b646a
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/RCS620S_AB.cpp	Fri May 29 09:12:00 2020 +0000
@@ -0,0 +1,340 @@
+#include "mbed.h"
+#include "RCS620S_AB.h"
+
+//public function
+
+    //rc-s620 デフォルトボーレート;115200
+    RCS620S_AB::RCS620S_AB(PinName tx, PinName rx):
+        _serial(tx, rx, 115200){
+        initialize();
+    };
+
+/***************/
+/**** 制御系 ****/
+/***************/
+
+    void RCS620S_AB::powerDown(){
+        sendCommand_and_RecieveRes(wired_data_RFConfiguration_PowerDown,(uint16_t)sizeof(wired_data_RFConfiguration_PowerDown));
+    }
+    
+    void RCS620S_AB::wakeUp(){
+        _serial.putc(0x55);
+        wait_ms(50);
+    }
+
+    void RCS620S_AB::reset(){
+         //”カードを”リセットするためにRFをOFF
+        sendCommand_and_RecieveRes(wired_data_RFConfiguration_RFoff,(uint16_t)sizeof(wired_data_RFConfiguration_RFoff));
+        wait_ms(50);
+        sendCommand_and_RecieveRes(wired_data_Reset,(uint16_t)sizeof(wired_data_Reset));
+    }
+    
+/***************/
+/**** 受信系 ****/
+/***************/
+    /*受信バッファ配列 要素番号カンペ (ATQB受信例)
+    
+    [11]D5 [12]4B [13]Tg [14~][CardRes] DCS
+    
+    [ 0] 00 [ 1] 00 [ 2] FF [ 3] 00 [ 4] FF [ 5] 00  ~ACK
+    [ 6] 00 [ 7] 00 [ 8] FF [ 9] 12 [10] EE ~LCS
+    [11] D5 [12] 4B [13] 01 [14] 01 [15] 50 ・・・ [LEN-2] DCS [LEN-1] 00
+    ・全部ほしい場合:[0] ~ [LEN-1]
+    ・レスポンス部が欲しい場合:[11] ~ [LEN-3]
+    ・カードのデータ部が欲しい場合:[14] ~ [LEN-3]
+    */
+
+    //重要!配列要素集は0始まりのためLENと1ずれる!
+
+    //※デバッグ用 受信バッファーのデータを全て取得(ACKやチェックサム含むすべてのデータ)
+    void RCS620S_AB::getAllRes(uint8_t ansArray[], int *ansLen){
+        extractRes(0, recieveLEN-1 , ansArray, ansLen);
+    }
+    
+    //ACKやチェックサムを除いたレスポンスを取得
+    void RCS620S_AB::getRes(uint8_t ansArray[], int *ansLen){
+        uint8_t dataLen = checkRxData_and_getLEN();
+        if(dataLen > 0){
+            extractRes(11, 11+dataLen-3 , ansArray, ansLen);
+        }else{
+            ansArray[0] = 0x00;
+            *ansLen = 0;
+        }
+    }
+    
+    //inListPasseveTarget 及び inDataExchangeからカード情報だけを取得
+    void RCS620S_AB::getCardRes(uint8_t ansArray[], int *ansLen){
+        
+        //inListPassiveTargetの場合 [11]D5 [12]4B [13]Tg [14~][CardRes] DCS
+        //inDataExchangeの場合 [11]D5 [12]41 [13]Status [14~][CardRes] DCS
+        //⇒共用可能
+        
+        if(checkCardRes()){
+            extractRes(14, recieveLEN-3 , ansArray, ansLen);
+        }else{
+            ansArray[0] = 0x00;
+            *ansLen = 0;
+        }
+    }
+
+/***************/
+/**** 送信系 ****/
+/***************/
+ 
+    //ICカードのコマンドのデータパケット部を受け取り、チェックサムなどの付加情報を付与し送信
+    void RCS620S_AB::sendCommand_and_RecieveRes(const uint8_t wired_packet_data[], uint16_t wired_packet_data_len){
+       
+        //長すぎたらエラー
+        if(wired_packet_data_len > 252){
+            exit(1);
+        }
+        
+        //0xD4で始まらなかったらエラー
+        if(wired_packet_data[0] != 0xD4){
+            exit(1);
+        }
+        
+        //送信コマンド = 0x00 0x00 0xff LEN LCS [DATA PACKET] DCS 0x00
+        
+        uint8_t *packet_data_command;
+        uint8_t LEN, LCS, DCS = 0x00;
+        uint32_t data_sum = 0x00000000;
+        
+        int i = 0;
+        
+        //LEN・LCSを計算
+        LEN = (uint8_t)(wired_packet_data_len);   //送信データの長さ
+        LCS = (uint8_t)(0x0100 - LEN);
+    
+        //card_command+リーダライタコマンド分のメモリを確保
+        
+        packet_data_command = (uint8_t*)malloc(sizeof(uint8_t) * (LEN + 7));
+        
+        
+        //カードリーダのコマンドを送信データに結合
+        
+        packet_data_command[0] = 0x00;   //Preamble
+        packet_data_command[1] = 0x00;   //Start Of Packet_1
+        packet_data_command[2] = 0xff;   //Start Of Packet_2
+        
+        packet_data_command[3] = LEN;   //LEN
+        packet_data_command[4] = LCS;   //LCS
+        
+        //パケットデータを流し込む
+        for(i = 0; i < LEN; i++){
+            packet_data_command[i + 5] = wired_packet_data[i];   //DATA
+            data_sum = data_sum + wired_packet_data[i];  //DCS計算用
+        }
+       
+        //DCSを計算
+        DCS = (uint8_t)(0x100 - (data_sum % 0x100));
+    
+        packet_data_command[5 + LEN] = DCS;   //DCS
+        packet_data_command[5 + LEN + 1] = 0x00;   //Postamble
+    
+        //レスポンスバッファをクリア
+        clearRecieveBuffer();
+    
+        //コマンドを送信
+        for(i = 0; i <= (5 + LEN + 1); i++){
+            _serial.putc(packet_data_command[i]);
+        }
+    
+        //powerdownの時はレスポンスが返ってこないので受信待機が無限ループに入ってしまう
+        //powerdown時はACKのみチェックする
+        //コマンドリファレンス39ページ『ただしACKは返します』
+        if(wired_packet_data[1] != wired_data_RFConfiguration_PowerDown[1]){
+            //レスポンス受信完了まで待機
+            waitWhileRead(5);
+        }else{
+            do{
+                wait_ms(1);
+            }while(recieveLEN <= sizeof(wired_complete_ACK));
+        }
+    
+        //メモリをfree
+        free(packet_data_command);
+    }
+
+
+    //ICカードのコマンドを、リーダライタのInDataExchangeを使ってICカードへ送信する関数
+    void RCS620S_AB::sendInDataExchange_and_RecieveRes(const uint8_t card_command[], uint16_t card_command_len){
+        
+        //card_command+リーダライタコマンド分のメモリを確保
+        uint8_t *packet_command;
+        packet_command = (uint8_t*)malloc(sizeof(uint8_t) * (card_command_len + 3));
+        
+        //無線コマンドの前にInDataExchange有線コマンド結合
+        packet_command[0] = 0xD4;   //コマンドコード
+        packet_command[1] = 0x40;   //サブコマンドコード
+        packet_command[2] = 0x01;   //Tg(InListPassiveTargetであらかじめ1枚に指定)
+        
+        for(int i = 0; i < card_command_len ; i++){
+            packet_command[i + 3] = card_command[i];
+        }
+    
+        //カードリーダへ送信
+        sendCommand_and_RecieveRes(packet_command, (card_command_len  + 3));
+        
+        //メモリをfree
+        free(packet_command);
+    }
+
+    
+    void RCS620S_AB::sendInListPasseveTarget_typeA(){
+        sendCommand_and_RecieveRes(wired_data_InListPassiveTarget_typeA,(uint16_t)sizeof(wired_data_InListPassiveTarget_typeA));
+    }
+    
+    void RCS620S_AB::sendInListPassiveTarget_typeB(){
+        sendCommand_and_RecieveRes(wired_data_InListPassiveTarget_typeB,(uint16_t)sizeof(wired_data_InListPassiveTarget_typeB));
+    }
+
+//private functioin
+
+/***************/
+/**** 制御系 ****/
+/***************/
+
+    void RCS620S_AB::initialize(){
+        //UART受信割り込み設定
+        _serial.attach(callback(this,&RCS620S_AB::serialRxIrq), Serial::RxIrq);
+        sendCommand_and_RecieveRes(wired_data_AdditionalTime24ms,(uint16_t)sizeof(wired_data_AdditionalTime24ms));
+    } 
+    
+/***************/
+/**** 受信系 ****/
+/***************/
+
+    //カードリーダ UART受信割込み
+    //※この関数のなかでデバッグ用printf使用不可(処理中に取りこぼす)
+    void RCS620S_AB::serialRxIrq(){
+        recieveBuffer[recieveLEN] = (uint8_t)_serial.getc(); //0
+        recieveLEN++; //1 LEN = 配列番号+1 になりOK
+        if(recieveLEN >= READ_BUF_SIZE){
+            exit(1);
+        }
+    }
+    
+    void RCS620S_AB::clearRecieveBuffer(){
+        //受信バッファカーソル位置を先頭に
+        recieveLEN = 0;
+        
+        //受信バッファをクリア
+        for(int i = 0; i < READ_BUF_SIZE; i++){
+            recieveBuffer[i] = 0x00;
+        }
+    }
+
+    //読み取り完了まで待機
+    //ACK受信後、一定時間経過しても受信文字数が増えなくなる(=RX割り込みがかからない=受信完了)まで待機
+    void RCS620S_AB::waitWhileRead(int cycleTime_ms){
+       
+        int cTime;
+        if(cycleTime_ms >= 1){
+            cTime = cycleTime_ms;
+        }else{
+            cTime = 1;
+        }
+        
+        //ackはmax3.5ms
+        int l;
+        do{
+            l = recieveLEN;   //現在の受信文字数
+            wait_ms(cTime);
+        }while(recieveLEN <= sizeof(wired_complete_ACK) || l < recieveLEN);//一定時間後の受信文字数と比較
+    }
+    
+    //受信バッファからrecieveBuffer[start] ~ recieveBuffer[end] を抜き出す
+    void RCS620S_AB::extractRes(int start, int end, uint8_t ansArray[], int *ansLen){
+        if(end > recieveLEN || start > end){
+            *ansLen = 0;
+        }else{
+            int j = 0;
+            for(int i = start; i <= end; i++){
+                ansArray[j] = recieveBuffer[i];
+                j++;
+            }
+            *ansLen = end - start + 1;
+        }
+    }
+
+/***************/
+/**** 検査系 ****/
+/***************/
+    
+    //頭についているACKが仕様書記載通りのデータになっているか確認
+    bool RCS620S_AB::checkACK(){
+        bool flag = true;
+        for(int i = 0; i<sizeof(wired_complete_ACK); i++){
+            if(wired_complete_ACK[i] != recieveBuffer[i]){
+                flag = false;
+            }
+        }
+        return flag;
+    }
+
+
+    bool RCS620S_AB::checkCardRes(){
+        //inListPassiveTargetの場合 D5 4B Tg [CardRes] DCS
+        //inDataExchangeの場合 D5 41 Status [CardRes] DCS
+    
+        //そもそも受信できてなければエラー
+        if(checkRxData_and_getLEN() < 1){
+            return false;
+        }
+    
+        //使う頻度が多いinDataExchangeを先に評価
+         if(recieveBuffer[12] == 0x41 && recieveBuffer[13] == 0x00){
+            //inListpassiveTargetレスポンス(0x41)ならばターゲットidが0x01かチェック
+            return true;
+        }else if(recieveBuffer[12] == 0x4B && recieveBuffer[13] == 0x01){
+            //inListpassiveTargetレスポンス(0x4B)ならばターゲットidが0x01かチェック
+            return true;
+        }else{
+            return false;
+        }
+    }
+    
+    
+    //受信データをチェックしてOKならLENを返す、異常なら0を返す
+    uint8_t RCS620S_AB::checkRxData_and_getLEN(){
+        
+        //頭にACKが付いているかチェック
+        if(!checkACK()){
+            return 0;
+        }   
+        
+        //LEN+LCSをチェックしてLENを取得
+        uint8_t data_len = 0;
+    
+        uint8_t recieved_LEN_check = (uint8_t)(0x00ff & (recieveBuffer[9]+recieveBuffer[10]));
+        if(recieved_LEN_check == 0x00 && recieveBuffer[9] > 0x00){
+            data_len = recieveBuffer[9];
+        }else{
+            //LEN受信エラー
+            return 0;
+        }
+        
+        //レスポンスコードをチェック
+        if(recieveBuffer[11] != 0xD5){
+            //レスポンスコードが 0xD5 でない
+            return 0;
+        }
+        
+        //DCSをチェック
+        uint32_t data_sum = 0x00000000;
+        for(int i = 11; i < 11 + data_len; i++){
+            data_sum = data_sum + recieveBuffer[i];
+        }
+        data_sum = 0x000000FF & data_sum;
+        //データ合計にDCSを足す
+        data_sum = data_sum + recieveBuffer[11 + data_len];
+        
+        if(data_sum == 0x100){
+            //LENを返す
+            return data_len;
+        }else{
+            //データ受信エラー
+            return 0;
+        }
+    }