ACS Audio Jack iOS Library  1.0.0
ACS Audio Jack iOS Library Documentation


Introduction

This library provides classes and protocols for communicating with ACS audio jack readers on iOS 5.0 or above.

Your application should include a header file AudioJack.h in order to use the classes and protocols provided by the library.

//
// MyViewController.h
//
#import <UIKit/UIKit.h>
...
@interface MyViewController : UIViewController <ACRAudioJackReaderDelegate>
...
@end

To use ACRAudioJackReader class, you should assign a delegate to your reader. Your delegate object is responsibe for receiving the data from the reader and should conform to the ACRAudioJackReaderDelegate protocol.

//
// MyViewController.m
//
#import "MyViewController.h"
...
@implementation MyViewController {
...
...
}
...
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
...
// Initialize ACRAudioJackReader object.
_reader = [[ACRAudioJackReader alloc] init];
[_reader setDelegate:self];
...
}
...

Resetting the reader

The sleep mode of reader is enabled by default. To use the reader, your application should call reset (ACRAudioJackReader) method. If your delegate object implements ACRAudioJackReaderDelegate::readerDidReset: method, it will receive a notification after the operation is completed.

...
// Reset the reader.
[_reader reset];
...
#pragma mark - Audio Jack Reader
...
- (void)readerDidReset:(ACRAudioJackReader *)reader {
// TODO: Add code here to process the notification.
...
}
...

Controlling the sleep mode

You can enable the sleep mode by calling sleep (ACRAudioJackReader) method. If your delegate object implements ACRAudioJackReaderDelegate::reader:didNotifyResult: method, it will receive a notification after the operation is completed.

...
// Enable the sleep mode.
[_reader sleep];
...
#pragma mark - Audio Jack Reader
...
- (void)reader:(ACRAudioJackReader *)reader didNotifyResult:(ACRResult *)result {
// TODO: Add code here to process the notification.
...
}
...

Setting the sleep timeout

You can set the sleep timeout by calling ACRAudioJackReader::setSleepTimeout method. If your delegate object implements ACRAudioJackReaderDelegate::reader:didNotifyResult: method, it will receive a notification after the operation is completed.

...
// Set the sleep timeout to 10 seconds.
[_reader setSleepTimeout:10];
...
#pragma mark - Audio Jack Reader
...
- (void)reader:(ACRAudioJackReader *)reader didNotifyResult:(ACRResult *)result {
// TODO: Add code here to process the notification.
...
}
...

Getting the firmware version

To get the firmware version, your application should call getFirmwareVersion (ACRAudioJackReader) method. Your delegate object should implement ACRAudioJackReaderDelegate::reader:didSendFirmwareVersion: method in order to receive the firmware version.

...
// Get the firmware version.
[_reader getFirmwareVersion];
...
#pragma mark - Audio Jack Reader
...
- (void)reader:(ACRAudioJackReader *)reader
didSendFirmwareVersion:(NSString *)firmwareVersion {
// TODO: Add code here to process the firmware version.
...
}
...

Getting the status

To get the status, your application should call getStatus (ACRAudioJackReader) method. Your delegate object should implement ACRAudioJackReaderDelegate::reader:didSendStatus: method in order to receive the status.

...
// Get the status.
[_reader getStatus];
...
#pragma mark - Audio Jack Reader
...
- (void)reader:(ACRAudioJackReader *)reader didSendStatus:(ACRStatus *)status {
// TODO: Add code here to process the status.
...
}
...

Receiving the track data

When you swipe a card, the reader notifies a track data and sends it through an audio channel to your iOS device. To receive the notification and the track data, your delegate object should implement ACRAudioJackReaderDelegate::readerDidNotifyTrackData: and ACRAudioJackReaderDelegate::reader:didSendTrackData: method. You can check the track error using ACRTrackData::track1ErrorCode and ACRTrackData::track2ErrorCode properties. Note that the received ACRTrackData object will be the instance of ACRAesTrackData or ACRDukptTrackData according to the settings. You must check the type of instance before accessing the object.

You can get the track data using ACRAesTrackData::trackData, ACRDukptTrackData::track1Data and ACRDukptTrackData::track2Data properties. Note that the track data of ACRAesTrackData object is encrypted by AES while the track data of ACRDukptTrackData object is encrypted by Triple DES. You must decrypt it before accessing the original track data.

After decrypting the track data of ACRAesTrackData object, you can use initWithBytes:length: (ACRTrack1Data) and initWithBytes:length: (ACRTrack2Data) methods to decode the track data into fields. For the track data or masked track data of ACRDukptTrackData object, you can use initWithString: (ACRTrack1Data) and initWithString: (ACRTrack2Data) methods.

...
#pragma mark - Audio Jack Reader
...
- (void)readerDidNotifyTrackData:(ACRAudioJackReader *)reader {
// TODO: Add your code here to process the notification.
...
}
...
- (void)reader:(ACRAudioJackReader *)reader
didSendTrackData:(ACRTrackData *)trackData {
// TODO: Add code here to process the track data.
if ((trackData.track1ErrorCode != ACRTrackErrorSuccess) ||
(trackData.track2ErrorCode != ACRTrackErrorSuccess)) {
// Show the track error.
...
return;
}
if ([trackData isKindOfClass:[ACRAesTrackData class]]) {
ACRAesTrackData *aesTrackData = (ACRAesTrackData *) trackData;
...
} else if ([trackData isKindOfClass:[ACRDukptTrackData class]]) {
ACRDukptTrackData *dukptTrackData = (ACRDukptTrackData *) trackData;
...
}
...
}
...

