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