Quantcast
Channel: C#タグが付けられた新着記事 - Qiita
Viewing all articles
Browse latest Browse all 9318

RFID リーダを制御する Low Level Reader Protocol(LLRP) について

$
0
0

はじめに

LLRP は RFIDリーダのネットワークインターフェースを標準化したプロトコルです.
仕様や詳細については下記のリンクを参照してください.
LLRP Toolkit
LLRP仕様

タグのメモリ構造などは下記を参考にしてください
GS1 EPC/RFID標準
RFIDタグの構造について

似た例(大体, 同じ例)が Impinj Support にもあります.
Hello LLRP (Low-Level Reader Protocol)

環境

名称Version備考
言語C#5.0
ライブラリlibltknet-sdk10.34.0libltknet-sdk(LLRP)

タグIDの取得

リーダに対して読込命令を発行し, 周辺にある RFID の EPC を取得します.

リーダへの接続

下記のコードでは, IPv4 アドレス 192.168.100.64のリーダに対して 5084(LLRP)で接続を行います.
既に何かしらのプログラムが LLRP に接続している場合は, エラーが発生します.

暗号化された通信を使用する場合は, ポート番号を 5085, useTLS = trueに変更します.

ENUM_ConnectionAttemptStatusTypestatus;LLRPClientclient=newLLRPClient(5084);// レポートイベントの登録client.OnRoAccessReportReceived+=newdelegateRoAccessReport(_LLRPClientOnRoAccessReportReceived);boolisOpened=client.Open(/* llrpReaderName = */"192.168.100.64",/* timeout        = */3000,/* useTLS         = */false,/* out status     = */outstatus);ResetToFactoryDefault(client);StopROSpec(client,0);DisableROSpec(client,0);DeleteROSpec(client,0);AddROSpec(client,1234);EnableROSpec(client,1234);StartROSpec(client,1234);Console.ReadLine();StopROSpec(client,1234);DisableROSpec(client,1234);DeleteROSpec(client,1234);client.Close();

レポートイベント

