{"_id":"5abba5c00117970012ba9b7b","category":{"_id":"5abba5c00117970012ba9b72","version":"5abba5c00117970012ba9b6e","project":"55093b151c38c50d00611894","__v":0,"sync":{"url":"","isSync":false},"reference":false,"createdAt":"2015-03-18T09:01:41.604Z","from_sync":false,"order":4,"slug":"code-examples","title":"Code Examples"},"project":"55093b151c38c50d00611894","user":"55093bd84510200d00adf3c7","version":{"_id":"5abba5c00117970012ba9b6e","project":"55093b151c38c50d00611894","__v":2,"createdAt":"2018-03-28T14:25:04.622Z","releaseDate":"2018-03-28T14:25:04.622Z","categories":["5abba5c00117970012ba9b6f","5abba5c00117970012ba9b70","5abba5c00117970012ba9b71","5abba5c00117970012ba9b72","5ace17b040606a0003eabc75"],"is_deprecated":false,"is_hidden":false,"is_beta":false,"is_stable":true,"codename":"","version_clean":"2.0.0","version":"2.0"},"__v":0,"updates":[],"next":{"pages":[],"description":""},"createdAt":"2015-03-18T13:45:03.014Z","link_external":false,"link_url":"","githubsync":"","sync_unique":"","hidden":false,"api":{"results":{"codes":[]},"settings":"","auth":"required","params":[],"url":""},"isReference":false,"order":8,"body":"# MagicBeep #\n\nThis is a quick start to using the ISKN API on Xcode. At the end of this tutorial, the developer should be capable to create an iOS application based on the ISKN API and master the most important concepts about the API architecture and usage. This involves listing the available slates, connecting to a slate, requesting information about the slate as well as subscribing to the ISKN services and decoding slate data.\nThe following tutorial assumes that the developer has already installed the latest version of Xcode.\nSo before you start, be sure you have your development environment set up.\n\nThis is a simple sound player app using the ISKN Slate. \nThe application detects the presence of a pen and plays different beep sounds when the pen enters or leaves the Slate field of view.\nNote that you can find __the full source code__ for this example in the ISKN_API examples folder.   \n\n \n## 1.Set Up Your Project\n\nIn this example you need to create a __Single View Application__.\nYou can specify _MagicBeep_ as a project name.\n\nLink the ISKN API to your project. To do so you can see the first tutorial [here](getting-started-with-iskn-api-on-ios).\n\nIn addition to the ISKN API,you need to add three iOS frameworks to the application : CoreBluetooth.framework, UIKit.framework and AudioToolbox.framework.\n\nThe CoreBluetooth framework provides the resources your iOS apps need to communicate with devices that are equipped with Bluetooth low energy (BLE) technology like the ISKN Slate.\n  \nThe UIKit framework (UIKit.framework) provides the crucial infrastructure needed to construct and manage iOS apps.\n \nThe AudioToolbox framework provides interfaces for recording, playback, and stream parsing.\n[block:image]\n{\n  \"images\": [\n    {\n      \"image\": [\n        \"https://files.readme.io/i5L3E0iNSJaRiH28J3Hi_Xcode_s2_Buildphases.png\",\n        \"Xcode_s2_Buildphases.png\",\n        \"880\",\n        \"297\",\n        \"#813817\",\n        \"\"\n      ]\n    }\n  ]\n}\n[/block]\nNow Add a C++ file with a header file to the MagicBeep folder to do so:\n+ Select the MagicBeep folder and right click on it. Select __New File...__ \n[block:image]\n{\n  \"images\": [\n    {\n      \"image\": [\n        \"https://files.readme.io/ZLhCuGXwQE6CfSMi2E9c_Xcode_s2_newFile.png\",\n        \"Xcode_s2_newFile.png\",\n        \"300\",\n        \"120\",\n        \"#2e64ab\",\n        \"\"\n      ]\n    }\n  ]\n}\n[/block]\n+ Select iOS then choose C++ file and click __Next__ \n[block:image]\n{\n  \"images\": [\n    {\n      \"image\": [\n        \"https://files.readme.io/e3809bc-Picture1.png\",\n        \"Picture1.png\",\n        1466,\n        1056,\n        \"#edeeed\"\n      ]\n    }\n  ]\n}\n[/block]\n+ Specify MagicBeep as a name and check __Also create a header file__ option then click __Next__ \n[block:image]\n{\n  \"images\": [\n    {\n      \"image\": [\n        \"https://files.readme.io/8mjCGEBlR7GgxHcpA4a9_Xcode_s2_cppFile_options.png\",\n        \"Xcode_s2_cppFile_options.png\",\n        \"736\",\n        \"432\",\n        \"#3268ad\",\n        \"\"\n      ]\n    }\n  ]\n}\n[/block]\n+ Select __Create__ on the next Window. Xcode generates a header file 'MagicBeep.h' and a source file 'MagicBeep.cpp' under the MagicBeep folder.\nDouble click on the MagicBeep.cpp file and change the extension from cpp to mm.\nNow your MagicBeep folder should look like this :\n[block:image]\n{\n  \"images\": [\n    {\n      \"image\": [\n        \"https://files.readme.io/9b4e3a7-Picture2.png\",\n        \"Picture2.png\",\n        546,\n        442,\n        \"#f1f1f2\"\n      ]\n    }\n  ]\n}\n[/block]\nSince the ISKN API is a C++ library you need to mix C++ and Objective-C in the MagicBeep Files.\n\nBy renaming the MagicBeep.cpp file to have a .mm extension you tell the compiler that this file combine the Objective-C and the C++ languages.\n\n\n## 2.Including the ISKN API main header file\n\nAdd a Header Search Path for the ISKN API header. To do so you can see the first tutorial [here](md_src_example_ios_s1.html).\n\nInclude ISKN_API.h file in of the MagicBeep.h file  :\n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"#include \\\"ISKN_API.h\\\"\",\n      \"language\": \"cplusplus\"\n    }\n  ]\n}\n[/block]\nSince the MagicBeep class should interact with both the graphical interface \nand the Audio service. We need to import the `AudioToolbox.h` file as well as\nthe `ViewController.h` file :\n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"#import <AudioToolbox/AudioToolbox.h>\\n#import \\\"ViewController.h\\\"\",\n      \"language\": \"cplusplus\"\n    }\n  ]\n}\n[/block]\n\nCreate a C++ class with MagicBeep as name in the MagicBeep.h. \nThen add a reference to the ViewController class. \nThis reference is used to interact with the graphical interface :\n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"class MagicBeep \\n{\\n    \\npublic:\\n    MagicBeep(ViewController *viewController);\\n    \\n    ViewController *viewController;\\n};\",\n      \"language\": \"cplusplus\"\n    }\n  ]\n}\n[/block]\n\nIn the MagicBeep.mm, add MagicBeep constructor implementation.\nThe constructor takes as a parameter a pointer to a ViewController.\nIt saves this reference in the internal attribute viewController :\n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"MagicBeep::MagicBeep(ViewController *viewController)\\n{\\n    // Get a pointer to the view controller\\n    this->viewController=viewController;   \\n}\",\n      \"language\": \"cplusplus\"\n    }\n  ]\n}\n[/block]\nThe viewController pointer allows access to the project ViewController.\n \n## 3.Preparing the event listener class\n\nTo receive the Slate events, you need to register a listener. \nIn this example, the MagicBeep class extends the Listener class.\n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"class MagicBeep : public Listener\",\n      \"language\": \"cplusplus\"\n    }\n  ]\n}\n[/block]\nThe listener class is an interface providing the following methods :\n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"virtual void processEvent(ISKN_API::Event &e, unsigned int timecode)=0;\\nvirtual void connectionStatusChanged(bool connected)=0;\",\n      \"language\": \"cplusplus\"\n    }\n  ]\n}\n[/block]\nThose methods __should be implemented__ by the subclass in order to receive the slate events.\nAt this point, the MagicBeep listener class is ready to be registered.\n \n## 4.Preparing the communication tools\n\nBefore registering the listener, we need to create the Slate manager object.\n\nTo do so, add those attributes to your MagicBeep class declaration :\n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"// ISKN API attributes\\n    SlateManager   *iskn_SlateManager;\",\n      \"language\": \"cplusplus\"\n    }\n  ]\n}\n[/block]\nIn the constructor method of the MagicBeep class, create the slate manager object :\n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"  // Create slate manager\\n    iskn_SlateManager  = new SlateManager();\",\n      \"language\": \"cplusplus\"\n    }\n  ]\n}\n[/block]\n## 5. Registering the events listener\n\nOnce the slate manager is created, it is possible to register the MagicBeep class as a listener. \nTo do so, use the **registerListener** method of the slate manager in MagicBeep constructor :\n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"//Register the MagicBeep class as a Listener\\n  \\tiskn_SlateManager->registerListener(this) ;\",\n      \"language\": \"cplusplus\"\n    }\n  ]\n}\n[/block]\n## 6. Scan for the Slates \n\nTo scan for the Slates, the MagicBeep class needs to extend the **BleScanListener** class. \n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"class MagicBeep :public Listener, BleScanListener\",\n      \"language\": \"cplusplus\"\n    }\n  ]\n}\n[/block]\nThe **BleScanListener** class is an interface providing three methods that should be implemented by the MagicBeep class:\n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"virtual void newDeviceFound(CBPeripheral *p_device)=0;\\nvirtual void notify(ScannerEvent evt)=0;\\nvirtual void scanFinished()=0;\",\n      \"language\": \"cplusplus\"\n    }\n  ]\n}\n[/block]\nTo launch the scan for the Slates, use the **startScan** method.\n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"// Scan for devices\\n   iskn_SlateManager->startScan(this);\",\n      \"language\": \"cplusplus\"\n    }\n  ]\n}\n[/block]\nWhen a Slate is discovered, the **newDeviceFound**  method is called.This methods takes a Bluetooth device as parameter. \nThe discovered Slate can be added to a list of discovered devices.\n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \" void MagicBeep::newDeviceFound(CBPeripheral *p_device)\\n{\\n   NSLog(:::at:::\\\"Device found %@\\\",p_device.name);\\n    [viewController.myData addObject:p_device.name];\\n    [viewController.devicesList reloadData]; \\n}\",\n      \"language\": \"cplusplus\"\n    }\n  ]\n}\n[/block]\nOnce a Slate is selected from the devices list, the **deviceSelected** method is called. the later stops the scan, retrieves the Slate instance and try to connect to it via the **connect** method.\n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"void deviceSelected(int deviceID)\\n{\\n magicBeep->iskn_SlateManager->stopScan();\\n CBPeripheral *p_device =magicBeep->iskn_SlateManager->getDeviceByID(deviceID);\\n magicBeep->iskn_SlateManager->connect(p_device);\\n [magicBeep->viewController.devicesList setHidden:YES];\\n}\",\n      \"language\": \"cplusplus\"\n    }\n  ]\n}\n[/block]\nWhen the Slate is connected, the **connectionStatusChanged** method is called : \n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"// Connection status has changed\\nvoid MagicBeep::connectionStatusChanged(bool connected)\\n{\\n    if(connected){\\n        // Request Slate description\\n        iskn_SlateManager.request(REQ_DESCRIPTION);\\n        \\n        // Subscribe to events (Status, Pen Status, Function Call and Pen_3D)\\n        \\n        iskn_SlateManager.subscribe(\\n                                 AUTO_STATUS |\\n                                 AUTO_SOFTWARE_EVENTS |\\n                                 AUTO_HARDWARE_EVENTS |\\n                                 AUTO_PEN_3D\\n                                 ) ;\\n                                     \\n        addTextToView(@\\\"[Connected]\\\\n\\\");\\n        NSLog(@\\\"[Connected]\\\\n\\\");\\n    }\\n    else\\n    {\\n        addTextToView(@\\\"[Could not connect]\\\\n\\\");\\n        NSLog(@\\\"[Could not connect]\\\\n\\\");\\n    }\\n}\",\n      \"language\": \"cplusplus\"\n    }\n  ]\n}\n[/block]\nIn this example, we request the Slate description.It gathers specific Slate information such as Slate name, the size of the Slate, the writing zone of the Slate. This is performed by the **request** method of the SlateManager class.\nFinally, we subscribe to automatic events services. This tells the Slate which events the MagicBeep class should receive.\n\nSo we subscribe to four types of events :\n\n + AUTO_STATUS        \t\t: Asks to receive slate status changes like Battery level.\n + AUTO_SOFTWARE_EVENTS    \t: Asks to receive Software events like object status changes.\n (Object recognised (SE_OBJECT_IN), object lost(SE_OBJECT_OUT), handshake event (a periodic event used to detect that the Slate is still on)).\n + AUTO_HARDWARE_EVENTS \t: Asks to receive Hardware events like a pressed button.\n + AUTO_PEN_2D        \t\t: Asks to receive the Pen tip 2D position and contact status at a 140Hz frequency when the pen is in the field of view of the slate.  \n\n\n## 7. Receive and extract events\n\nThe processEvent method is called whenever a new event is received from the Slate.\n\nUse the type attribute of the Event object in order to figure out the event type.\nYou can use a switch case statement as follow :\n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"switch (event.Type)\\n    {\\n        case EVT_STATUS :\\n        {\\n            //Slate status change detected\\n        }\\n            break ;\\n            \\n        case EVT_PEN_2D :\\n        {\\n            // New pen position and contact received\\n        }\\n            break ;\\n            \\n        case EVT_HARDWARE :\\n        {\\n   \\t\\t\\t//A hardware event happened \\n   \\t\\t\\tEventHardware &ev=event.HardwareEvent ;\\n            switch (ev.getHardwareEventType())\\n            {\\n                case HE_BUTTON1_PRESSED :\\n                     Button 1 is pressed\\n                    break ;\\n                case HE_BUTTON2_PRESSED :\\n                \\t Button 2 is pressed\\n                    break ;\\n                default :\\n                    break ;\\n            }\\n        }\\n            break ;\\n            \\n        case EVT_DESCRIPTION :\\n        {\\n        \\tEvent received after description request\\n        }\\n            break ;\\n            \\n        case EVT_SOFTWARE :\\n        {\\n        \\t//A software event has happened\\n        \\t\\n            EventSoftware &ev=event.SoftwareEvent ;\\n            \\n            switch (ev.getSoftwareEventType())\\n            {\\n                case SE_OBJECT_IN :\\n                {\\n                  // A new object is detected\\n                }\\n                    break ;\\n                case SE_OBJECT_OUT :\\n                {\\n                  // Object lost\\n                }\\n            }\\n        }\\n            break ;\\n            \\n        default :\\n        \\n            break ;\\n    }\",\n      \"language\": \"cplusplus\"\n    }\n  ]\n}\n[/block]\n## 8. Add a C wrapper to connect the objective-C and the C++\nIn order to link the view controller (Objective-C) to the MagicBeep class (C++),\nwe use C function Wrappers. \nThe first function `launchMagicBeep(ViewController *viewController)` is used to construct an instance of the MagicBeep class.\nThe instance is declared in the MagicBeep.mm source file:\n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"MagicBeep * magicBeep ;\",\n      \"language\": \"cplusplus\"\n    }\n  ]\n}\n[/block]\n\nThe wrapper function is preceded by the `extern \"C\"` statement in order to specify that it is a C function.\n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"extern \\\"C\\\"\\nvoid launchMagicBeep(ViewController *viewController)\\n{\\ntry\\n{\\nmagicBeep=new MagicBeep(viewController);\\n}\\ncatch (Error &err)\\n{\\nNSLog(@\\\"Error\\\");\\n}\\n}\",\n      \"language\": \"cplusplus\"\n    }\n  ]\n}\n[/block]\nThe wrapper function is called when the view is loaded.\nFirst in the `ViewController.m` file, add a prototype definition for the `launchMagicBeep` function.\n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"extern void launchMagicBeep(ViewController* viewController) ;\",\n      \"language\": \"cplusplus\"\n    }\n  ]\n}\n[/block]\nThen call `launchMagicBeep` in the viewDidLoad method of your ViewController :\n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"launchMagicBeep(self) ;\",\n      \"language\": \"cplusplus\"\n    }\n  ]\n}\n[/block]\n\nNow, the MagicBeep class has direct access to any synthesized property of the viewController.\n\n\n## 9. Preparing the Storyboard\n\nIn this application we use a simple interface with a `TextView`, a `Table view` to list the scanned slates and `Toolbar` with a single text item and an activity indicator to tell when the application is connecting to the Slate.\n\nCreate outlets for the TextView, the item, the Table view and the activityIndicator, in the `ViewController.h`:\n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"@interface ViewController : UIViewController<UITableViewDataSource,UITableViewDelegate>\\n{\\n    NSMutableArray *myData;\\n}\\n@property NSMutableArray *myData;\\n@property (weak, nonatomic) IBOutlet UITextView *mainText;\\n@property (weak, nonatomic) IBOutlet UIBarButtonItem *connectionStatus;\\n@property (weak, nonatomic) IBOutlet UIActivityIndicatorView *activityIndicator;\\n@property (weak, nonatomic) IBOutlet UITableView *devicesList;\\n\\n@end\",\n      \"language\": \"objectivec\"\n    }\n  ]\n}\n[/block]\nNow, synthesise them in the `ViewController.m` :\n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"@synthesize mainText;\\n@synthesize connectionStatus;\\n@synthesize activityIndicator;\\n@synthesize devicesList;\\n@synthesize myData;\",\n      \"language\": \"objectivec\"\n    }\n  ]\n}\n[/block]\nAt this stage, the interface can be accessed by the MagicBeep class.\n\n## 10. Interacting with the interface\n\nAdd a method `addTextToView(NSString *str)` to the MagicBeep class. \nThis method adds a string to the textview :\n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"\\tvoid MagicBeep::addTextToView(NSString *str)\\n\\t{\\n\\t\\tviewController.mainText.text=[viewController.mainText.text stringByAppendingString:str] ;\\n\\t\\tNSLog(@\\\"%@\\\", str) ;\\n\\t}\",\n      \"language\": \"cplusplus\"\n    }\n  ]\n}\n[/block]\nNow use this function to notify the user about all events that are received.\nHere how to call the addTextToView method from the `processEvent` method: \n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"\\tswitch (event.Type)\\n\\t\\t{\\n\\t\\t\\tcase EVT_STATUS :\\n\\t\\t\\t{\\n\\t\\t\\t\\tEventStatus &ev=event.Status ;\\n\\t\\t\\t\\tint bat=ev.getBattery() ;\\n\\t\\t\\t\\taddTextToView([NSString stringWithFormat:@\\\"Battery %d\\\\n\\\", bat]) ;\\n\\t\\t\\t}\\n\\t\\t\\tbreak ;\\n\\t\\t\\n\\t\\t\\tcase EVT_HARDWARE :\\n\\t\\t\\t{\\n\\t\\t\\t\\tEventHardware &ev=event.HardwareEvent ;\\n\\t\\t\\t\\tswitch (ev.getHardwareEventType())\\n\\t\\t\\t\\t{\\n\\t\\t\\t\\tcase HE_BUTTON1_PRESSED :\\n\\t\\t\\t\\taddTextToView([NSString stringWithFormat:@\\\"Button 1 pressed\\\\n\\\"]) ;\\n\\t\\t\\t\\tbreak ;\\n\\t\\t\\t\\tcase HE_BUTTON2_PRESSED :\\n\\t\\t\\t\\taddTextToView([NSString stringWithFormat:@\\\"Button 2 pressed\\\\n\\\"]) ;\\n\\t\\t\\t\\tbreak ;\\n        case HE_BUTTON1_LONGPRESS:\\n          addTextToView([NSString stringWithFormat:@\\\"Button 1 long pressed\\\\n\\\"]) ;\\n        break;\\n        case HE_BUTTON2_LONGPRESS:\\n          addTextToView([NSString stringWithFormat:@\\\"Button 2 long pressed\\\\n\\\"]) ;\\n        break;\\n\\t\\t\\t\\tdefault :\\n\\t\\t\\t\\tbreak ;\\n\\t\\t\\t\\t}\\n\\t\\t\\t}\\n\\t\\t\\tbreak ;\\n\\n\\t\\t\\tcase EVT_DESCRIPTION :\\n\\t\\t\\t{\\n\\t\\t\\t\\tEventDescription &ev=event.Description ;\\n        NSString *nss_deviceName = [NSString stringWithUTF8String:ev.getDeviceName()];\\n            \\n        [viewController.connectionStatus setTitle:[@\\\"Connected to Slate \\\" stringByAppendingString: nss_deviceName]];\\n\\n        addTextToView([NSString stringWithFormat:@\\\"Connected to Slate : %@\\\\n\\\", nss_deviceName]) ;\\n\\t\\t\\t}\\n\\t\\t\\tbreak ;\\n\\t\\t\\t\\n\\t\\t\\tcase EVT_SOFTWARE :\\n\\t\\t\\t{\\n\\t\\t\\t\\tEventSoftware &ev=event.SoftwareEvent ;\\n\\t\\t\\t\\tint p=ev.getObjectID() ;\\n\\t\\t\\t\\tswitch (ev.getSoftwareEventType())\\n\\t\\t\\t\\t{\\n\\t\\t\\t\\tcase SE_OBJECT_IN :\\n\\t\\t\\t\\t{\\n\\t\\t\\t\\taddTextToView([NSString stringWithFormat:@\\\"Object in \\\\n\\\"]) ;\\n\\t\\t\\t\\t}\\n\\t\\t\\t\\tbreak ;\\n\\t\\t\\t\\tcase SE_OBJECT_OUT :\\n\\t\\t\\t\\t{\\n\\t\\t\\t\\taddTextToView([NSString stringWithFormat:@\\\"Object out \\\\n\\\"]) ;\\n\\t\\t\\t\\t}\\n\\t\\t\\t\\t}\\n\\t\\t\\t}\\n\\t\\t\\tbreak ;\\n\\n\\t\\t\\tdefault :\\n\\t\\t\\tbreak ;\\n\\t\\t}\",\n      \"language\": \"cplusplus\"\n    }\n  ]\n}\n[/block]\n## 11. Animate the activityIndicator\n\nTo indicate that the application is connecting to the Slate, we add the following line to the constructor of the MagicBeep class :\n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"[viewController.activityIndicator startAnimating];\",\n      \"language\": \"cplusplus\"\n    }\n  ]\n}\n[/block]\n\nThe animation should be stopped and the indicator should disappear when the connection succeeds.\nAdd the following code to the `connectionStatusChanged` method, in the if(connected) scope :\n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"viewController.activityIndicator.hidesWhenStopped=true;\\n[viewController.activityIndicator stopAnimating];\",\n      \"language\": \"cplusplus\"\n    }\n  ]\n}\n[/block]\n\n## 12. Play the Beep sound\n\nThis application plays a simple tone when a pen enters in the slate field of view.\nIn this example, three Wave files are added to the project :Beep.wav,Beep 2.wav and Beep 3.wav in new group called Sounds.\n[block:image]\n{\n  \"images\": [\n    {\n      \"image\": [\n        \"https://files.readme.io/9bWVHNXfTE68wEMcZESP_Xcode_s2_Sounds.png\",\n        \"Xcode_s2_Sounds.png\",\n        \"263\",\n        \"412\",\n        \"#1f53a1\",\n        \"\"\n      ]\n    }\n  ]\n}\n[/block]\nAdd the definition of the sounds to the MagicBeep constructor :\n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"//Create first sound path\\nNSURL *soundURL1=[NSURL fileURLWithPath:[[NSBundle mainBundle] pathForResource:@\\\"Beep\\\" ofType:@\\\"wav\\\"]];\\n// Create the first sound    \\nAudioServicesCreateSystemSoundID((__bridge CFURLRef) soundURL1, &beepTone1);\\n    \\n//Create second sound path   \\nNSURL *soundURL2=[NSURL fileURLWithPath:[[NSBundle mainBundle] pathForResource:@\\\"Beep 2\\\" ofType:@\\\"wav\\\"]];  \\n// Create the second sound   \\nAudioServicesCreateSystemSoundID((__bridge CFURLRef) soundURL2, &beepTone2);\\n \\n//Create third sound path    \\nNSURL *soundURL3=[NSURL fileURLWithPath:[[NSBundle mainBundle] pathForResource:@\\\"Beep 3\\\" ofType:@\\\"wav\\\"]];   \\n// Create the third sound   \\nAudioServicesCreateSystemSoundID((__bridge CFURLRef) soundURL3, &beepTone3);\",\n      \"language\": \"cplusplus\"\n    }\n  ]\n}\n[/block]\nAdd playSound(int soundID) method to the MagicBeep class which plays a different sound when pen is detected.\n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"void MagicBeep::playSound(int soundID)\\n{\\n    switch (soundID)\\n    {\\n        case  1:\\n        {\\n           AudioServicesPlaySystemSound(beepTone1);\\n        }\\n            break ;\\n            \\n        case  2:\\n        {\\n            AudioServicesPlaySystemSound(beepTone2);\\n        }\\n            break ;\\n       \\n        default:\\n        {\\n            AudioServicesPlaySystemSound(beepTone3);\\n        }\\n            break ;\\n    \\n    }\\n}\",\n      \"language\": \"cplusplus\"\n    }\n  ]\n}\n[/block]\n\nNow the sound is ready to be played.\nYou can play the sound when the pen is in the Slate field of view by using the playSound method :\n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"case EVT_SOFTWARE :     \\n{          \\n\\tEventSoftware &ev=event.SoftwareEvent ;\\n\\tint p=ev.getObjectID() ;\\n            \\n\\tswitch (ev.getSoftwareEventType())         \\n\\t{         \\n\\t\\tcase SE_OBJECT_IN :       \\n\\t\\t{          \\n\\t\\t\\taddTextToView([NSString stringWithFormat:@\\\"Object in \\\\n\\\"]) ;\\n      playSound(1);      \\n\\t\\t}          \\n\\t\\t\\tbreak ;      \\n\\t\\tcase SE_OBJECT_OUT :       \\n\\t\\t{         \\n\\t\\t\\t addTextToView([NSString stringWithFormat:@\\\"Object out \\\\n\\\"]) ;\\n       playSound(2);    \\n\\t\\t}\\n\\t\\t\\tbreak;          \\n\\t}      \\n}       \\n\\tbreak ;\",\n      \"language\": \"cplusplus\"\n    }\n  ]\n}\n[/block]\nTo sum up your MagicBeep.h and your MagicBeep.mm files should be like this:\n\nMagicBeep.h file :\n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"//\\n//  MagicBeep.h\\n//  MagicBeep\\n//\\n//  Created by ALOUI Rabeb on 08/02/15.\\n//  Copyright (c) 2015 ISKN. All rights reserved.\\n//\\n\\n#ifndef __MagicBeep__MagicBeep__\\n#define __MagicBeep__MagicBeep__\\n\\n#include <ISKN_API.h>\\n#import <AudioToolbox/AudioToolbox.h>\\n#import \\\"ViewController.h\\\"\\n\\n\\nusing namespace ISKN_API;\\n\\nclass MagicBeep :public Listener, BleScanListener\\n{\\n    \\npublic:\\n    \\n    // ISKN API attributes\\n    SlateManager   *iskn_SlateManager;\\n    \\n    // Application specific attributes\\n    SystemSoundID beepTone1,beepTone2,beepTone3;\\n    ViewController *viewController;\\n    \\n    // Constructor\\n    MagicBeep(ViewController *viewController);\\n    \\n    // Inherited methods\\n    \\n    // Listener\\n    void connectionStatusChanged(bool connected);\\n    void processEvent(ISKN_API::Event &event, unsigned int timecode);\\n    \\n    // BleScanListener\\n    void newDeviceFound(CBPeripheral *p_device);\\n    void notify(ScannerEvent evt);\\n    void scanFinished();\\n    \\n    // Application specific methods\\n    void addTextToView(NSString *str);\\n    void playSound(int soundID);\\n};\\n\\n\\n#endif /* defined(__MagicBeep__MagicBeep__) */\",\n      \"language\": \"cplusplus\"\n    }\n  ]\n}\n[/block]\n\nMagicBeep.mm file :\n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"//\\n//  MagicBeep.cpp\\n//  MagicBeep\\n//\\n//  Created by ALOUI Rabeb on 08/02/15.\\n//  Copyright (c) 2015 ISKN. All rights reserved.\\n//\\n\\n#include \\\"MagicBeep.h\\\"\\n\\nMagicBeep * magicBeep ;\\n\\n\\n// Cpp/Objective-C Wrapper function\\n\\nextern \\\"C\\\"\\n{\\n    void launchMagicBeep(ViewController *viewController)\\n    {\\n        try\\n        {\\n            magicBeep=new MagicBeep(viewController);\\n        }\\n        catch (Error &err)\\n        {\\n            NSLog(@\\\"Error\\\");\\n        }\\n    }\\n\\n    void deviceSelected(int deviceID)\\n    {\\n        magicBeep->iskn_SlateManager->stopScan();\\n        CBPeripheral *p_device =magicBeep->iskn_SlateManager->getDeviceByID(deviceID);\\n        magicBeep->iskn_SlateManager->connect(p_device);\\n        [magicBeep->viewController.devicesList setHidden:YES];\\n \\n    }\\n}\\n\\n//MagicBeep constructor\\nMagicBeep::MagicBeep(ViewController *viewController)\\n{\\n    // Get a pointer to the ViewController\\n    this->viewController=viewController;\\n    \\n    // Create slate manager\\n    iskn_SlateManager  = new SlateManager();\\n    \\n    //Register the MagicBeep class as a Listener\\n    iskn_SlateManager->registerListener(this) ;\\n    \\n   \\n    addTextToView(@\\\"Scan for ISKN Slates...\\\\n\\\");\\n    \\n    // Scan for devices\\n    iskn_SlateManager->startScan(this);\\n    \\n    [viewController.activityIndicator startAnimating];\\n    \\n    //Create first sound path\\n    NSURL *soundURL1=[NSURL fileURLWithPath:[[NSBundle mainBundle] pathForResource:@\\\"Beep\\\" ofType:@\\\"wav\\\"]];\\n    // Create the first sound\\n    AudioServicesCreateSystemSoundID((__bridge CFURLRef) soundURL1, &beepTone1);\\n    \\n    \\n    //Create second sound path\\n    NSURL *soundURL2=[NSURL fileURLWithPath:[[NSBundle mainBundle] pathForResource:@\\\"Beep 2\\\" ofType:@\\\"wav\\\"]];\\n    // Create the second sound\\n    AudioServicesCreateSystemSoundID((__bridge CFURLRef) soundURL2, &beepTone2);\\n    \\n    \\n    //Create third sound path\\n    NSURL *soundURL3=[NSURL fileURLWithPath:[[NSBundle mainBundle] pathForResource:@\\\"Beep 3\\\" ofType:@\\\"wav\\\"]];\\n    // Create the third sound\\n    AudioServicesCreateSystemSoundID((__bridge CFURLRef) soundURL3, &beepTone3);\\n    \\n}\\n// newDeviceFound function\\n\\nvoid MagicBeep::newDeviceFound(CBPeripheral *p_device)\\n{\\n    NSLog(@\\\"Device found %@\\\",p_device.name);\\n    [viewController.myData addObject:p_device.name];\\n    [viewController.devicesList reloadData];\\n}\\n\\n// connectionStatusChanged function \\n\\nvoid MagicBeep::connectionStatusChanged(bool connected)\\n{\\n    if(connected){\\n        // Request Slate description\\n        iskn_SlateManager->request(REQ_DESCRIPTION);\\n        \\n        // Subscribe to events (Status, Software events, Hardware events and Pen 2D event)\\n        iskn_SlateManager->subscribe(\\n                                 AUTO_STATUS |\\n                                 AUTO_SOFTWARE_EVENTS |\\n                                 AUTO_HARDWARE_EVENTS |\\n                                 AUTO_PEN_2D\\n                                 ) ;\\n        \\n        viewController.activityIndicator.hidesWhenStopped=true;\\n        [viewController.activityIndicator stopAnimating];\\n        \\n        NSLog(@\\\"[Connected]\\\\n\\\");\\n    }\\n    else\\n    {\\n        addTextToView(@\\\"[Could not connect]\\\\n\\\");\\n        NSLog(@\\\"[Could not connect]\\\\n\\\");\\n    }\\n}\\n\\n// processEvent function\\n\\nvoid MagicBeep::processEvent(Event &event, unsigned int timecode)\\n{\\n    switch (event.Type)\\n    {\\n        case EVT_STATUS :\\n        {\\n            EventStatus &ev=event.Status ;\\n            int bat=ev.getBattery() ;\\n            addTextToView([NSString stringWithFormat:@\\\"Battery %d\\\\n\\\", bat]) ;\\n        }\\n            break ;\\n            \\n        case EVT_PEN_2D :\\n        {\\n            EventPen2D &ev=event.Pen2D ;\\n            Vector2D po=ev.getPosition() ;\\n            NSLog(@\\\"%@\\\", [NSString stringWithFormat:@\\\"EvtPen2D : %d : (%f , %f)\\\\n\\\", ev.Touch() ? 1 : 0, po.X, po.Y]) ;\\n        }\\n            break ;\\n            \\n        case EVT_HARDWARE :\\n        {\\n            EventHardware &ev=event.HardwareEvent ;\\n            switch (ev.getHardwareEventType())\\n            {\\n                case HE_BUTTON1_PRESSED :\\n                    addTextToView([NSString stringWithFormat:@\\\"Button 1 pressed\\\\n\\\"]) ;\\n                    break ;\\n                case HE_BUTTON2_PRESSED :\\n                    addTextToView([NSString stringWithFormat:@\\\"Button 2 pressed\\\\n\\\"]) ;\\n                    break ;\\n                case HE_BUTTON1_LONGPRESS:\\n                    addTextToView([NSString stringWithFormat:@\\\"Button 1 long pressed\\\\n\\\"]) ;\\n                    break;\\n                case HE_BUTTON2_LONGPRESS:\\n                    addTextToView([NSString stringWithFormat:@\\\"Button 2 long pressed\\\\n\\\"]) ;\\n                    break;\\n                default :\\n                    break ;\\n            }\\n        }\\n            break ;\\n            \\n        case EVT_DESCRIPTION :\\n        {\\n            EventDescription &ev=event.Description ;\\n            NSString *nss_deviceName = [NSString stringWithUTF8String:ev.getDeviceName()];\\n            \\n            [viewController.connectionStatus setTitle:[@\\\"Connected to Slate \\\" stringByAppendingString: nss_deviceName]];\\n\\n            addTextToView([NSString stringWithFormat:@\\\"Connected to Slate : %@\\\\n\\\", nss_deviceName]) ;\\n        }\\n            break ;\\n            \\n            \\n        case EVT_SOFTWARE :\\n        {\\n            EventSoftware &ev=event.SoftwareEvent ;\\n            \\n            switch (ev.getSoftwareEventType())\\n            {\\n                case SE_OBJECT_IN :\\n                {\\n                    addTextToView([NSString stringWithFormat:@\\\"Object in \\\\n\\\"]) ;\\n                    playSound(1);\\n                }\\n                    break ;\\n                case SE_OBJECT_OUT :\\n                {\\n                    addTextToView([NSString stringWithFormat:@\\\"Object out \\\\n\\\"]) ;\\n                    playSound(2);\\n                }\\n                    break;\\n                case SE_HANDSHAKE:\\n                    // Nothing to do\\n                    break;\\n                    \\n                case SE_UNKNOWN:\\n                    // Nothing to do\\n                    break;\\n            }\\n        }\\n            break ;\\n            \\n        default :\\n            break ;\\n    }\\n    \\n}\\n\\n// addTextToView function\\n\\nvoid MagicBeep::addTextToView(NSString *str)\\n{\\n    viewController.mainText.text=[viewController.mainText.text stringByAppendingString:str] ;\\n    NSLog(@\\\"%@\\\", str) ;\\n}\\n\\n// playSound function\\n\\nvoid MagicBeep::playSound(int soundID)\\n{\\n    switch (soundID)\\n    {\\n        case  1:\\n        {\\n           AudioServicesPlaySystemSound(beepTone1);\\n        }\\n            break ;\\n            \\n        case  2:\\n        {\\n            AudioServicesPlaySystemSound(beepTone2);\\n        }\\n            break ;\\n       \\n        default:\\n        {\\n            AudioServicesPlaySystemSound(beepTone3);\\n        }\\n            break ;\\n    \\n    }\\n}\\nvoid MagicBeep::notify(ScannerEvent evt)\\n{\\n    switch(evt){\\n        case BLESCANNER_EVENT_NONE:\\n            //...\\n            break;\\n        case BLESCANNER_EVENT_ACTIVATION_REQUIRED:\\n            NSLog(@\\\"Notification received\\\");\\n            break;\\n        case BLESCANNER_EVENT_BLE_NOT_SUPPORTED:\\n            NSLog(@\\\"BLE not supported\\\");\\n            break;\\n        case BLESCANNER_EVENT_BLE_SCAN_STARTED:\\n            NSLog(@\\\"Scan started\\\");\\n            break;\\n            \\n    }\\n    \\n}\\nvoid MagicBeep::scanFinished()\\n{\\n    NSLog(@\\\"Scan finished\\\");   \\n}\",\n      \"language\": \"cplusplus\"\n    }\n  ]\n}\n[/block]\n## 13. Run your project\n\nYour project is now ready to run. At launch the App will scan for Slates. \nThe discovered Slates will be added to the devices list on the right.\n[block:image]\n{\n  \"images\": [\n    {\n      \"image\": [\n        \"https://files.readme.io/af8a31f-last1.PNG\",\n        \"last1.PNG\",\n        2048,\n        1536,\n        \"#f4faf4\"\n      ]\n    }\n  ]\n}\n[/block]\nWhen a Slate is selected, the App will connect to it and some Slate information like the name et the battery level.\n[block:image]\n{\n  \"images\": [\n    {\n      \"image\": [\n        \"https://files.readme.io/02c52f3-last2.PNG\",\n        \"last2.PNG\",\n        2048,\n        1536,\n        \"#172330\"\n      ]\n    }\n  ]\n}\n[/block]","excerpt":"","slug":"magicbeep-example-on-ios","type":"basic","title":"MagicBeep example on iOS"}

MagicBeep example on iOS


# MagicBeep # This is a quick start to using the ISKN API on Xcode. At the end of this tutorial, the developer should be capable to create an iOS application based on the ISKN API and master the most important concepts about the API architecture and usage. This involves listing the available slates, connecting to a slate, requesting information about the slate as well as subscribing to the ISKN services and decoding slate data. The following tutorial assumes that the developer has already installed the latest version of Xcode. So before you start, be sure you have your development environment set up. This is a simple sound player app using the ISKN Slate. The application detects the presence of a pen and plays different beep sounds when the pen enters or leaves the Slate field of view. Note that you can find __the full source code__ for this example in the ISKN_API examples folder. ## 1.Set Up Your Project In this example you need to create a __Single View Application__. You can specify _MagicBeep_ as a project name. Link the ISKN API to your project. To do so you can see the first tutorial [here](getting-started-with-iskn-api-on-ios). In addition to the ISKN API,you need to add three iOS frameworks to the application : CoreBluetooth.framework, UIKit.framework and AudioToolbox.framework. The CoreBluetooth framework provides the resources your iOS apps need to communicate with devices that are equipped with Bluetooth low energy (BLE) technology like the ISKN Slate. The UIKit framework (UIKit.framework) provides the crucial infrastructure needed to construct and manage iOS apps. The AudioToolbox framework provides interfaces for recording, playback, and stream parsing. [block:image] { "images": [ { "image": [ "https://files.readme.io/i5L3E0iNSJaRiH28J3Hi_Xcode_s2_Buildphases.png", "Xcode_s2_Buildphases.png", "880", "297", "#813817", "" ] } ] } [/block] Now Add a C++ file with a header file to the MagicBeep folder to do so: + Select the MagicBeep folder and right click on it. Select __New File...__ [block:image] { "images": [ { "image": [ "https://files.readme.io/ZLhCuGXwQE6CfSMi2E9c_Xcode_s2_newFile.png", "Xcode_s2_newFile.png", "300", "120", "#2e64ab", "" ] } ] } [/block] + Select iOS then choose C++ file and click __Next__ [block:image] { "images": [ { "image": [ "https://files.readme.io/e3809bc-Picture1.png", "Picture1.png", 1466, 1056, "#edeeed" ] } ] } [/block] + Specify MagicBeep as a name and check __Also create a header file__ option then click __Next__ [block:image] { "images": [ { "image": [ "https://files.readme.io/8mjCGEBlR7GgxHcpA4a9_Xcode_s2_cppFile_options.png", "Xcode_s2_cppFile_options.png", "736", "432", "#3268ad", "" ] } ] } [/block] + Select __Create__ on the next Window. Xcode generates a header file 'MagicBeep.h' and a source file 'MagicBeep.cpp' under the MagicBeep folder. Double click on the MagicBeep.cpp file and change the extension from cpp to mm. Now your MagicBeep folder should look like this : [block:image] { "images": [ { "image": [ "https://files.readme.io/9b4e3a7-Picture2.png", "Picture2.png", 546, 442, "#f1f1f2" ] } ] } [/block] Since the ISKN API is a C++ library you need to mix C++ and Objective-C in the MagicBeep Files. By renaming the MagicBeep.cpp file to have a .mm extension you tell the compiler that this file combine the Objective-C and the C++ languages. ## 2.Including the ISKN API main header file Add a Header Search Path for the ISKN API header. To do so you can see the first tutorial [here](md_src_example_ios_s1.html). Include ISKN_API.h file in of the MagicBeep.h file : [block:code] { "codes": [ { "code": "#include \"ISKN_API.h\"", "language": "cplusplus" } ] } [/block] Since the MagicBeep class should interact with both the graphical interface and the Audio service. We need to import the `AudioToolbox.h` file as well as the `ViewController.h` file : [block:code] { "codes": [ { "code": "#import <AudioToolbox/AudioToolbox.h>\n#import \"ViewController.h\"", "language": "cplusplus" } ] } [/block] Create a C++ class with MagicBeep as name in the MagicBeep.h. Then add a reference to the ViewController class. This reference is used to interact with the graphical interface : [block:code] { "codes": [ { "code": "class MagicBeep \n{\n \npublic:\n MagicBeep(ViewController *viewController);\n \n ViewController *viewController;\n};", "language": "cplusplus" } ] } [/block] In the MagicBeep.mm, add MagicBeep constructor implementation. The constructor takes as a parameter a pointer to a ViewController. It saves this reference in the internal attribute viewController : [block:code] { "codes": [ { "code": "MagicBeep::MagicBeep(ViewController *viewController)\n{\n // Get a pointer to the view controller\n this->viewController=viewController; \n}", "language": "cplusplus" } ] } [/block] The viewController pointer allows access to the project ViewController. ## 3.Preparing the event listener class To receive the Slate events, you need to register a listener. In this example, the MagicBeep class extends the Listener class. [block:code] { "codes": [ { "code": "class MagicBeep : public Listener", "language": "cplusplus" } ] } [/block] The listener class is an interface providing the following methods : [block:code] { "codes": [ { "code": "virtual void processEvent(ISKN_API::Event &e, unsigned int timecode)=0;\nvirtual void connectionStatusChanged(bool connected)=0;", "language": "cplusplus" } ] } [/block] Those methods __should be implemented__ by the subclass in order to receive the slate events. At this point, the MagicBeep listener class is ready to be registered. ## 4.Preparing the communication tools Before registering the listener, we need to create the Slate manager object. To do so, add those attributes to your MagicBeep class declaration : [block:code] { "codes": [ { "code": "// ISKN API attributes\n SlateManager *iskn_SlateManager;", "language": "cplusplus" } ] } [/block] In the constructor method of the MagicBeep class, create the slate manager object : [block:code] { "codes": [ { "code": " // Create slate manager\n iskn_SlateManager = new SlateManager();", "language": "cplusplus" } ] } [/block] ## 5. Registering the events listener Once the slate manager is created, it is possible to register the MagicBeep class as a listener. To do so, use the **registerListener** method of the slate manager in MagicBeep constructor : [block:code] { "codes": [ { "code": "//Register the MagicBeep class as a Listener\n \tiskn_SlateManager->registerListener(this) ;", "language": "cplusplus" } ] } [/block] ## 6. Scan for the Slates To scan for the Slates, the MagicBeep class needs to extend the **BleScanListener** class. [block:code] { "codes": [ { "code": "class MagicBeep :public Listener, BleScanListener", "language": "cplusplus" } ] } [/block] The **BleScanListener** class is an interface providing three methods that should be implemented by the MagicBeep class: [block:code] { "codes": [ { "code": "virtual void newDeviceFound(CBPeripheral *p_device)=0;\nvirtual void notify(ScannerEvent evt)=0;\nvirtual void scanFinished()=0;", "language": "cplusplus" } ] } [/block] To launch the scan for the Slates, use the **startScan** method. [block:code] { "codes": [ { "code": "// Scan for devices\n iskn_SlateManager->startScan(this);", "language": "cplusplus" } ] } [/block] When a Slate is discovered, the **newDeviceFound** method is called.This methods takes a Bluetooth device as parameter. The discovered Slate can be added to a list of discovered devices. [block:code] { "codes": [ { "code": " void MagicBeep::newDeviceFound(CBPeripheral *p_device)\n{\n NSLog(@\"Device found %@\",p_device.name);\n [viewController.myData addObject:p_device.name];\n [viewController.devicesList reloadData]; \n}", "language": "cplusplus" } ] } [/block] Once a Slate is selected from the devices list, the **deviceSelected** method is called. the later stops the scan, retrieves the Slate instance and try to connect to it via the **connect** method. [block:code] { "codes": [ { "code": "void deviceSelected(int deviceID)\n{\n magicBeep->iskn_SlateManager->stopScan();\n CBPeripheral *p_device =magicBeep->iskn_SlateManager->getDeviceByID(deviceID);\n magicBeep->iskn_SlateManager->connect(p_device);\n [magicBeep->viewController.devicesList setHidden:YES];\n}", "language": "cplusplus" } ] } [/block] When the Slate is connected, the **connectionStatusChanged** method is called : [block:code] { "codes": [ { "code": "// Connection status has changed\nvoid MagicBeep::connectionStatusChanged(bool connected)\n{\n if(connected){\n // Request Slate description\n iskn_SlateManager.request(REQ_DESCRIPTION);\n \n // Subscribe to events (Status, Pen Status, Function Call and Pen_3D)\n \n iskn_SlateManager.subscribe(\n AUTO_STATUS |\n AUTO_SOFTWARE_EVENTS |\n AUTO_HARDWARE_EVENTS |\n AUTO_PEN_3D\n ) ;\n \n addTextToView(@\"[Connected]\\n\");\n NSLog(@\"[Connected]\\n\");\n }\n else\n {\n addTextToView(@\"[Could not connect]\\n\");\n NSLog(@\"[Could not connect]\\n\");\n }\n}", "language": "cplusplus" } ] } [/block] In this example, we request the Slate description.It gathers specific Slate information such as Slate name, the size of the Slate, the writing zone of the Slate. This is performed by the **request** method of the SlateManager class. Finally, we subscribe to automatic events services. This tells the Slate which events the MagicBeep class should receive. So we subscribe to four types of events : + AUTO_STATUS : Asks to receive slate status changes like Battery level. + AUTO_SOFTWARE_EVENTS : Asks to receive Software events like object status changes. (Object recognised (SE_OBJECT_IN), object lost(SE_OBJECT_OUT), handshake event (a periodic event used to detect that the Slate is still on)). + AUTO_HARDWARE_EVENTS : Asks to receive Hardware events like a pressed button. + AUTO_PEN_2D : Asks to receive the Pen tip 2D position and contact status at a 140Hz frequency when the pen is in the field of view of the slate. ## 7. Receive and extract events The processEvent method is called whenever a new event is received from the Slate. Use the type attribute of the Event object in order to figure out the event type. You can use a switch case statement as follow : [block:code] { "codes": [ { "code": "switch (event.Type)\n {\n case EVT_STATUS :\n {\n //Slate status change detected\n }\n break ;\n \n case EVT_PEN_2D :\n {\n // New pen position and contact received\n }\n break ;\n \n case EVT_HARDWARE :\n {\n \t\t\t//A hardware event happened \n \t\t\tEventHardware &ev=event.HardwareEvent ;\n switch (ev.getHardwareEventType())\n {\n case HE_BUTTON1_PRESSED :\n Button 1 is pressed\n break ;\n case HE_BUTTON2_PRESSED :\n \t Button 2 is pressed\n break ;\n default :\n break ;\n }\n }\n break ;\n \n case EVT_DESCRIPTION :\n {\n \tEvent received after description request\n }\n break ;\n \n case EVT_SOFTWARE :\n {\n \t//A software event has happened\n \t\n EventSoftware &ev=event.SoftwareEvent ;\n \n switch (ev.getSoftwareEventType())\n {\n case SE_OBJECT_IN :\n {\n // A new object is detected\n }\n break ;\n case SE_OBJECT_OUT :\n {\n // Object lost\n }\n }\n }\n break ;\n \n default :\n \n break ;\n }", "language": "cplusplus" } ] } [/block] ## 8. Add a C wrapper to connect the objective-C and the C++ In order to link the view controller (Objective-C) to the MagicBeep class (C++), we use C function Wrappers. The first function `launchMagicBeep(ViewController *viewController)` is used to construct an instance of the MagicBeep class. The instance is declared in the MagicBeep.mm source file: [block:code] { "codes": [ { "code": "MagicBeep * magicBeep ;", "language": "cplusplus" } ] } [/block] The wrapper function is preceded by the `extern "C"` statement in order to specify that it is a C function. [block:code] { "codes": [ { "code": "extern \"C\"\nvoid launchMagicBeep(ViewController *viewController)\n{\ntry\n{\nmagicBeep=new MagicBeep(viewController);\n}\ncatch (Error &err)\n{\nNSLog(@\"Error\");\n}\n}", "language": "cplusplus" } ] } [/block] The wrapper function is called when the view is loaded. First in the `ViewController.m` file, add a prototype definition for the `launchMagicBeep` function. [block:code] { "codes": [ { "code": "extern void launchMagicBeep(ViewController* viewController) ;", "language": "cplusplus" } ] } [/block] Then call `launchMagicBeep` in the viewDidLoad method of your ViewController : [block:code] { "codes": [ { "code": "launchMagicBeep(self) ;", "language": "cplusplus" } ] } [/block] Now, the MagicBeep class has direct access to any synthesized property of the viewController. ## 9. Preparing the Storyboard In this application we use a simple interface with a `TextView`, a `Table view` to list the scanned slates and `Toolbar` with a single text item and an activity indicator to tell when the application is connecting to the Slate. Create outlets for the TextView, the item, the Table view and the activityIndicator, in the `ViewController.h`: [block:code] { "codes": [ { "code": "@interface ViewController : UIViewController<UITableViewDataSource,UITableViewDelegate>\n{\n NSMutableArray *myData;\n}\n@property NSMutableArray *myData;\n@property (weak, nonatomic) IBOutlet UITextView *mainText;\n@property (weak, nonatomic) IBOutlet UIBarButtonItem *connectionStatus;\n@property (weak, nonatomic) IBOutlet UIActivityIndicatorView *activityIndicator;\n@property (weak, nonatomic) IBOutlet UITableView *devicesList;\n\n@end", "language": "objectivec" } ] } [/block] Now, synthesise them in the `ViewController.m` : [block:code] { "codes": [ { "code": "@synthesize mainText;\n@synthesize connectionStatus;\n@synthesize activityIndicator;\n@synthesize devicesList;\n@synthesize myData;", "language": "objectivec" } ] } [/block] At this stage, the interface can be accessed by the MagicBeep class. ## 10. Interacting with the interface Add a method `addTextToView(NSString *str)` to the MagicBeep class. This method adds a string to the textview : [block:code] { "codes": [ { "code": "\tvoid MagicBeep::addTextToView(NSString *str)\n\t{\n\t\tviewController.mainText.text=[viewController.mainText.text stringByAppendingString:str] ;\n\t\tNSLog(@\"%@\", str) ;\n\t}", "language": "cplusplus" } ] } [/block] Now use this function to notify the user about all events that are received. Here how to call the addTextToView method from the `processEvent` method: [block:code] { "codes": [ { "code": "\tswitch (event.Type)\n\t\t{\n\t\t\tcase EVT_STATUS :\n\t\t\t{\n\t\t\t\tEventStatus &ev=event.Status ;\n\t\t\t\tint bat=ev.getBattery() ;\n\t\t\t\taddTextToView([NSString stringWithFormat:@\"Battery %d\\n\", bat]) ;\n\t\t\t}\n\t\t\tbreak ;\n\t\t\n\t\t\tcase EVT_HARDWARE :\n\t\t\t{\n\t\t\t\tEventHardware &ev=event.HardwareEvent ;\n\t\t\t\tswitch (ev.getHardwareEventType())\n\t\t\t\t{\n\t\t\t\tcase HE_BUTTON1_PRESSED :\n\t\t\t\taddTextToView([NSString stringWithFormat:@\"Button 1 pressed\\n\"]) ;\n\t\t\t\tbreak ;\n\t\t\t\tcase HE_BUTTON2_PRESSED :\n\t\t\t\taddTextToView([NSString stringWithFormat:@\"Button 2 pressed\\n\"]) ;\n\t\t\t\tbreak ;\n case HE_BUTTON1_LONGPRESS:\n addTextToView([NSString stringWithFormat:@\"Button 1 long pressed\\n\"]) ;\n break;\n case HE_BUTTON2_LONGPRESS:\n addTextToView([NSString stringWithFormat:@\"Button 2 long pressed\\n\"]) ;\n break;\n\t\t\t\tdefault :\n\t\t\t\tbreak ;\n\t\t\t\t}\n\t\t\t}\n\t\t\tbreak ;\n\n\t\t\tcase EVT_DESCRIPTION :\n\t\t\t{\n\t\t\t\tEventDescription &ev=event.Description ;\n NSString *nss_deviceName = [NSString stringWithUTF8String:ev.getDeviceName()];\n \n [viewController.connectionStatus setTitle:[@\"Connected to Slate \" stringByAppendingString: nss_deviceName]];\n\n addTextToView([NSString stringWithFormat:@\"Connected to Slate : %@\\n\", nss_deviceName]) ;\n\t\t\t}\n\t\t\tbreak ;\n\t\t\t\n\t\t\tcase EVT_SOFTWARE :\n\t\t\t{\n\t\t\t\tEventSoftware &ev=event.SoftwareEvent ;\n\t\t\t\tint p=ev.getObjectID() ;\n\t\t\t\tswitch (ev.getSoftwareEventType())\n\t\t\t\t{\n\t\t\t\tcase SE_OBJECT_IN :\n\t\t\t\t{\n\t\t\t\taddTextToView([NSString stringWithFormat:@\"Object in \\n\"]) ;\n\t\t\t\t}\n\t\t\t\tbreak ;\n\t\t\t\tcase SE_OBJECT_OUT :\n\t\t\t\t{\n\t\t\t\taddTextToView([NSString stringWithFormat:@\"Object out \\n\"]) ;\n\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\tbreak ;\n\n\t\t\tdefault :\n\t\t\tbreak ;\n\t\t}", "language": "cplusplus" } ] } [/block] ## 11. Animate the activityIndicator To indicate that the application is connecting to the Slate, we add the following line to the constructor of the MagicBeep class : [block:code] { "codes": [ { "code": "[viewController.activityIndicator startAnimating];", "language": "cplusplus" } ] } [/block] The animation should be stopped and the indicator should disappear when the connection succeeds. Add the following code to the `connectionStatusChanged` method, in the if(connected) scope : [block:code] { "codes": [ { "code": "viewController.activityIndicator.hidesWhenStopped=true;\n[viewController.activityIndicator stopAnimating];", "language": "cplusplus" } ] } [/block] ## 12. Play the Beep sound This application plays a simple tone when a pen enters in the slate field of view. In this example, three Wave files are added to the project :Beep.wav,Beep 2.wav and Beep 3.wav in new group called Sounds. [block:image] { "images": [ { "image": [ "https://files.readme.io/9bWVHNXfTE68wEMcZESP_Xcode_s2_Sounds.png", "Xcode_s2_Sounds.png", "263", "412", "#1f53a1", "" ] } ] } [/block] Add the definition of the sounds to the MagicBeep constructor : [block:code] { "codes": [ { "code": "//Create first sound path\nNSURL *soundURL1=[NSURL fileURLWithPath:[[NSBundle mainBundle] pathForResource:@\"Beep\" ofType:@\"wav\"]];\n// Create the first sound \nAudioServicesCreateSystemSoundID((__bridge CFURLRef) soundURL1, &beepTone1);\n \n//Create second sound path \nNSURL *soundURL2=[NSURL fileURLWithPath:[[NSBundle mainBundle] pathForResource:@\"Beep 2\" ofType:@\"wav\"]]; \n// Create the second sound \nAudioServicesCreateSystemSoundID((__bridge CFURLRef) soundURL2, &beepTone2);\n \n//Create third sound path \nNSURL *soundURL3=[NSURL fileURLWithPath:[[NSBundle mainBundle] pathForResource:@\"Beep 3\" ofType:@\"wav\"]]; \n// Create the third sound \nAudioServicesCreateSystemSoundID((__bridge CFURLRef) soundURL3, &beepTone3);", "language": "cplusplus" } ] } [/block] Add playSound(int soundID) method to the MagicBeep class which plays a different sound when pen is detected. [block:code] { "codes": [ { "code": "void MagicBeep::playSound(int soundID)\n{\n switch (soundID)\n {\n case 1:\n {\n AudioServicesPlaySystemSound(beepTone1);\n }\n break ;\n \n case 2:\n {\n AudioServicesPlaySystemSound(beepTone2);\n }\n break ;\n \n default:\n {\n AudioServicesPlaySystemSound(beepTone3);\n }\n break ;\n \n }\n}", "language": "cplusplus" } ] } [/block] Now the sound is ready to be played. You can play the sound when the pen is in the Slate field of view by using the playSound method : [block:code] { "codes": [ { "code": "case EVT_SOFTWARE : \n{ \n\tEventSoftware &ev=event.SoftwareEvent ;\n\tint p=ev.getObjectID() ;\n \n\tswitch (ev.getSoftwareEventType()) \n\t{ \n\t\tcase SE_OBJECT_IN : \n\t\t{ \n\t\t\taddTextToView([NSString stringWithFormat:@\"Object in \\n\"]) ;\n playSound(1); \n\t\t} \n\t\t\tbreak ; \n\t\tcase SE_OBJECT_OUT : \n\t\t{ \n\t\t\t addTextToView([NSString stringWithFormat:@\"Object out \\n\"]) ;\n playSound(2); \n\t\t}\n\t\t\tbreak; \n\t} \n} \n\tbreak ;", "language": "cplusplus" } ] } [/block] To sum up your MagicBeep.h and your MagicBeep.mm files should be like this: MagicBeep.h file : [block:code] { "codes": [ { "code": "//\n// MagicBeep.h\n// MagicBeep\n//\n// Created by ALOUI Rabeb on 08/02/15.\n// Copyright (c) 2015 ISKN. All rights reserved.\n//\n\n#ifndef __MagicBeep__MagicBeep__\n#define __MagicBeep__MagicBeep__\n\n#include <ISKN_API.h>\n#import <AudioToolbox/AudioToolbox.h>\n#import \"ViewController.h\"\n\n\nusing namespace ISKN_API;\n\nclass MagicBeep :public Listener, BleScanListener\n{\n \npublic:\n \n // ISKN API attributes\n SlateManager *iskn_SlateManager;\n \n // Application specific attributes\n SystemSoundID beepTone1,beepTone2,beepTone3;\n ViewController *viewController;\n \n // Constructor\n MagicBeep(ViewController *viewController);\n \n // Inherited methods\n \n // Listener\n void connectionStatusChanged(bool connected);\n void processEvent(ISKN_API::Event &event, unsigned int timecode);\n \n // BleScanListener\n void newDeviceFound(CBPeripheral *p_device);\n void notify(ScannerEvent evt);\n void scanFinished();\n \n // Application specific methods\n void addTextToView(NSString *str);\n void playSound(int soundID);\n};\n\n\n#endif /* defined(__MagicBeep__MagicBeep__) */", "language": "cplusplus" } ] } [/block] MagicBeep.mm file : [block:code] { "codes": [ { "code": "//\n// MagicBeep.cpp\n// MagicBeep\n//\n// Created by ALOUI Rabeb on 08/02/15.\n// Copyright (c) 2015 ISKN. All rights reserved.\n//\n\n#include \"MagicBeep.h\"\n\nMagicBeep * magicBeep ;\n\n\n// Cpp/Objective-C Wrapper function\n\nextern \"C\"\n{\n void launchMagicBeep(ViewController *viewController)\n {\n try\n {\n magicBeep=new MagicBeep(viewController);\n }\n catch (Error &err)\n {\n NSLog(@\"Error\");\n }\n }\n\n void deviceSelected(int deviceID)\n {\n magicBeep->iskn_SlateManager->stopScan();\n CBPeripheral *p_device =magicBeep->iskn_SlateManager->getDeviceByID(deviceID);\n magicBeep->iskn_SlateManager->connect(p_device);\n [magicBeep->viewController.devicesList setHidden:YES];\n \n }\n}\n\n//MagicBeep constructor\nMagicBeep::MagicBeep(ViewController *viewController)\n{\n // Get a pointer to the ViewController\n this->viewController=viewController;\n \n // Create slate manager\n iskn_SlateManager = new SlateManager();\n \n //Register the MagicBeep class as a Listener\n iskn_SlateManager->registerListener(this) ;\n \n \n addTextToView(@\"Scan for ISKN Slates...\\n\");\n \n // Scan for devices\n iskn_SlateManager->startScan(this);\n \n [viewController.activityIndicator startAnimating];\n \n //Create first sound path\n NSURL *soundURL1=[NSURL fileURLWithPath:[[NSBundle mainBundle] pathForResource:@\"Beep\" ofType:@\"wav\"]];\n // Create the first sound\n AudioServicesCreateSystemSoundID((__bridge CFURLRef) soundURL1, &beepTone1);\n \n \n //Create second sound path\n NSURL *soundURL2=[NSURL fileURLWithPath:[[NSBundle mainBundle] pathForResource:@\"Beep 2\" ofType:@\"wav\"]];\n // Create the second sound\n AudioServicesCreateSystemSoundID((__bridge CFURLRef) soundURL2, &beepTone2);\n \n \n //Create third sound path\n NSURL *soundURL3=[NSURL fileURLWithPath:[[NSBundle mainBundle] pathForResource:@\"Beep 3\" ofType:@\"wav\"]];\n // Create the third sound\n AudioServicesCreateSystemSoundID((__bridge CFURLRef) soundURL3, &beepTone3);\n \n}\n// newDeviceFound function\n\nvoid MagicBeep::newDeviceFound(CBPeripheral *p_device)\n{\n NSLog(@\"Device found %@\",p_device.name);\n [viewController.myData addObject:p_device.name];\n [viewController.devicesList reloadData];\n}\n\n// connectionStatusChanged function \n\nvoid MagicBeep::connectionStatusChanged(bool connected)\n{\n if(connected){\n // Request Slate description\n iskn_SlateManager->request(REQ_DESCRIPTION);\n \n // Subscribe to events (Status, Software events, Hardware events and Pen 2D event)\n iskn_SlateManager->subscribe(\n AUTO_STATUS |\n AUTO_SOFTWARE_EVENTS |\n AUTO_HARDWARE_EVENTS |\n AUTO_PEN_2D\n ) ;\n \n viewController.activityIndicator.hidesWhenStopped=true;\n [viewController.activityIndicator stopAnimating];\n \n NSLog(@\"[Connected]\\n\");\n }\n else\n {\n addTextToView(@\"[Could not connect]\\n\");\n NSLog(@\"[Could not connect]\\n\");\n }\n}\n\n// processEvent function\n\nvoid MagicBeep::processEvent(Event &event, unsigned int timecode)\n{\n switch (event.Type)\n {\n case EVT_STATUS :\n {\n EventStatus &ev=event.Status ;\n int bat=ev.getBattery() ;\n addTextToView([NSString stringWithFormat:@\"Battery %d\\n\", bat]) ;\n }\n break ;\n \n case EVT_PEN_2D :\n {\n EventPen2D &ev=event.Pen2D ;\n Vector2D po=ev.getPosition() ;\n NSLog(@\"%@\", [NSString stringWithFormat:@\"EvtPen2D : %d : (%f , %f)\\n\", ev.Touch() ? 1 : 0, po.X, po.Y]) ;\n }\n break ;\n \n case EVT_HARDWARE :\n {\n EventHardware &ev=event.HardwareEvent ;\n switch (ev.getHardwareEventType())\n {\n case HE_BUTTON1_PRESSED :\n addTextToView([NSString stringWithFormat:@\"Button 1 pressed\\n\"]) ;\n break ;\n case HE_BUTTON2_PRESSED :\n addTextToView([NSString stringWithFormat:@\"Button 2 pressed\\n\"]) ;\n break ;\n case HE_BUTTON1_LONGPRESS:\n addTextToView([NSString stringWithFormat:@\"Button 1 long pressed\\n\"]) ;\n break;\n case HE_BUTTON2_LONGPRESS:\n addTextToView([NSString stringWithFormat:@\"Button 2 long pressed\\n\"]) ;\n break;\n default :\n break ;\n }\n }\n break ;\n \n case EVT_DESCRIPTION :\n {\n EventDescription &ev=event.Description ;\n NSString *nss_deviceName = [NSString stringWithUTF8String:ev.getDeviceName()];\n \n [viewController.connectionStatus setTitle:[@\"Connected to Slate \" stringByAppendingString: nss_deviceName]];\n\n addTextToView([NSString stringWithFormat:@\"Connected to Slate : %@\\n\", nss_deviceName]) ;\n }\n break ;\n \n \n case EVT_SOFTWARE :\n {\n EventSoftware &ev=event.SoftwareEvent ;\n \n switch (ev.getSoftwareEventType())\n {\n case SE_OBJECT_IN :\n {\n addTextToView([NSString stringWithFormat:@\"Object in \\n\"]) ;\n playSound(1);\n }\n break ;\n case SE_OBJECT_OUT :\n {\n addTextToView([NSString stringWithFormat:@\"Object out \\n\"]) ;\n playSound(2);\n }\n break;\n case SE_HANDSHAKE:\n // Nothing to do\n break;\n \n case SE_UNKNOWN:\n // Nothing to do\n break;\n }\n }\n break ;\n \n default :\n break ;\n }\n \n}\n\n// addTextToView function\n\nvoid MagicBeep::addTextToView(NSString *str)\n{\n viewController.mainText.text=[viewController.mainText.text stringByAppendingString:str] ;\n NSLog(@\"%@\", str) ;\n}\n\n// playSound function\n\nvoid MagicBeep::playSound(int soundID)\n{\n switch (soundID)\n {\n case 1:\n {\n AudioServicesPlaySystemSound(beepTone1);\n }\n break ;\n \n case 2:\n {\n AudioServicesPlaySystemSound(beepTone2);\n }\n break ;\n \n default:\n {\n AudioServicesPlaySystemSound(beepTone3);\n }\n break ;\n \n }\n}\nvoid MagicBeep::notify(ScannerEvent evt)\n{\n switch(evt){\n case BLESCANNER_EVENT_NONE:\n //...\n break;\n case BLESCANNER_EVENT_ACTIVATION_REQUIRED:\n NSLog(@\"Notification received\");\n break;\n case BLESCANNER_EVENT_BLE_NOT_SUPPORTED:\n NSLog(@\"BLE not supported\");\n break;\n case BLESCANNER_EVENT_BLE_SCAN_STARTED:\n NSLog(@\"Scan started\");\n break;\n \n }\n \n}\nvoid MagicBeep::scanFinished()\n{\n NSLog(@\"Scan finished\"); \n}", "language": "cplusplus" } ] } [/block] ## 13. Run your project Your project is now ready to run. At launch the App will scan for Slates. The discovered Slates will be added to the devices list on the right. [block:image] { "images": [ { "image": [ "https://files.readme.io/af8a31f-last1.PNG", "last1.PNG", 2048, 1536, "#f4faf4" ] } ] } [/block] When a Slate is selected, the App will connect to it and some Slate information like the name et the battery level. [block:image] { "images": [ { "image": [ "https://files.readme.io/02c52f3-last2.PNG", "last2.PNG", 2048, 1536, "#172330" ] } ] } [/block]