Receiving the raw data

If you want to access a raw data of a response, your delegate object should implement ACRAudioJackReaderDelegate::reader:didSendRawData:length: method. Note that the raw data is not verified by CRC16 checksum and you can call verifyData:length: (ACRAudioJackReader) method to verify it.

...
#pragma mark - Audio Jack Reader
...
- (void)reader:(ACRAudioJackReader *)reader
didSendRawData:(const uint8_t *)rawData length:(NSUInteger)length {
// TODO: Add code here to process the raw data.
...
}
...

Working with the ICC

If your reader came with the ICC interface, you can operate the card using the following methods:

Before transmitting the APDU, you need to reset the card using powerCardWithAction:slotNum:timeout:error: (ACRAudioJackReader) method. The ATR string will be returned if the card is operated normally. Otherwise, it will return the error code.

After resetting the card, the card state is changed to ACRCardNegotiable or ACRCardSpecific. You cannot transmit the APDU if the card state is not equal to ACRCardSpecific. To select the protocol, invoke setProtocol:slotNum:timeout:error: (ACRAudioJackReader) method with the preferred protocols.

After selecting the protocol, you can transmit the command APDU using transmitApdu:slotNum:timeout:error: (ACRAudioJackReader) or transmitApdu:length:slotNum:timeout:error: (ACRAudioJackReader) method.

...
NSUInteger slotNum = 0;
NSTimeInterval timeout = 10; // 10 seconds.
NSData *atr = nil;
ACRCardProtocol activeProtocol = 0;
uint8_t commandApdu[] = { 0x00, 0x84, 0x00, 0x00, 0x08 };
NSData *responseApdu = nil;
NSError *error = nil;
...
// Reset the card.
atr = [_reader powerCardWithAction:powerAction slotNum:slotNum timeout:timeout
error:&error];
if (atr != nil) {
// Set the protocol.
activeProtocol = [_reader setProtocol:protocols slotNum:slotNum
timeout:timeout error:&error];
// Transmit the APDU.
responseApdu = [_reader transmitApdu:commandApdu length:sizeof(commandApdu)
slotNum:slotNum timeout:timeout error:&error];
}
...

You can transmit the control command to the reader using transmitControlCommand:controlCode:slotNum:timeout:error: (ACRAudioJackReader) or transmitControlCommand:length:controlCode:slotNum:timeout:error: (ACRAudioJackReader) method if the reader supports a set of escape commands.

...
NSUInteger controlCode = ACRIoctlCcidEscape;
uint8_t controlCommand[] = { 0xE0, 0x00, 0x00, 0x18, 0x00 };
NSData *controlResponse = nil;
...
// Transmit the control command.
controlResponse = [_reader transmitControlCommand:controlCommand
controlCode:controlCode slotNum:slotNum timeout:timeout error:&error];
...

Working with the PICC

If your reader came with the PICC interface, you can operate the card using the following methods:

Before transmitting the APDU, you need to power on the card using piccPowerOnWithTimeout:cardType: (ACRAudioJackReader) method. If your delegate object implements ACRAudioJackReaderDelegate::reader:didSendPiccAtr:length method, it will receive the ATR string from the card.

To transmit the APDU, you can use piccTransmitWithTimeout:commandApdu:length: (ACRAudioJackReader) method. If your delegate object implements ACRAudioJackReaderDelegate::reader:didSendPiccResponseApdu:length method, it will receive the response APDU from the card.

After using the card, you can pwoer off the card using piccPowerOff (ACRAudioJackReader) method. If your delegate object implements ACRAudioJackReaderDelegate::reader:didNotifyResult: method, it will receive a notification after the operation is completed.

...
NSUInteger timeout = 1; // 1 second.
NSUInteger cardType = ACRPiccCardTypeIso14443TypeA |
uint8_t commandApdu[] = { 0x00, 0x84, 0x00, 0x00, 0x08 };
...
// Power on the PICC.
[_reader piccPowerOnWithTimeout:timeout cardType:cardType];
...
// Transmit the APDU.
[_reader piccTransmitWithTimeout:timeout commandApdu:commandApdu
length:sizeof(commandApdu)];
...
// Power off the PICC.
[_reader piccPowerOff];
...
#pragma mark - Audio Jack Reader
...
- (void)reader:(ACRAudioJackReader *)reader didSendPiccAtr:(const uint8_t *)atr
length:(NSUInteger)length {
// TODO: Add code here to process the ATR.
...
}
- (void)reader:(ACRAudioJackReader *)reader
didSendPiccResponseApdu:(const uint8_t *)responseApdu
length:(NSUInteger)length {
// TODO: Add code here to process the response APDU.
...
}
- (void)reader:(ACRAudioJackReader *)reader didNotifyResult:(ACRResult *)result {
// TODO: Add code here to process the notification.
...
}
...