privatestaticvoid_LLRPClientOnRoAccessReportReceived(MSG_RO_ACCESS_REPORTmsg){foreach(PARAM_TagReportDatadatainmsg.TagReportData){stringcrc=null,pc=null;stringepc=null;if(data.AirProtocolTagData.Count>0){// CRC, PCfor(inti=0;i<data.AirProtocolTagData.Count;++i){IParameterairProtocol=data.AirProtocolTagData[i];if(airProtocolisPARAM_C1G2_CRC){crc=string.Format("{0:X4}",(airProtocolasPARAM_C1G2_CRC).CRC);}elseif(airProtocolisPARAM_C1G2_PC){pc=string.Format("{0:X4}",(airProtocolasPARAM_C1G2_PC).PC_Bits);}}}// EPCIParameterpEpc=data.EPCParameter[0];if(pEpcisPARAM_EPC_96){epc=(pEpcasPARAM_EPC_96).EPC.ToHexString();}elseif(pEpcisPARAM_EPCData){epc=(pEpcasPARAM_EPCData).EPC.ToHexString();}Console.Error.WriteLine("CRC: {0}, PC: {1}\t{2} {3} {4} {5} {6} {7}-{8}",(crc!=null)?crc:"(none)",(pc!=null)?pc:"(none)",epc,data.ROSpecID.ROSpecID,data.AntennaID.AntennaID,data.PeakRSSI.PeakRSSI,data.TagSeenCount.TagCount,data.FirstSeenTimestampUTC.Microseconds,data.LastSeenTimestampUTC.Microseconds);}}

任意: リーダの初期化

publicstaticvoidResetToFactoryDefault(LLRPClientclient){MSG_SET_READER_CONFIGmsg=newMSG_SET_READER_CONFIG();MSG_ERROR_MESSAGEmsgErr=null;msg.ResetToFactoryDefault=true;MSG_SET_READER_CONFIG_RESPONSEmsgResp=client.SET_READER_CONFIG(/* msg        = */msg,/* out msgErr = */outmsgErr,/* timeout    = */3000);if(msgResp!=null){}elseif(msgErr!=null){Console.Error.WriteLine(msgErr.LLRPStatus.ErrorDescription);}else{// Timeout}}

Reader Operation (ROSpec) の追加

Impinj 社製のリーダは 1つの ROSpec に対応していますが, リーダによっては複数の ROSpec を追加できるかもしれません.(そのようなリーダに対応したことがないため)
そのため, ROSpec を追加する前に ROSpec を削除をすることをおすすめします. 削除方法については後述します.

ROSpec スタートトリガ

ROSpec の開始方法として下記の種類があります.

  • GPI
    リーダが GPIO を備えている場合, 対象のポートが ON または OFF (電圧の印加もしくは 0[V] に接地)した際に ROSpec を開始させます.
  • Immediate
    ROSpec を有効化した時に, ROSpec を開始します.
  • Null
    ROSpec を明示的に開始する必要があります.
  • Periodic
    指定した秒数後に ROSpec を開始します. LLRP の使用を見る限りでは, 開始時間を設定することができるようです.(未検証)

ROSpec 停止トリガ

  • Duration
    ROSpec が開始した後, 指定した秒数後に ROSpec を停止します.
  • GPI_With_Timeout
    GPIO の対象のポートが ON または OFF した際に, ROSpec を停止します. Timeout で秒数も指定することが可能です.
  • Null
    ROSpec を明示的に停止する必要があります.

ROReport Spec

リーダから発行するレポート(ROSpec のみの場合は, 検出したタグの情報)を設定します.
レポートを発行する方法として,

  • Upon_N_Tags_Or_End_Of_AISpec
    N 個のタグを検出もしくは AISpec の終了
  • Upon_N_Tags_Or_End_Of_ROSpec
    N 個のタグの検出もしくは, ROSpec の終了

の 2つのどちらかを指定することができます.
タグの個数 N は 0 を指定すると, タグの個数についての終了条件が無視されることになります. そのため, ROSpec もしくは AISpec が終了した際にレポートの発行されることになります.

publicstaticvoidAddROSpec(LLRPClientclient,uintroSpecID){PARAM_ROSpecroSpec=newPARAM_ROSpec();roSpec.CurrentState=ENUM_ROSpecState.Disabled;roSpec.Priority=0;// ROSpec の削除, 有効化, 無効化, 開始, 停止で同じ ROSpec ID を使用します.roSpec.ROSpecID=1234;roSpec.SpecParameter=newUNION_SpecParameter();// Boundary SpecPARAM_ROBoundarySpecboundarySpec=newPARAM_ROBoundarySpec();roSpec.ROBoundarySpec=boundarySpec;// Start triggerPARAM_ROSpecStartTriggerstartTrigger=newPARAM_ROSpecStartTrigger();boundarySpec.ROSpecStartTrigger=startTrigger;startTrigger.ROSpecStartTriggerType=ENUM_ROSpecStartTriggerType.Null;// Stop TriggerPARAM_ROSpecStopTriggerstopTrigger=newPARAM_ROSpecStopTrigger();boundarySpec.ROSpecStopTrigger=stopTrigger;stopTrigger.ROSpecStopTriggerType=ENUM_ROSpecStopTriggerType.Null;// Report specPARAM_ROReportSpecreportSpec=newPARAM_ROReportSpec();roSpec.ROReportSpec=reportSpec;// N個のタグを検出もしくは ROSpec の終了を条件にしてタグレポートを発行させる.// 0 にしているため, この場合では ROSpec の終了のみを条件としている.reportSpec.N=0;reportSpec.ROReportTrigger=ENUM_ROReportTriggerType.Upon_N_Tags_Or_End_Of_ROSpec;// Tag report content selectorPARAM_TagReportContentSelectortagReportContentSelector=newPARAM_TagReportContentSelector();reportSpec.TagReportContentSelector=tagReportContentSelector;// EPC 領域の先頭 2[word] CRC + PCBits の取得tagReportContentSelector.AirProtocolEPCMemorySelector=newUNION_AirProtocolEPCMemorySelector();tagReportContentSelector.AirProtocolEPCMemorySelector.Add(newPARAM_C1G2EPCMemorySelector(){EnableCRC=true,EnablePCBits=true});// タグ受信時のレポートに// アンテナID, 周波数ID, [初-末]検出時刻, 受信感度, ROSpecID, タグ検出回数// を含めるtagReportContentSelector.EnableAntennaID=true;tagReportContentSelector.EnableChannelIndex=true;tagReportContentSelector.EnableFirstSeenTimestamp=true;tagReportContentSelector.EnableLastSeenTimestamp=true;tagReportContentSelector.EnablePeakRSSI=true;tagReportContentSelector.EnableROSpecID=true;tagReportContentSelector.EnableTagSeenCount=true;// Antenna Inventory specPARAM_AISpecaiSpec=newPARAM_AISpec();roSpec.SpecParameter.Add(aiSpec);// AISpec stop triggerPARAM_AISpecStopTriggeraiSpecStopTrigger=newPARAM_AISpecStopTrigger();aiSpec.AISpecStopTrigger=aiSpecStopTrigger;aiSpecStopTrigger.AISpecStopTriggerType=ENUM_AISpecStopTriggerType.Null;// 使用するアンテナを指定aiSpec.AntennaIDs=newUInt16Array();// 0 を指定するとリーダが対応しているアンテナすべてを有効化できます.//aiSpec.AntennaIDs.Add(0);aiSpec.AntennaIDs.Add(1);aiSpec.AntennaIDs.Add(2);aiSpec.AntennaIDs.Add(3);aiSpec.AntennaIDs.Add(4);aiSpec.InventoryParameterSpec=newPARAM_InventoryParameterSpec[1];// Inventory parameter specPARAM_InventoryParameterSpecinventoryParameterSpec=newPARAM_InventoryParameterSpec();aiSpec.InventoryParameterSpec[0]=inventoryParameterSpec;inventoryParameterSpec.ProtocolID=ENUM_AirProtocols.EPCGlobalClass1Gen2;inventoryParameterSpec.InventoryParameterSpecID=1235;inventoryParameterSpec.AntennaConfiguration=newPARAM_AntennaConfiguration[4];// アンテナ設定for(ushorti=0;i<4;++i){PARAM_AntennaConfigurationantennaConfig=newPARAM_AntennaConfiguration();inventoryParameterSpec.AntennaConfiguration[i]=antennaConfig;antennaConfig.AntennaID=(ushort)(i+1);// RFReceiverPARAM_RFReceiverrfReceiver=newPARAM_RFReceiver();antennaConfig.RFReceiver=rfReceiver;// 受信感度 -80.00[dBm]rfReceiver.ReceiverSensitivity=1;// RFTransmitterPARAM_RFTransmitterrfTransmitter=newPARAM_RFTransmitter();antennaConfig.RFTransmitter=rfTransmitter;rfTransmitter.ChannelIndex=1;rfTransmitter.HopTableID=0;// 出力電力 30.00[dBm]rfTransmitter.TransmitPower=81;}MSG_ADD_ROSPECmsg=newMSG_ADD_ROSPEC();msg.ROSpec=roSpec;MSG_ERROR_MESSAGEmsgErr=null;MSG_ADD_ROSPEC_RESPONSEmsgResp=client.ADD_ROSPEC(/* msg        = */msg,/* out msgErr = */outmsgErr,/* timeout    = */3000);if(msgResp!=null){// Success}elseif(msgErr!=null){Console.Error.WriteLine(msgErr.LLRPStatus.ErrorDescription);}else{// Timeout}}

ROSpec の削除

publicstaticvoidDeleteROSpec(LLRPClientclient,uintroSpecID){MSG_DELETE_ROSPECmsg=newMSG_DELETE_ROSPEC();msg.ROSpecID=roSpecID;MSG_ERROR_MESSAGEmsgErr=null;MSG_DELETE_ROSPEC_RESPONSEmsgResp=client.DELETE_ROSPEC(/* msg        = */msg,/* out msgErr = */outmsgErr,/* timeout    = */3000);if(msgResp!=null){// Success}elseif(msgErr!=null){Console.Error.WriteLine(msgErr.LLRPStatus.ErrorDescription);}else{// Timeout}}

ROSpec の有効化

publicstaticvoidEnableROSpec(LLRPClientclient,uintroSpecID){MSG_ENABLE_ROSPECmsg=newMSG_ENABLE_ROSPEC();msg.ROSpecID=roSpecID;MSG_ERROR_MESSAGEmsgErr=null;MSG_ENABLE_ROSPEC_RESPONSEmsgResp=client.ENABLE_ROSPEC(/* msg        = */msg,/* out msgErr = */outmsgErr,/* timeout    = */3000);if(msgResp!=null){// Success}elseif(msgErr!=null){Console.Error.WriteLine(msgErr.LLRPStatus.ErrorDescription);}else{// Timeout}}

ROSpec の無効化

publicstaticvoidDisableROSpec(LLRPClientclient,uintroSpecID){MSG_DISABLE_ROSPECmsg=newMSG_DISABLE_ROSPEC();msg.ROSpecID=roSpecID;MSG_ERROR_MESSAGEmsgErr=null;MSG_DISABLE_ROSPEC_RESPONSEmsgResp=client.DISABLE_ROSPEC(/* msg        = */msg,/* out msgErr = */outmsgErr,/* timeout    = */3000);if(msgResp!=null){// Success}elseif(msgErr!=null){Console.Error.WriteLine(msgErr.LLRPStatus.ErrorDescription);}else{// Timeout}}

ROSpec の開始

publicstaticvoidStartROSpec(LLRPClientclient,uintroSpecID){MSG_START_ROSPECmsg=newMSG_START_ROSPEC();msg.ROSpecID=roSpecID;MSG_ERROR_MESSAGEmsgErr=null;MSG_START_ROSPEC_RESPONSEmsgResp=client.START_ROSPEC(/* msg        = */msg,/* out msgErr = */outmsgErr,/* timeout    = */3000);if(msgResp!=null){// Success}elseif(msgErr!=null){Console.Error.WriteLine(msgErr.LLRPStatus.ErrorDescription);}else{// Timeout}}

ROSpec の停止

publicstaticvoidStopROSpec(LLRPClientclient,uintroSpecID){MSG_STOP_ROSPECmsg=newMSG_STOP_ROSPEC();msg.ROSpecID=roSpecID;MSG_ERROR_MESSAGEmsgErr=null;MSG_STOP_ROSPEC_RESPONSEmsgResp=client.STOP_ROSPEC(/* msg        = */msg,/* out msgErr = */outmsgErr,/* timeout    = */3000);if(msgResp!=null){// Success}elseif(msgErr!=null){Console.Error.WriteLine(msgErr.LLRPStatus.ErrorDescription);}else{// Timeout}}

リーダの切断

LLRP.Close内で MSG_CLOSE_CONNECTIONを使用して切断処理を行っています.

client.Close();

実行結果

上述した設定に対応したリーダであれば, 下図のような結果になると思います.
この結果の例の FirstSeenTimestampUTCLastSeenTimestampUTCで取得された値は, Unix時間となっているため, そのままの値を DateTime に渡すと正しくない時間が取得されてしまいます.

result.png

小言

リーダによって対応するメッセージやパラメータが相違している場合があり,
例えば Impinj 社製のリーダを制御するプログラムを作成しても他社のリーダを動作させられないことがあります.

サンプル例としたコード中にコメントにて // Successの場所がありますが, リーダによっては msgResp内の LLRPStatusにエラーメッセージおよびステータスコートが含まれている可能性があります.
その場合, msgErrは常に nullになります.(ほんと, やめてほしい)


Viewing all articles
Browse latest Browse all 9318

Latest Images

Trending Articles