Qiita Teams that are logged in
You are not logged in to any team

Log in to Qiita Team
Community
OrganizationAdvent CalendarQiitadon (β)
Service
Qiita JobsQiita ZineQiita Blog
Help us understand the problem. What is going on with this article?

iOS External Accessories: iMag Pro IIで磁気カードを読む

More than 5 years have passed since last update.

iMag Pro II 入手

  • ID Tech Japanさんにメールで連絡しました
  • 見積書を作ってもらって発注しました
  • SDKのCDを焼いてもらえて、一緒に納品されます。
  • iMag.hとlibiMagSDK.a がお目当てになります。

プロジェクト作成

  • 空ののソリューションつくります

image

バインディングライブラリ作成(IdTechBind)

  • Binding Libaryを作成

image

Peeko:CardScanSample hide$ tree .
.
├── CardScanSample.sln
└── IdTechBind
    ├── ApiDefinition.cs
    ├── IdTechBind.csproj
    ├── Resources
    └── StructsAndEnums.cs

2 directories, 4 files

libMagSDK.linkwith.cs 作成

  • libiMagSDK.a をプロジェクトルートにドラッグ&ドロップ

image

image

Peeko:CardScanSample hide$ tree .
.
├── CardScanSample.sln
└── IdTechBind
    ├── ApiDefinition.cs
    ├── IdTechBind.csproj
    ├── Resources
    ├── StructsAndEnums.cs
    ├── bin
    │   └── Debug
    ├── libiMagSDK.a
    ├── libiMagSDK.linkwith.cs
    └── obj
        └── Debug

6 directories, 6 files

ApiDefinition.cs 作成

image

image

image

image

  • 実行エラー(Xcode6になってXamarimも更新したら出るようになった.... XCode5の時はでなかったのに....)

image

