The U Grok It SDK for iOS enables easy integration of RFID functionality into an iOS app. Here are the basics of using the SDK. The SDK requires iOS 8.0 or above (and has been tested up to iOS 12.0.1) and supports both Objective-C and Swift. The SDK works with XCode 10.0.0 (and has worked with previous versions of XCode going back several years, but we do not test compatibility with previous version of XCode.
Downloading and Installation
The SDK is distributed as a ZIP file and includes:
|
|
The sample apps demonstrates use of the API. Opening the ugrokitSdk workspace file opens a workspace containing both sample apps. These can be runn either the iOS simulator or an iOS device.
To integrate the U Grok It API into your app, drag the library file (libUGrokItApi.a) from a
Finder window into your project in XCode.
Then click Finish at the dialog box. You can click the checkbox to copy the library file into
the project's folder or not, either way works. This library file works both in the iOS simulator
and on iOS devices.
Drag the include/ folder from a Finder window into your project in XCode
Drag UgrokItResources.bundle from a Finder window into your project in XCode
The application must link with the following libraries. This is set in XCode by clicking on the application in the Project Navigator (on the left), then clicking on the application name under TARGET, then "Build Phases", then "Link Binary with Libraries" and clicking the "+"
- libz.tbd
In Build Settings, set Other Linker Flags to -ObjC
In Build Settings, set Library Search Paths to $(SRCROOT)/..
For Swift, you must also set Objective-C Bridging Header to UgiSwiftBridgingHeader.h inside the include/ folder
For either Objective-C or Swift, edit Info.plist and add a "Privacy - Microphone Usage Description" entry. This is the message iOS will show the user to request permission to use the microphone.
The API is accessed through the Ugi singleton object (Ugi is short for U Grok It). Import Ugi.h:
#import "Ugi.h"
The singleton object should be explicitly created with the createSingleton. This is usually done in your application's main.c file (which XCode puts in the "Supporting Files" folder):
int main(int argc, char * argv[]) { @autoreleasepool { [Ugi createSingleton]; // ADD THIS LINE return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class])); } }The singleton object is normally released in applicationWillTerminate:
[Ugi releaseSingleton];
The API is accessed through the Ugi singleton object (Ugi is short for U Grok It).
The singleton object should be explicitly created with the createSingleton. This is usually done in your AppDelegate's init method:
override init() { Ugi.createSingleton() Ugi.singleton().openConnection() }The singleton object is normally released in applicationWillTerminate
func applicationWillTerminate(application: UIApplication) { Ugi.singleton().closeConnection() }
A production level app needs to do a few housekeeping functions:
- Region Setting
A new Grokker must be configured for the region of the world that it will operate in. - Firmware Update
From time to time, we will release firmware updates for the Grokker.
Calling [Ugi createSingleton] as shown above will use standard UI built into the SDK for these functions.
If you want to customize this UI or if you want to be more restrictive about how and when firmware updates are done, you can pass your own configuration delegate object to createSingletonWithConfigurationDelegate: instead of calling createSingleton:
Communication with the grokker is done via the audio port. For an application that uses U Grok It functionality all the time, this is done in the application delegate's init and applicationWillTerminate methods. For an application that only uses U Grok It occasionally, the connection can be opened and closed at the appropriate points.
[[Ugi singleton] openConnection];
[[Ugi singleton] closeConnection];
Ugi.singleton().openConnection()
Ugi.singleton().closeConnection()
openConnection returns immediately, it does not wait for a connection to the grokker to actually be established. If a grokker is connected, the connection takes 400-500ms (just under half a second) for the connection sequence. Your app can get notification of connection state changes by calling addConnectionStateListener in the Ugi singleton object. Usually a state changed method is not needed, using the Inventory methods described below takes care of this.
Finding RFID tags is accomplished by running inventory. Once inventory is started, the grokker continually looks for RFID tags and reports them back to the iOS device.
Starting inventory returns a UgiInventory object that holds the results of the inventory. The application can either save the UgiInventory object or can use [Ugi singleton].activeInventory to get to it.
UgiInventory does some useful aggregation of the raw data from the grokker and reports back to your application via an InventoryDelegate object. Inventory can be run either with a configuration built from one of the pre-defined inventory types or with a custom UgiRfidConfiguration object.
The application can tell the grokker to report all RFID tags it finds:
UgiInventory *inventory = [[Ugi singleton] startInventory:self // delegate object withConfiguration:[UgiRfidConfiguration configWithInventoryType:UGI_INVENTORY_TYPE_LOCATE_DISTANCE]];
let inventory = Ugi.singleton().startInventory( self, withConfiguration: UgiRfidConfiguration.configWithInventoryType(UgiInventoryTypes.UGI_INVENTORY_TYPE_LOCATE_DISTANCE))
Or the application can pass a specific tag to find:
UgiEpc *epc = [UgiEpc epcFromString:@"35fffffff99c70a063405c48"]; UgiInventory *inventory = [[Ugi singleton] startInventory:self // delegate object withConfiguration:[UgiRfidConfiguration configWithInventoryType:UGI_INVENTORY_TYPE_LOCATE_DISTANCE] withEpc:epc]; // EPC to find
let epc = UgiEpc(fromString: "35fffffff99c70a063405c48") let inventory = Ugi.singleton().startInventory( self, withConfiguration: UgiRfidConfiguration.configWithInventoryType(UgiInventoryTypes.UGI_INVENTORY_TYPE_LOCATE_DISTANCE), withEpc: epc)
Or the application can pass an array of tags to find:
UgiEpc *epc1 = [UgiEpc epcFromString:@"35fffffff99c70a063405c48"]; UgiEpc *epc2 = [UgiEpc epcFromString:@"35fffffff956734504747454"]; UgiInventory *inventory = [[Ugi singleton] startInventory:self // delegate object withConfiguration:[UgiRfidConfiguration configWithInventoryType:UGI_INVENTORY_TYPE_LOCATE_DISTANCE] withEpcs:[NSArray arrayWithObjects:epc1, epc2, nil]];
let epc1 = UgiEpc(fromString: "35fffffff99c70a063405c48") let epc2 = UgiEpc(fromString: "35fffffff956734504747454") let inventory = Ugi.singleton().startInventory( self, withConfiguration: UgiRfidConfiguration.configWithInventoryType(UgiInventoryTypes.UGI_INVENTORY_TYPE_LOCATE_DISTANCE), withEpcs: [epc1, epc2])
Inventory runs until the application stops it.
[[Ugi singleton].activeInventory stopInventoryWithCompletion:^{ // Code to run when inventory is stopped }];
Ugi.singleton().activeInventory.stopInventoryWithCompletion { // Code to run when inventory is stopped }
The inventory code reports back to the application via the inventory delegate object. All methods in the inventory delete are optional - the delegate just implements what it needs. The delegate object must implement the UgiInventoryDelegate protocol:
@interface ViewController : UIViewController<UgiInventoryDelegate>
class ViewController: UgiInventoryDelegate {
Only a subset of the inventory delegate methods are discussed here.
When a new tag is found, the delegate is notified via inventoryTagFound (the detailedPerReadData is nil unless the Grokker was told to return detailed per-read data).
- (void) inventoryTagFound:(UgiTag *)tag withDetailedPerReadData:(NSArray *)detailedPerReadData { // tag was found for the first time }
func inventoryTagFound(tag: UgiTag!, withDetailedPerReadData detailedPerReadData: [UgiDetailedPerReadData]?) { // tag was found for the first time }
The UgiTag object contains information about the tag including:
- Its EPC code
- The time the tag was first read, the time the tag was most recently read
- The total number of times this tag has been read
- A history of how many times this tags has been read in recent time intervals (the default being the number of reads per 500ms going back 10 seconds, but this is configurable)
When a tag is found again, the delegate is notified via inventoryTagSubsequentFinds (the detailedPerReadData is nil unless the Grokker was told to return detailed per-read data).
- (void) inventoryTagSubsequentFinds:(UgiTag *)tag numFinds:(int)num withDetailedPerReadData:(NSArray *)detailedPerReadData { // tag found count more times }
func inventoryTagSubsequentFinds(tag: UgiTag!, numFinds num: Int32, withDetailedPerReadData detailedPerReadData: [UgiDetailedPerReadData]?) { // tag found count more times }
When a tag is first found, has not been seen for a while (by default 10 seconds, but configurable), or is seen again after not being seen for awhile, the delegate is notified via:
- (void) inventoryTagChanged:(UgiTag *)tag isFirstFind:(BOOL)firstFind { if (firstFind) { // tag was found for the first time } else if (tag.isVisible) { // tag was not visible, is now visible again } else { // tag is no longer visible } }
func inventoryTagChanged(tag: UgiTag!, isFirstFind firstFind: Bool) { if (firstFind) { // tag was found for the first time } else if (tag.isVisible) { // tag was not visible, is now visible again } else { // tag is no longer visible } }
Usually the delegate either implements inventoryTagChanged, or implements inventoryTagFound (and sometimes inventoryTagSubsequentFinds).
The delegate can filter which tags are kept track of via:
- (BOOL) inventoryFilter:(UgiEpc *)epc if (this tag should be ignored) { return YES; } else { return NO; } }
func inventoryFilter(epc: UgiEpc!) -> Bool { if (this tag should be ignored) { return true; } else { return false; } }
If this method returns YES, the tag is ignored entirely; inventoryTagFound, inventoryTagSubsequentFinds and inventoryTagChanged are never called for it.
While inventory is running, the app can access the list of found tags via the tags property of the UgiInventory object. Usage is typically:
for (UgiTag *tag in [Ugi singleton].activeInventory.tags) { // do something with tag }
Ugi.singleton().activeInventory.tags.forEach { (tag) in // do something with tag }
Methods in UgiInventory allow tag access for reading, writing and locking. All of these functions work similarly.
While inventory is running, the app can program tags via:
UgiEpc *oldEpc = [UgiEpc epcFromString:@"1234567890abcdef12345678"]; UgiEpc *newEpc = [UgiEpc epcFromString:@"35fffffff956734504747454"]; [[Ugi singleton].activeInventory programTag:oldEpc toEpc:newEpc withPassword:UGI_NO_PASSWORD whenCompleted:^(UgiTag *tag, UgiTagAccessReturnValues result) { if (result == UGI_TAG_ACCESS_OK) { // tag programmed successfully } else { // tag programming was unsuccessful } }];
let oldEpc = UgiEpc(fromString: "1234567890abcdef12345678") let newEpc = UgiEpc(fromString: "35fffffff956734504747454") Ugi.singleton().activeInventory.programTag( oldEpc, toEpc: newEpc, withPassword: UGI_NO_PASSWORD, whenCompleted: { (tag, result) in if (result == UgiTagAccessReturnValues.UGI_TAG_ACCESS_OK) { // tag programmed successfully } else { // tag programming was unsuccessful } })
Sometime after the programTag method is called, the completion will be with the success or failure of the programming.
Since U Grok It plugs into the iOS device's audio port, the audio port needs to be on the bottom of the Grokker, requiring iPhones before the iPhone 5 to be held upside down. This can easily be accomplished in the View's supportedInterfaceOrientations (or shouldAutorotateToInterfaceOrientation pre-iOS 6), either by custom code or by using a UGI method:
- (NSUInteger)supportedInterfaceOrientations { return [[Ugi singleton] supportedInterfaceOrientationsWithAllowRotationOnTablet:YES]; }
override func supportedInterfaceOrientations() -> UIInterfaceOrientationMask { return Ugi.singleton().supportedInterfaceOrientationsWithAllowRotationOnTablet(true) }
The UgiRfidConfiguration object holds the configuration to be used during inventory. Several pre-defined types can be used, defined in the UgiInventoryTypes enum. Values that can be configured include:
- Power level
Initial, minimum and maximum power levels can be set. If a range is provided (minimum != maximum), then the power level is varied over this range. - Q value
Initial, minimum and maximum Q values can be set. If a range is provided (minimum != maximum), then the Q value is dynamically adjusted based on the number of tags in range - Session
The inventory session (0, 1, 2, or 3) - Power level and sensitivity for writing tags
The power level and sensitivity used when writing data to tags - Sensitivity
The reader sensitivity
For more detailed information about RFID and configuration, see RFID Configuration
The sounds that the grokker makes when tags are found can be configured.
To test your app using the iOS simulator (for instance to test devices that you do not have physically, or to take screen shots), you can plug the Grokker into your Mac and it will work with your app running in the iOS simulator. Be sure to plug the Grokker in before running the app, and keep it plugged in, since the iOS simulator does not handle audio devices being plugged and unplugged. On a Macbook (Pro or Air) you can plug the Grokker in directly, on a Mac Mini you will need an adapter cable (the Mac Mini has seperate microphone and speaker jacks).
The SDK uses the Internet in a few cases, see SDK Internet Usage for details.
The SDK contains user visible strings for updating firmware, setting region of the world, and UI building blocks. It is localized into Spanish, French and German. For the localized strings to be used, your app must be localized into these languages as well. If you are interested in localizations to other languages, contact us.
Copyright © 2012-2017 U Grok It, Inc. connect@UGrokIt.com U Grok It and the U Grok It logo are registered trademarks of U Grok It, Inc. All other trademarks and copyrights are the property of their respective owners |