M5stackでFeliCa リーダーを作った話


なぜ作ったか

弊社の私の所属部署では、座席抽選Webアプリ(自社ツール、というか、私のチーム謹製)を用いたフリーアドレスを実施しています。

定期券、社員証を「ぴっ」で抽選が出来たら面白いのではと思い、作ってみました。

つかっているもの

最初のプロトタイプ

電源(3V3とGNDと16,17をつなぐだけ)

最終形態

紆余曲折のあと、ダイソーの吸盤でモニタフレームに張り付きました。

ブロック図

ざっくり、こんな感じ。

M5Stack

開発にはArduinoを使用しました。

RC-S620S

Sony謹製のライブラリ が公開されています。
しかし、Serialが1で固定されているため、ライブラリを一部変更する必要があります。(Serialがとられると、デバッグも出来ないので)

RCS620S.cppの300行以降に4カ所あるSerialをSerial2に変更するだけです。

シリアルポートの指定

下のソースの通り Serial2.begin(SERIAL_BOUND, SERIAL_8N1, 16, 17);でRC-S620Sに繋がります。

Felicaの読み込み

Felicaカードは、ライブラリのサンプルで読み込むことが可能です。くせ者は、モバイルSuica(Apple)です。

通常、下ソースの「<<ここ」に「ワイルドカード:0xFFFF」をしているすると、カードタイプに応じた情報が読み取られます。

しかし、モバイルSuicaの場合、「SUICAのコード:0x0003」を指定しないと反応しません。
苦肉の策ですが(Pythonのライブラリを参考)モバイルSuicaと通常カードを交互に読むことで双方に対応させました。

felicaReader.ino
#include <RCS620S.h>

#define SERIAL_BOUND     115200
#define COMMAND_TIMEOUT  400
#define POLLING_INTERVAL 500
#define SD_PN            4

#define SYSCODE_SUICA 0x0003
#define SYSCODE_DEF   0xFFFF

#define SENSE_ITERATIONS 10
#define SENSE_INTERVAL   10


RCS620S rcs620s;

int iterations;
uint16_t targetSys; 

void setup() {
  // put your setup code here, to run once:
  int ret;

  Serial.begin(SERIAL_BOUND);
  Serial2.begin(SERIAL_BOUND, SERIAL_8N1, 16, 17);

  ret = rcs620s.initDevice();
  delay(10);
  Serial.print("Init RCS620s ");
  while(!ret) {
    delay(100);
    Serial.print(".");
  };
  Serial.println(".");
  Serial.println("Connect RCS620S");

  iterations = 0;
  targetSys = SYSCODE_SUICA;
}

void loop() {
  // put your main code here, to run repeatedly:
  int ret, i, interval;

  rcs620s.timeout = COMMAND_TIMEOUT;

  if(targetSys == SYSCODE_SUICA && iterations >= SENSE_ITERATIONS){
    targetSys = SYSCODE_DEF;
    interval = POLLING_INTERVAL;
    iterations = 0;
  }else{
    targetSys = SYSCODE_SUICA;
    interval = SENSE_INTERVAL;
    iterations++;
  }

  ret = rcs620s.polling(targetSys);  <<ここ

  if(ret) {
    Serial.print("--> find:");

    for(i = 0; i < 8; i++)
    {
      if(rcs620s.idm[i] / 0x10 == 0) Serial.print(0);
      Serial.print(rcs620s.idm[i], HEX);
    }
    Serial.println(".");
  }
  rcs620s.rfOff();
  delay(interval);
}

また、ソースの記載通りですが、FecliaのIDmを利用しています。正直よろしくないですが、

  • 勤怠ではなく、座席抽選であること
  • 既存のカード(定期券、社員証など)を幅広く使いたかった

などを言い訳に、よしとしています。

作ってみて

プロトタイプとFelica情報読み取り、自社アプリのAPIキックまでは結構簡単にできたのですが、

  • M5Stackの画面遷移
  • 連続運用
  • バージョンアップ(バグ対応ともいう)

と、通常のアプリ開発と同じところで時間がかかるものですね。(あたりまえですが)