In file included from /Users/hide/Documents/80097802-006_iMag_SDK_2.7_A/SDK/iMag.h:10:
In file included from /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS.sdk/System/Library/Frameworks/UIKit.framework/Headers/UIKit.h:9:
In file included from /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS.sdk/System/Library/Frameworks/UIKit.framework/Headers/UIAccelerometer.h:8:
In file included from /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS.sdk/System/Library/Frameworks/Foundation.framework/Headers/Foundation.h:10:
In file included from /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS.sdk/System/Library/Frameworks/Foundation.framework/Headers/NSArray.h:7:
In file included from /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS.sdk/System/Library/Frameworks/Foundation.framework/Headers/NSRange.h:5:
/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS.sdk/System/Library/Frameworks/Foundation.framework/Headers/NSValue.h:12:1: error: 'objc_returns_inner_pointer' attribute only applies to methods
@property (readonly) const char *objCType NS_RETURNS_INNER_POINTER;
^                                         ~~~~~~~~~~~~~~~~~~~~~~~~
In file included from /Users/hide/Documents/80097802-006_iMag_SDK_2.7_A/SDK/iMag.h:10:
In file included from /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS.sdk/System/Library/Frameworks/UIKit.framework/Headers/UIKit.h:9:
In file included from /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS.sdk/System/Library/Frameworks/UIKit.framework/Headers/UIAccelerometer.h:8:
In file included from /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS.sdk/System/Library/Frameworks/Foundation.framework/Headers/Foundation.h:15:
In file included from /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS.sdk/System/Library/Frameworks/Foundation.framework/Headers/NSCharacterSet.h:8:
/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS.sdk/System/Library/Frameworks/Foundation.framework/Headers/NSString.h:248:1: error: 'objc_returns_inner_pointer' attribute only applies to methods
@property (readonly) __strong const char *UTF8String NS_RETURNS_INNER_POINTER;  // Convenience to return null-terminated UTF8 representation
^                                                    ~~~~~~~~~~~~~~~~~~~~~~~~
In file included from /Users/hide/Documents/80097802-006_iMag_SDK_2.7_A/SDK/iMag.h:10:
In file included from /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS.sdk/System/Library/Frameworks/UIKit.framework/Headers/UIKit.h:9:
In file included from /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS.sdk/System/Library/Frameworks/UIKit.framework/Headers/UIAccelerometer.h:8:
In file included from /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS.sdk/System/Library/Frameworks/Foundation.framework/Headers/Foundation.h:17:
/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS.sdk/System/Library/Frameworks/Foundation.framework/Headers/NSData.h:76:1: error: 'objc_returns_inner_pointer' attribute only applies to methods
@property (readonly) const void *bytes NS_RETURNS_INNER_POINTER;
^                                      ~~~~~~~~~~~~~~~~~~~~~~~~
/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS.sdk/System/Library/Frameworks/Foundation.framework/Headers/NSData.h:161:1: error: 'objc_returns_inner_pointer' attribute only applies to methods
@property (readonly) void *mutableBytes NS_RETURNS_INNER_POINTER;
^                                       ~~~~~~~~~~~~~~~~~~~~~~~~
In file included from /Users/hide/Documents/80097802-006_iMag_SDK_2.7_A/SDK/iMag.h:10:
In file included from /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS.sdk/System/Library/Frameworks/UIKit.framework/Headers/UIKit.h:9:
In file included from /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS.sdk/System/Library/Frameworks/UIKit.framework/Headers/UIAccelerometer.h:8:
In file included from /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS.sdk/System/Library/Frameworks/Foundation.framework/Headers/Foundation.h:25:
/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS.sdk/System/Library/Frameworks/Foundation.framework/Headers/NSDecimalNumber.h:101:1: error: 'objc_returns_inner_pointer' attribute only applies to methods
@property (readonly) const char *objCType NS_RETURNS_INNER_POINTER;
^                                         ~~~~~~~~~~~~~~~~~~~~~~~~
In file included from /Users/hide/Documents/80097802-006_iMag_SDK_2.7_A/SDK/iMag.h:10:
In file included from /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS.sdk/System/Library/Frameworks/UIKit.framework/Headers/UIKit.h:9:
In file included from /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS.sdk/System/Library/Frameworks/UIKit.framework/Headers/UIAccelerometer.h:8:
In file included from /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS.sdk/System/Library/Frameworks/Foundation.framework/Headers/Foundation.h:31:
In file included from /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS.sdk/System/Library/Frameworks/Foundation.framework/Headers/NSFileManager.h:8:
/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS.sdk/System/Library/Frameworks/Foundation.framework/Headers/NSPathUtilities.h:34:1: error: 'objc_returns_inner_pointer' attribute only applies to methods
@property (readonly) __strong const char *fileSystemRepresentation NS_RETURNS_INNER_POINTER;
^                                                                  ~~~~~~~~~~~~~~~~~~~~~~~~
In file included from /Users/hide/Documents/80097802-006_iMag_SDK_2.7_A/SDK/iMag.h:10:
In file included from /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS.sdk/System/Library/Frameworks/UIKit.framework/Headers/UIKit.h:9:
In file included from /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS.sdk/System/Library/Frameworks/UIKit.framework/Headers/UIAccelerometer.h:8:
In file included from /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS.sdk/System/Library/Frameworks/Foundation.framework/Headers/Foundation.h:41:
/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS.sdk/System/Library/Frameworks/Foundation.framework/Headers/NSKeyValueObserving.h:183:1: error: 'objc_returns_inner_pointer' attribute only applies to methods
@property void *observationInfo NS_RETURNS_INNER_POINTER;
^                               ~~~~~~~~~~~~~~~~~~~~~~~~
In file included from /Users/hide/Documents/80097802-006_iMag_SDK_2.7_A/SDK/iMag.h:10:
In file included from /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS.sdk/System/Library/Frameworks/UIKit.framework/Headers/UIKit.h:9:
In file included from /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS.sdk/System/Library/Frameworks/UIKit.framework/Headers/UIAccelerometer.h:8:
In file included from /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS.sdk/System/Library/Frameworks/Foundation.framework/Headers/Foundation.h:46:
/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS.sdk/System/Library/Frameworks/Foundation.framework/Headers/NSMethodSignature.h:22:1: error: 'objc_returns_inner_pointer' attribute only applies to methods
@property (readonly) const char *methodReturnType NS_RETURNS_INNER_POINTER;
^                                                 ~~~~~~~~~~~~~~~~~~~~~~~~
In file included from /Users/hide/Documents/80097802-006_iMag_SDK_2.7_A/SDK/iMag.h:10:
In file included from /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS.sdk/System/Library/Frameworks/UIKit.framework/Headers/UIKit.h:9:
In file included from /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS.sdk/System/Library/Frameworks/UIKit.framework/Headers/UIAccelerometer.h:8:
In file included from /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS.sdk/System/Library/Frameworks/Foundation.framework/Headers/Foundation.h:74:
/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS.sdk/System/Library/Frameworks/Foundation.framework/Headers/NSURL.h:86:1: error: 'objc_returns_inner_pointer' attribute only applies to methods
@property (readonly) __strong const char *fileSystemRepresentation NS_RETURNS_INNER_POINTER NS_AVAILABLE(10_9, 7_0);
^                                                                  ~~~~~~~~~~~~~~~~~~~~~~~~
9 errors generated.
Error while processing /Users/hide/Documents/80097802-006_iMag_SDK_2.7_A/SDK/iMag.h.
sharpie-clang-parser exited with error code: 1
System.Exception: sharpie-clang-parser exited with error code: 1
  at Sharpie.ObjC.Parser.Parse (System.IO.TextWriter sexpWriter, System.Collections.Generic.List`1 stderrLines) [0x00000] in <filename unknown>:0 
  at Sharpie.Mac.MainWindowController+<GenerateBinding>c__AnonStorey3.<>m__B (System.Object o) [0x00000] in <filename unknown>:0 

  • 報告されている. Object Sharpieのパーサー古いってよ!
  • Xcode5だと以下の用に解析される
using System;

using MonoTouch.Foundation;

namespace IdTechBind {

    [BaseType (typeof (NSObject))]
    public partial interface IMag : EAAccessoryDelegate, NSStreamDelegate {

        [Export ("init")]
        IntPtr Constructor ();

        [Export ("iMagConnected")]
        bool IMagConnected { get; }

        [Export ("session")]
        EASession Session { get; set; }

        [Export ("SendCMD:")]
        NSData SendCMD (NSData writeBuf);

        [Export ("SendCMDGetVersion"), Verify ("ObjC method massaged into getter property", "/Users/hide/Documents/80097802-006_iMag_SDK_2.7_A/SDK/iMag2.h", Line = 29)]
        NSData SendCMDGetVersion { get; }

        [Export ("SendCMDGetSerialNumber"), Verify ("ObjC method massaged into getter property", "/Users/hide/Documents/80097802-006_iMag_SDK_2.7_A/SDK/iMag2.h", Line = 30)]
        NSData SendCMDGetSerialNumber { get; }

        [Static, Export ("enableLogging:")]
        void EnableLogging (bool enable);
    }
}
  • このファイルを元にAppDefinition.cs を作るのですが、以下のように修正
using System;
using System.Drawing;

using MonoTouch.ObjCRuntime;
using MonoTouch.Foundation;
using MonoTouch.UIKit;

using MonoTouch.ExternalAccessory;


namespace IdTechBind
{

    [BaseType (typeof (NSObject))]
    public partial interface iMag       // Must be "iMag" as same as in *.h file. NOT IMag...   {
        [Export ("session")]
        EASession Session { get; set; }

        [Export ("iMagConnected")]
        bool IMagConnected { get; }

        [Export ("SendCMD:")]
        NSData SendCMD (NSData writeBuf);

        [Export ("SendCMDGetVersion")]
        NSData SendCMDGetVersion();

        [Export ("SendCMDGetSerialNumber")]
        NSData SendCMDGetSerialNumber();

        [Static, Export ("enableLogging:")]
        void EnableLogging (bool enable);

    }
}
  • IMagと生成されますが、iMagにすること。 Objective-Cの名前に合わせないと new できないっぽい。
  • EAAccessoryDelegate, NSStreamDelegate は無視してよいです。これは、 EAAccessory, NSStreameのプロトコルを実装しろということで、コンクリートクラスでなんかすればいいのではないでしょうか。
  • EAAccessoryDelegate,NSStreamDelegateともにXamarinではabstractクラスで定義されているので、C#的には多重継承できないので、やるにしても別名でプロトコル用のinterfaceを定義するなど必要です。

リンクオプション(libiMagSDK.linkwith.cs)

  • 自動生成されるlibiMagSDK.linkwith.csを編集
  • デバイスにアクセスするので、ExternalAccessory は必須
using System;
using MonoTouch.ObjCRuntime;

// ArmV7s : iPhone5
[assembly: LinkWith (
        "libiMagSDK.a", 
        LinkTarget.ArmV6 | LinkTarget.ArmV7 | LinkTarget.ArmV7s | LinkTarget.Simulator,
        Frameworks = "ExternalAccessory UIKit Foundation CoreGraphics",
        ForceLoad = true)]

ビルド

  • バインディングライブラリをビルドすると中間ファイルなどが自動生成されて、ターゲットコードにトランスレートされたC#プログラム Objective-C ライブラリがリンクされる。
Peeko:CardScanSample hide$ tree IdTechBind/obj/
IdTechBind/obj/
└── Debug
    ├── IdTechBind.csproj.FilesWrittenAbsolute.txt
    ├── IdTechBind.dll
    ├── IdTechBind.dll.mdb
    ├── MonoTouch,Version=v1.0.AssemblyAttribute.cs
    └── ios
        ├── IdTechBind.IdTechBind
        │   └── iMag.g.cs
        ├── ObjCRuntime
        │   └── Messaging.g.cs
        ├── sources.list
        ├── temp.dll
        └── temp.dll.mdb

4 directories, 9 files

中間ライブラリを作成(IdTechCardReader)

準備

  • Libraryプロジェクトを作成
  • MyClassをCardReaderにリファクタリング
  • IdTechBindを参照

CardReaderを実装

using System;
using System.Drawing;
using System.Collections.Generic;

using MonoTouch.Foundation;
using MonoTouch.UIKit;
using MonoTouch.ExternalAccessory;
using System.Threading.Tasks;
using System.CodeDom.Compiler;

namespace IdTechCardReader
{
    public class CardReader 
    {
        // カードリーダーからの通知をエベントで返す
        public delegate void ConnectedEvent(NSNotification notification);
        public delegate void DisconnectedEvent(NSNotification notification);
        public delegate void ScannedEvent(NSNotification notification);

        public event ConnectedEvent Connected;  
        public event DisconnectedEvent Disconnected;
        public event ScannedEvent Scanned;

        // 通知センター用のオブザーバー
        List<NSObject> _observers ;

        public CardReader ()
        {
            // 通知センターでデバイスから通知がきたらC#イベントでアプリにコールバックする
            _observers = new List<NSObject>(){
                NSNotificationCenter.DefaultCenter.AddObserver(
                    "iMagDidConnectNotification",
                    delegate(NSNotification notification) {
                        this.Connected(notification);
                    }),
                NSNotificationCenter.DefaultCenter.AddObserver(
                    "iMagDidDisconnectNotification",
                    delegate (NSNotification notification){
                        this.Disconnected(notification);
                    }),

                NSNotificationCenter.DefaultCenter.AddObserver(
                    "iMagDidReceiveDataNotification",
                    delegate(NSNotification notfication) {
                        this.Scanned(notfication);
                    }
                )
            };
        }

        // ID Tech iMag II カードリーダー
        IdTechBind.iMag _mag =null;

        // 終了処理
        public void Dispose()
        {
            NSNotificationCenter.DefaultCenter.RemoveObservers (_observers);
        }

        // カードリーダーを利用できるようにする
        public void Connect()
        {
            if (_mag == null) {
                // コンストラクタでイニシャライズまで行われる
                _mag = new IdTechBind.iMag ();             
                IdTechBind.iMag.EnableLogging (true);
            }
        }
    }
}

iOSアプリ作成(Shopper)

Single Viewアプリで作成

  • 作成

image

Info.plistで通知センターを受け取るようにする

  • 「ソース」で編集する
  • com.idtechproducts.reader を Supported external accessory protocolsで指定

image

IdTechCardReaderから C#のイベント受け取る

  • メインのビューコントローラで、StartCardReaderをコールしたら(ボタンとかViewDidLoadとかで)イベントを受け取って処理できるようにする
        IdTechCardReader.CardReader _magpro = null;

        void StartCardReader()
        {
            _magpro = new IdTechCardReader.CardReader();

            // リーダーが接続された
            _magpro.Connected += async(notification) => {
                //TODO: Card Reader Status
                await MessageBox ("Connected", notification.Description);
            };

            // リーダが取り外された
            _magpro.Disconnected +=async (notification) => {
                await MessageBox ("DisConnected", notification.Description);
            };

            // スキャンが発生

            _magpro.Scanned += async(notification) => {

                // バイト列をパースします
                var data = _magpro.GetScannedData(notification);

                if( this.CardType.SelectedSegment == 0 ){
                    // クレジットカード: ISOとかの規格でフォーマット決まってる
                    await MessageBox ("Credit:",
                        (new IdTechCardReader.PlainCreditCard(data)).ToString());
                }
                if( this.CardType.SelectedSegment == 1 ){
                    // T-POINTカードは規格とは違う
                    await MessageBox ("T-CARD:",
                        (new IdTechCardReader.TCard(data)).ToString());
                }
                if( this.CardType.SelectedSegment == 2 ){
                    // どこのかわからん
                    await MessageBox ("Other:",
                        (new IdTechCardReader.Data(data)).ToString());
                }
            };

            // 開始
            _magpro.Connect();
        }

iMag Pro II

  • 情報少なめ
  • 暗号化はDUKPTでセッションごとに派生キーを発生させてそれで読み取りデータを暗号化する模様
  • 永続キーは購入する時に設定してもらうのかも
  • 設定コマンドを実行してみたが、常にNAK(0x15)が返るので、何も出来ないかあるいは何か実装がまちがえているのかも
hidelafoglia
コンピュータプログラミング勉強中です。
https://github.com/hdknr/note
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away