SONY製のNFCカードリーダ RC-S620/S をイニシエータとして使用し、NFC Type-A/Bと通信するライブラリです。FeliCaとは通信できません。(This library can't communicate with FeliCa! Only for NFC Type-A/B.)
RCS620S_AB.cpp
- Committer:
- hmizuno
- Date:
- 2020-06-06
- Revision:
- 1:98c4a45b646a
- Parent:
- 0:16a4197a4dfb
- Child:
- 2:08ccf5062b69
File content as of revision 1:98c4a45b646a:
#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; } }