├── Brainwaves ├── Brainwaves.xcodeproj │ ├── project.pbxproj │ ├── project.xcworkspace │ │ ├── contents.xcworkspacedata │ │ └── xcuserdata │ │ │ └── Nikhil.xcuserdatad │ │ │ └── UserInterfaceState.xcuserstate │ └── xcuserdata │ │ └── Nikhil.xcuserdatad │ │ ├── xcdebugger │ │ └── Breakpoints_v2.xcbkptlist │ │ └── xcschemes │ │ ├── Brainwaves.xcscheme │ │ └── xcschememanagement.plist ├── Brainwaves.xcworkspace │ ├── contents.xcworkspacedata │ └── xcuserdata │ │ └── Nikhil.xcuserdatad │ │ └── UserInterfaceState.xcuserstate ├── Brainwaves │ ├── AppDelegate.swift │ ├── Assets.xcassets │ │ └── AppIcon.appiconset │ │ │ └── Contents.json │ ├── Base.lproj │ │ ├── LaunchScreen.storyboard │ │ └── Main.storyboard │ ├── HomeViewController.swift │ └── Info.plist ├── Podfile ├── Podfile.lock └── Pods │ ├── Alamofire │ ├── LICENSE │ ├── README.md │ └── Source │ │ ├── Alamofire.swift │ │ ├── Download.swift │ │ ├── Error.swift │ │ ├── Manager.swift │ │ ├── MultipartFormData.swift │ │ ├── NetworkReachabilityManager.swift │ │ ├── Notifications.swift │ │ ├── ParameterEncoding.swift │ │ ├── Request.swift │ │ ├── Response.swift │ │ ├── ResponseSerialization.swift │ │ ├── Result.swift │ │ ├── ServerTrustPolicy.swift │ │ ├── Stream.swift │ │ ├── Timeline.swift │ │ ├── Upload.swift │ │ └── Validation.swift │ ├── Manifest.lock │ ├── Pods.xcodeproj │ ├── project.pbxproj │ └── xcuserdata │ │ └── Nikhil.xcuserdatad │ │ └── xcschemes │ │ ├── Alamofire.xcscheme │ │ ├── Pods-Brainwaves.xcscheme │ │ └── xcschememanagement.plist │ └── Target Support Files │ ├── Alamofire │ ├── Alamofire-Private.xcconfig │ ├── Alamofire-dummy.m │ ├── Alamofire-prefix.pch │ ├── Alamofire-umbrella.h │ ├── Alamofire.modulemap │ ├── Alamofire.xcconfig │ └── Info.plist │ └── Pods-Brainwaves │ ├── Info.plist │ ├── Pods-Brainwaves-acknowledgements.markdown │ ├── Pods-Brainwaves-acknowledgements.plist │ ├── Pods-Brainwaves-dummy.m │ ├── Pods-Brainwaves-frameworks.sh │ ├── Pods-Brainwaves-resources.sh │ ├── Pods-Brainwaves-umbrella.h │ ├── Pods-Brainwaves.debug.xcconfig │ ├── Pods-Brainwaves.modulemap │ └── Pods-Brainwaves.release.xcconfig ├── README.md ├── emokit ├── .gitignore ├── CMakeLists.txt ├── FAQ.md ├── INSTALL ├── LICENSE ├── README.md ├── cmake_modules │ ├── FindHIDAPI.cmake │ ├── FindMcrypt.cmake │ └── Findlibusb-1.0.cmake ├── doc │ ├── Announcement.md │ ├── emotiv_protocol.asciidoc │ └── usbinfo.txt ├── examples │ ├── contact │ │ ├── CMakeLists.txt │ │ └── contact.c │ ├── emokit_osc │ │ ├── CMakeLists.txt │ │ ├── Findoscpack.cmake │ │ ├── emokit_osc.cpp │ │ └── pd │ │ │ └── emokit-osc.pd │ └── emokitd │ │ ├── CMakeLists.txt │ │ ├── emokitd.c │ │ └── emokitd.h ├── include │ └── emokit │ │ └── emokit.h ├── linux │ └── epoc.rules ├── python │ ├── MANIFEST.in │ ├── Makefile │ ├── dist │ │ └── emokit-0.0.1-py2.7.egg │ ├── emokit.egg-info │ │ ├── PKG-INFO │ │ ├── SOURCES.txt │ │ ├── dependency_links.txt │ │ ├── not-zip-safe │ │ ├── requires.txt │ │ └── top_level.txt │ ├── emokit │ │ ├── Makefile-manual │ │ ├── Makefile.am │ │ ├── __init__.py │ │ ├── cv.py │ │ ├── cv2.so │ │ ├── data.txt │ │ ├── emotiv.py │ │ ├── hid.c │ │ ├── hid.o │ │ ├── hidapi.h │ │ └── src │ │ │ └── pip-delete-this-directory.txt │ ├── example.py │ ├── mouse_control.py │ ├── render.py │ ├── requirements.txt │ ├── setup.py │ └── tests │ │ └── test_emokit.py └── src │ ├── CMakeLists.txt │ └── emokit.c └── scripts ├── brainwaves-script ├── data.txt └── ngrok /Brainwaves/Brainwaves.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /Brainwaves/Brainwaves.xcodeproj/project.xcworkspace/xcuserdata/Nikhil.xcuserdatad/UserInterfaceState.xcuserstate: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nikhiljay/brainwaves/42d96dccedf09504589fc9e14e3b470de7f5c0b2/Brainwaves/Brainwaves.xcodeproj/project.xcworkspace/xcuserdata/Nikhil.xcuserdatad/UserInterfaceState.xcuserstate -------------------------------------------------------------------------------- /Brainwaves/Brainwaves.xcodeproj/xcuserdata/Nikhil.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | -------------------------------------------------------------------------------- /Brainwaves/Brainwaves.xcodeproj/xcuserdata/Nikhil.xcuserdatad/xcschemes/Brainwaves.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 32 | 33 | 39 | 40 | 41 | 42 | 43 | 44 | 54 | 56 | 62 | 63 | 64 | 65 | 66 | 67 | 73 | 75 | 81 | 82 | 83 | 84 | 86 | 87 | 90 | 91 | 92 | -------------------------------------------------------------------------------- /Brainwaves/Brainwaves.xcodeproj/xcuserdata/Nikhil.xcuserdatad/xcschemes/xcschememanagement.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | SchemeUserState 6 | 7 | Brainwaves.xcscheme 8 | 9 | orderHint 10 | 0 11 | 12 | 13 | SuppressBuildableAutocreation 14 | 15 | 3152ED441CAEF0D3001BD663 16 | 17 | primary 18 | 19 | 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /Brainwaves/Brainwaves.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /Brainwaves/Brainwaves.xcworkspace/xcuserdata/Nikhil.xcuserdatad/UserInterfaceState.xcuserstate: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nikhiljay/brainwaves/42d96dccedf09504589fc9e14e3b470de7f5c0b2/Brainwaves/Brainwaves.xcworkspace/xcuserdata/Nikhil.xcuserdatad/UserInterfaceState.xcuserstate -------------------------------------------------------------------------------- /Brainwaves/Brainwaves/AppDelegate.swift: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.swift 3 | // Brainwaves 4 | // 5 | // Created by Nikhil D'Souza on 4/1/16. 6 | // Copyright © 2016 Nikhil. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | @UIApplicationMain 12 | class AppDelegate: UIResponder, UIApplicationDelegate { 13 | 14 | var window: UIWindow? 15 | 16 | 17 | func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool { 18 | // Override point for customization after application launch. 19 | return true 20 | } 21 | 22 | func applicationWillResignActive(application: UIApplication) { 23 | // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state. 24 | // Use this method to pause ongoing tasks, disable timers, and throttle down OpenGL ES frame rates. Games should use this method to pause the game. 25 | } 26 | 27 | func applicationDidEnterBackground(application: UIApplication) { 28 | // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later. 29 | // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits. 30 | } 31 | 32 | func applicationWillEnterForeground(application: UIApplication) { 33 | // Called as part of the transition from the background to the inactive state; here you can undo many of the changes made on entering the background. 34 | } 35 | 36 | func applicationDidBecomeActive(application: UIApplication) { 37 | // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface. 38 | } 39 | 40 | func applicationWillTerminate(application: UIApplication) { 41 | // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:. 42 | } 43 | 44 | 45 | } 46 | 47 | -------------------------------------------------------------------------------- /Brainwaves/Brainwaves/Assets.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "iphone", 5 | "size" : "29x29", 6 | "scale" : "2x" 7 | }, 8 | { 9 | "idiom" : "iphone", 10 | "size" : "29x29", 11 | "scale" : "3x" 12 | }, 13 | { 14 | "idiom" : "iphone", 15 | "size" : "40x40", 16 | "scale" : "2x" 17 | }, 18 | { 19 | "idiom" : "iphone", 20 | "size" : "40x40", 21 | "scale" : "3x" 22 | }, 23 | { 24 | "idiom" : "iphone", 25 | "size" : "60x60", 26 | "scale" : "2x" 27 | }, 28 | { 29 | "idiom" : "iphone", 30 | "size" : "60x60", 31 | "scale" : "3x" 32 | } 33 | ], 34 | "info" : { 35 | "version" : 1, 36 | "author" : "xcode" 37 | } 38 | } -------------------------------------------------------------------------------- /Brainwaves/Brainwaves/Base.lproj/LaunchScreen.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 30 | 40 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | -------------------------------------------------------------------------------- /Brainwaves/Brainwaves/Base.lproj/Main.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | -------------------------------------------------------------------------------- /Brainwaves/Brainwaves/HomeViewController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // HomeViewController.swift 3 | // Brainwaves 4 | // 5 | // Created by Nikhil D'Souza on 4/1/16. 6 | // Copyright © 2016 Nikhil. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | import Alamofire 11 | import Foundation 12 | 13 | class HomeViewController: UIViewController, UITextFieldDelegate { 14 | 15 | @IBOutlet weak var outputText: UITextView! 16 | @IBOutlet weak var serverTextField: UITextField! 17 | @IBOutlet weak var loadIndicator: UIActivityIndicatorView! 18 | 19 | var serverURL: String! 20 | 21 | override func viewDidLoad() { 22 | super.viewDidLoad() 23 | 24 | loadIndicator.stopAnimating() 25 | serverTextField.delegate = self 26 | repeatRequest() 27 | 28 | } 29 | 30 | func repeatRequest() { 31 | if serverURL != nil { 32 | _ = NSTimer.scheduledTimerWithTimeInterval(1, target: self, selector: #selector(HomeViewController.getRequest), userInfo: nil, repeats: true) 33 | } else { 34 | self.outputText.text = "Enter a server URL!" 35 | } 36 | } 37 | 38 | func getRequest() { 39 | 40 | loadIndicator.stopAnimating() 41 | 42 | Alamofire.request(.GET, serverURL!) 43 | .responseJSON { response in 44 | if let JSON = response.result.value { 45 | 46 | self.outputText.text = "" 47 | 48 | for node in JSON as! [String: AnyObject] { 49 | let nodeData = node.1["value"]! 50 | self.outputText.text! += node.0 + ": " + String(nodeData!) + "\n" 51 | } 52 | 53 | } 54 | 55 | switch response.result { 56 | case .Success: 57 | print("Validation Successful") 58 | case .Failure(let error): 59 | self.outputText.text = String(error) 60 | print(error) 61 | } 62 | } 63 | } 64 | 65 | func textFieldShouldReturn(textField: UITextField) -> Bool { 66 | textField.resignFirstResponder() 67 | serverURL = serverTextField.text 68 | repeatRequest() 69 | loadIndicator.startAnimating() 70 | return true 71 | } 72 | 73 | } 74 | -------------------------------------------------------------------------------- /Brainwaves/Brainwaves/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | APPL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | 1 23 | LSRequiresIPhoneOS 24 | 25 | UILaunchStoryboardName 26 | LaunchScreen 27 | UIMainStoryboardFile 28 | Main 29 | UIRequiredDeviceCapabilities 30 | 31 | armv7 32 | 33 | UISupportedInterfaceOrientations 34 | 35 | UIInterfaceOrientationPortrait 36 | 37 | 38 | 39 | -------------------------------------------------------------------------------- /Brainwaves/Podfile: -------------------------------------------------------------------------------- 1 | platform :ios, '8.0' 2 | use_frameworks! 3 | 4 | target 'Brainwaves' do 5 | pod 'Alamofire', '~> 3.0' 6 | end 7 | 8 | -------------------------------------------------------------------------------- /Brainwaves/Podfile.lock: -------------------------------------------------------------------------------- 1 | PODS: 2 | - Alamofire (3.3.0) 3 | 4 | DEPENDENCIES: 5 | - Alamofire (~> 3.0) 6 | 7 | SPEC CHECKSUMS: 8 | Alamofire: 9054db4a1b1ca9e363223183e01cea380159a27c 9 | 10 | COCOAPODS: 0.38.2 11 | -------------------------------------------------------------------------------- /Brainwaves/Pods/Alamofire/LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2014–2016 Alamofire Software Foundation (http://alamofire.org/) 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy 4 | of this software and associated documentation files (the "Software"), to deal 5 | in the Software without restriction, including without limitation the rights 6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | copies of the Software, and to permit persons to whom the Software is 8 | furnished to do so, subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in 11 | all copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | THE SOFTWARE. 20 | -------------------------------------------------------------------------------- /Brainwaves/Pods/Alamofire/Source/Alamofire.swift: -------------------------------------------------------------------------------- 1 | // Alamofire.swift 2 | // 3 | // Copyright (c) 2014–2016 Alamofire Software Foundation (http://alamofire.org/) 4 | // 5 | // Permission is hereby granted, free of charge, to any person obtaining a copy 6 | // of this software and associated documentation files (the "Software"), to deal 7 | // in the Software without restriction, including without limitation the rights 8 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | // copies of the Software, and to permit persons to whom the Software is 10 | // furnished to do so, subject to the following conditions: 11 | // 12 | // The above copyright notice and this permission notice shall be included in 13 | // all copies or substantial portions of the Software. 14 | // 15 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | // THE SOFTWARE. 22 | 23 | import Foundation 24 | 25 | // MARK: - URLStringConvertible 26 | 27 | /** 28 | Types adopting the `URLStringConvertible` protocol can be used to construct URL strings, which are then used to 29 | construct URL requests. 30 | */ 31 | public protocol URLStringConvertible { 32 | /** 33 | A URL that conforms to RFC 2396. 34 | 35 | Methods accepting a `URLStringConvertible` type parameter parse it according to RFCs 1738 and 1808. 36 | 37 | See https://tools.ietf.org/html/rfc2396 38 | See https://tools.ietf.org/html/rfc1738 39 | See https://tools.ietf.org/html/rfc1808 40 | */ 41 | var URLString: String { get } 42 | } 43 | 44 | extension String: URLStringConvertible { 45 | public var URLString: String { 46 | return self 47 | } 48 | } 49 | 50 | extension NSURL: URLStringConvertible { 51 | public var URLString: String { 52 | return absoluteString 53 | } 54 | } 55 | 56 | extension NSURLComponents: URLStringConvertible { 57 | public var URLString: String { 58 | return URL!.URLString 59 | } 60 | } 61 | 62 | extension NSURLRequest: URLStringConvertible { 63 | public var URLString: String { 64 | return URL!.URLString 65 | } 66 | } 67 | 68 | // MARK: - URLRequestConvertible 69 | 70 | /** 71 | Types adopting the `URLRequestConvertible` protocol can be used to construct URL requests. 72 | */ 73 | public protocol URLRequestConvertible { 74 | /// The URL request. 75 | var URLRequest: NSMutableURLRequest { get } 76 | } 77 | 78 | extension NSURLRequest: URLRequestConvertible { 79 | public var URLRequest: NSMutableURLRequest { 80 | return self.mutableCopy() as! NSMutableURLRequest 81 | } 82 | } 83 | 84 | // MARK: - Convenience 85 | 86 | func URLRequest( 87 | method: Method, 88 | _ URLString: URLStringConvertible, 89 | headers: [String: String]? = nil) 90 | -> NSMutableURLRequest 91 | { 92 | let mutableURLRequest = NSMutableURLRequest(URL: NSURL(string: URLString.URLString)!) 93 | mutableURLRequest.HTTPMethod = method.rawValue 94 | 95 | if let headers = headers { 96 | for (headerField, headerValue) in headers { 97 | mutableURLRequest.setValue(headerValue, forHTTPHeaderField: headerField) 98 | } 99 | } 100 | 101 | return mutableURLRequest 102 | } 103 | 104 | // MARK: - Request Methods 105 | 106 | /** 107 | Creates a request using the shared manager instance for the specified method, URL string, parameters, and 108 | parameter encoding. 109 | 110 | - parameter method: The HTTP method. 111 | - parameter URLString: The URL string. 112 | - parameter parameters: The parameters. `nil` by default. 113 | - parameter encoding: The parameter encoding. `.URL` by default. 114 | - parameter headers: The HTTP headers. `nil` by default. 115 | 116 | - returns: The created request. 117 | */ 118 | public func request( 119 | method: Method, 120 | _ URLString: URLStringConvertible, 121 | parameters: [String: AnyObject]? = nil, 122 | encoding: ParameterEncoding = .URL, 123 | headers: [String: String]? = nil) 124 | -> Request 125 | { 126 | return Manager.sharedInstance.request( 127 | method, 128 | URLString, 129 | parameters: parameters, 130 | encoding: encoding, 131 | headers: headers 132 | ) 133 | } 134 | 135 | /** 136 | Creates a request using the shared manager instance for the specified URL request. 137 | 138 | If `startRequestsImmediately` is `true`, the request will have `resume()` called before being returned. 139 | 140 | - parameter URLRequest: The URL request 141 | 142 | - returns: The created request. 143 | */ 144 | public func request(URLRequest: URLRequestConvertible) -> Request { 145 | return Manager.sharedInstance.request(URLRequest.URLRequest) 146 | } 147 | 148 | // MARK: - Upload Methods 149 | 150 | // MARK: File 151 | 152 | /** 153 | Creates an upload request using the shared manager instance for the specified method, URL string, and file. 154 | 155 | - parameter method: The HTTP method. 156 | - parameter URLString: The URL string. 157 | - parameter headers: The HTTP headers. `nil` by default. 158 | - parameter file: The file to upload. 159 | 160 | - returns: The created upload request. 161 | */ 162 | public func upload( 163 | method: Method, 164 | _ URLString: URLStringConvertible, 165 | headers: [String: String]? = nil, 166 | file: NSURL) 167 | -> Request 168 | { 169 | return Manager.sharedInstance.upload(method, URLString, headers: headers, file: file) 170 | } 171 | 172 | /** 173 | Creates an upload request using the shared manager instance for the specified URL request and file. 174 | 175 | - parameter URLRequest: The URL request. 176 | - parameter file: The file to upload. 177 | 178 | - returns: The created upload request. 179 | */ 180 | public func upload(URLRequest: URLRequestConvertible, file: NSURL) -> Request { 181 | return Manager.sharedInstance.upload(URLRequest, file: file) 182 | } 183 | 184 | // MARK: Data 185 | 186 | /** 187 | Creates an upload request using the shared manager instance for the specified method, URL string, and data. 188 | 189 | - parameter method: The HTTP method. 190 | - parameter URLString: The URL string. 191 | - parameter headers: The HTTP headers. `nil` by default. 192 | - parameter data: The data to upload. 193 | 194 | - returns: The created upload request. 195 | */ 196 | public func upload( 197 | method: Method, 198 | _ URLString: URLStringConvertible, 199 | headers: [String: String]? = nil, 200 | data: NSData) 201 | -> Request 202 | { 203 | return Manager.sharedInstance.upload(method, URLString, headers: headers, data: data) 204 | } 205 | 206 | /** 207 | Creates an upload request using the shared manager instance for the specified URL request and data. 208 | 209 | - parameter URLRequest: The URL request. 210 | - parameter data: The data to upload. 211 | 212 | - returns: The created upload request. 213 | */ 214 | public func upload(URLRequest: URLRequestConvertible, data: NSData) -> Request { 215 | return Manager.sharedInstance.upload(URLRequest, data: data) 216 | } 217 | 218 | // MARK: Stream 219 | 220 | /** 221 | Creates an upload request using the shared manager instance for the specified method, URL string, and stream. 222 | 223 | - parameter method: The HTTP method. 224 | - parameter URLString: The URL string. 225 | - parameter headers: The HTTP headers. `nil` by default. 226 | - parameter stream: The stream to upload. 227 | 228 | - returns: The created upload request. 229 | */ 230 | public func upload( 231 | method: Method, 232 | _ URLString: URLStringConvertible, 233 | headers: [String: String]? = nil, 234 | stream: NSInputStream) 235 | -> Request 236 | { 237 | return Manager.sharedInstance.upload(method, URLString, headers: headers, stream: stream) 238 | } 239 | 240 | /** 241 | Creates an upload request using the shared manager instance for the specified URL request and stream. 242 | 243 | - parameter URLRequest: The URL request. 244 | - parameter stream: The stream to upload. 245 | 246 | - returns: The created upload request. 247 | */ 248 | public func upload(URLRequest: URLRequestConvertible, stream: NSInputStream) -> Request { 249 | return Manager.sharedInstance.upload(URLRequest, stream: stream) 250 | } 251 | 252 | // MARK: MultipartFormData 253 | 254 | /** 255 | Creates an upload request using the shared manager instance for the specified method and URL string. 256 | 257 | - parameter method: The HTTP method. 258 | - parameter URLString: The URL string. 259 | - parameter headers: The HTTP headers. `nil` by default. 260 | - parameter multipartFormData: The closure used to append body parts to the `MultipartFormData`. 261 | - parameter encodingMemoryThreshold: The encoding memory threshold in bytes. 262 | `MultipartFormDataEncodingMemoryThreshold` by default. 263 | - parameter encodingCompletion: The closure called when the `MultipartFormData` encoding is complete. 264 | */ 265 | public func upload( 266 | method: Method, 267 | _ URLString: URLStringConvertible, 268 | headers: [String: String]? = nil, 269 | multipartFormData: MultipartFormData -> Void, 270 | encodingMemoryThreshold: UInt64 = Manager.MultipartFormDataEncodingMemoryThreshold, 271 | encodingCompletion: (Manager.MultipartFormDataEncodingResult -> Void)?) 272 | { 273 | return Manager.sharedInstance.upload( 274 | method, 275 | URLString, 276 | headers: headers, 277 | multipartFormData: multipartFormData, 278 | encodingMemoryThreshold: encodingMemoryThreshold, 279 | encodingCompletion: encodingCompletion 280 | ) 281 | } 282 | 283 | /** 284 | Creates an upload request using the shared manager instance for the specified method and URL string. 285 | 286 | - parameter URLRequest: The URL request. 287 | - parameter multipartFormData: The closure used to append body parts to the `MultipartFormData`. 288 | - parameter encodingMemoryThreshold: The encoding memory threshold in bytes. 289 | `MultipartFormDataEncodingMemoryThreshold` by default. 290 | - parameter encodingCompletion: The closure called when the `MultipartFormData` encoding is complete. 291 | */ 292 | public func upload( 293 | URLRequest: URLRequestConvertible, 294 | multipartFormData: MultipartFormData -> Void, 295 | encodingMemoryThreshold: UInt64 = Manager.MultipartFormDataEncodingMemoryThreshold, 296 | encodingCompletion: (Manager.MultipartFormDataEncodingResult -> Void)?) 297 | { 298 | return Manager.sharedInstance.upload( 299 | URLRequest, 300 | multipartFormData: multipartFormData, 301 | encodingMemoryThreshold: encodingMemoryThreshold, 302 | encodingCompletion: encodingCompletion 303 | ) 304 | } 305 | 306 | // MARK: - Download Methods 307 | 308 | // MARK: URL Request 309 | 310 | /** 311 | Creates a download request using the shared manager instance for the specified method and URL string. 312 | 313 | - parameter method: The HTTP method. 314 | - parameter URLString: The URL string. 315 | - parameter parameters: The parameters. `nil` by default. 316 | - parameter encoding: The parameter encoding. `.URL` by default. 317 | - parameter headers: The HTTP headers. `nil` by default. 318 | - parameter destination: The closure used to determine the destination of the downloaded file. 319 | 320 | - returns: The created download request. 321 | */ 322 | public func download( 323 | method: Method, 324 | _ URLString: URLStringConvertible, 325 | parameters: [String: AnyObject]? = nil, 326 | encoding: ParameterEncoding = .URL, 327 | headers: [String: String]? = nil, 328 | destination: Request.DownloadFileDestination) 329 | -> Request 330 | { 331 | return Manager.sharedInstance.download( 332 | method, 333 | URLString, 334 | parameters: parameters, 335 | encoding: encoding, 336 | headers: headers, 337 | destination: destination 338 | ) 339 | } 340 | 341 | /** 342 | Creates a download request using the shared manager instance for the specified URL request. 343 | 344 | - parameter URLRequest: The URL request. 345 | - parameter destination: The closure used to determine the destination of the downloaded file. 346 | 347 | - returns: The created download request. 348 | */ 349 | public func download(URLRequest: URLRequestConvertible, destination: Request.DownloadFileDestination) -> Request { 350 | return Manager.sharedInstance.download(URLRequest, destination: destination) 351 | } 352 | 353 | // MARK: Resume Data 354 | 355 | /** 356 | Creates a request using the shared manager instance for downloading from the resume data produced from a 357 | previous request cancellation. 358 | 359 | - parameter resumeData: The resume data. This is an opaque data blob produced by `NSURLSessionDownloadTask` 360 | when a task is cancelled. See `NSURLSession -downloadTaskWithResumeData:` for additional 361 | information. 362 | - parameter destination: The closure used to determine the destination of the downloaded file. 363 | 364 | - returns: The created download request. 365 | */ 366 | public func download(resumeData data: NSData, destination: Request.DownloadFileDestination) -> Request { 367 | return Manager.sharedInstance.download(data, destination: destination) 368 | } 369 | -------------------------------------------------------------------------------- /Brainwaves/Pods/Alamofire/Source/Download.swift: -------------------------------------------------------------------------------- 1 | // Download.swift 2 | // 3 | // Copyright (c) 2014–2016 Alamofire Software Foundation (http://alamofire.org/) 4 | // 5 | // Permission is hereby granted, free of charge, to any person obtaining a copy 6 | // of this software and associated documentation files (the "Software"), to deal 7 | // in the Software without restriction, including without limitation the rights 8 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | // copies of the Software, and to permit persons to whom the Software is 10 | // furnished to do so, subject to the following conditions: 11 | // 12 | // The above copyright notice and this permission notice shall be included in 13 | // all copies or substantial portions of the Software. 14 | // 15 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | // THE SOFTWARE. 22 | 23 | import Foundation 24 | 25 | extension Manager { 26 | private enum Downloadable { 27 | case Request(NSURLRequest) 28 | case ResumeData(NSData) 29 | } 30 | 31 | private func download(downloadable: Downloadable, destination: Request.DownloadFileDestination) -> Request { 32 | var downloadTask: NSURLSessionDownloadTask! 33 | 34 | switch downloadable { 35 | case .Request(let request): 36 | dispatch_sync(queue) { 37 | downloadTask = self.session.downloadTaskWithRequest(request) 38 | } 39 | case .ResumeData(let resumeData): 40 | dispatch_sync(queue) { 41 | downloadTask = self.session.downloadTaskWithResumeData(resumeData) 42 | } 43 | } 44 | 45 | let request = Request(session: session, task: downloadTask) 46 | 47 | if let downloadDelegate = request.delegate as? Request.DownloadTaskDelegate { 48 | downloadDelegate.downloadTaskDidFinishDownloadingToURL = { session, downloadTask, URL in 49 | return destination(URL, downloadTask.response as! NSHTTPURLResponse) 50 | } 51 | } 52 | 53 | delegate[request.delegate.task] = request.delegate 54 | 55 | if startRequestsImmediately { 56 | request.resume() 57 | } 58 | 59 | return request 60 | } 61 | 62 | // MARK: Request 63 | 64 | /** 65 | Creates a download request for the specified method, URL string, parameters, parameter encoding, headers 66 | and destination. 67 | 68 | If `startRequestsImmediately` is `true`, the request will have `resume()` called before being returned. 69 | 70 | - parameter method: The HTTP method. 71 | - parameter URLString: The URL string. 72 | - parameter parameters: The parameters. `nil` by default. 73 | - parameter encoding: The parameter encoding. `.URL` by default. 74 | - parameter headers: The HTTP headers. `nil` by default. 75 | - parameter destination: The closure used to determine the destination of the downloaded file. 76 | 77 | - returns: The created download request. 78 | */ 79 | public func download( 80 | method: Method, 81 | _ URLString: URLStringConvertible, 82 | parameters: [String: AnyObject]? = nil, 83 | encoding: ParameterEncoding = .URL, 84 | headers: [String: String]? = nil, 85 | destination: Request.DownloadFileDestination) 86 | -> Request 87 | { 88 | let mutableURLRequest = URLRequest(method, URLString, headers: headers) 89 | let encodedURLRequest = encoding.encode(mutableURLRequest, parameters: parameters).0 90 | 91 | return download(encodedURLRequest, destination: destination) 92 | } 93 | 94 | /** 95 | Creates a request for downloading from the specified URL request. 96 | 97 | If `startRequestsImmediately` is `true`, the request will have `resume()` called before being returned. 98 | 99 | - parameter URLRequest: The URL request 100 | - parameter destination: The closure used to determine the destination of the downloaded file. 101 | 102 | - returns: The created download request. 103 | */ 104 | public func download(URLRequest: URLRequestConvertible, destination: Request.DownloadFileDestination) -> Request { 105 | return download(.Request(URLRequest.URLRequest), destination: destination) 106 | } 107 | 108 | // MARK: Resume Data 109 | 110 | /** 111 | Creates a request for downloading from the resume data produced from a previous request cancellation. 112 | 113 | If `startRequestsImmediately` is `true`, the request will have `resume()` called before being returned. 114 | 115 | - parameter resumeData: The resume data. This is an opaque data blob produced by `NSURLSessionDownloadTask` 116 | when a task is cancelled. See `NSURLSession -downloadTaskWithResumeData:` for 117 | additional information. 118 | - parameter destination: The closure used to determine the destination of the downloaded file. 119 | 120 | - returns: The created download request. 121 | */ 122 | public func download(resumeData: NSData, destination: Request.DownloadFileDestination) -> Request { 123 | return download(.ResumeData(resumeData), destination: destination) 124 | } 125 | } 126 | 127 | // MARK: - 128 | 129 | extension Request { 130 | /** 131 | A closure executed once a request has successfully completed in order to determine where to move the temporary 132 | file written to during the download process. The closure takes two arguments: the temporary file URL and the URL 133 | response, and returns a single argument: the file URL where the temporary file should be moved. 134 | */ 135 | public typealias DownloadFileDestination = (NSURL, NSHTTPURLResponse) -> NSURL 136 | 137 | /** 138 | Creates a download file destination closure which uses the default file manager to move the temporary file to a 139 | file URL in the first available directory with the specified search path directory and search path domain mask. 140 | 141 | - parameter directory: The search path directory. `.DocumentDirectory` by default. 142 | - parameter domain: The search path domain mask. `.UserDomainMask` by default. 143 | 144 | - returns: A download file destination closure. 145 | */ 146 | public class func suggestedDownloadDestination( 147 | directory directory: NSSearchPathDirectory = .DocumentDirectory, 148 | domain: NSSearchPathDomainMask = .UserDomainMask) 149 | -> DownloadFileDestination 150 | { 151 | return { temporaryURL, response -> NSURL in 152 | let directoryURLs = NSFileManager.defaultManager().URLsForDirectory(directory, inDomains: domain) 153 | 154 | if !directoryURLs.isEmpty { 155 | return directoryURLs[0].URLByAppendingPathComponent(response.suggestedFilename!) 156 | } 157 | 158 | return temporaryURL 159 | } 160 | } 161 | 162 | /// The resume data of the underlying download task if available after a failure. 163 | public var resumeData: NSData? { 164 | var data: NSData? 165 | 166 | if let delegate = delegate as? DownloadTaskDelegate { 167 | data = delegate.resumeData 168 | } 169 | 170 | return data 171 | } 172 | 173 | // MARK: - DownloadTaskDelegate 174 | 175 | class DownloadTaskDelegate: TaskDelegate, NSURLSessionDownloadDelegate { 176 | var downloadTask: NSURLSessionDownloadTask? { return task as? NSURLSessionDownloadTask } 177 | var downloadProgress: ((Int64, Int64, Int64) -> Void)? 178 | 179 | var resumeData: NSData? 180 | override var data: NSData? { return resumeData } 181 | 182 | // MARK: - NSURLSessionDownloadDelegate 183 | 184 | // MARK: Override Closures 185 | 186 | var downloadTaskDidFinishDownloadingToURL: ((NSURLSession, NSURLSessionDownloadTask, NSURL) -> NSURL)? 187 | var downloadTaskDidWriteData: ((NSURLSession, NSURLSessionDownloadTask, Int64, Int64, Int64) -> Void)? 188 | var downloadTaskDidResumeAtOffset: ((NSURLSession, NSURLSessionDownloadTask, Int64, Int64) -> Void)? 189 | 190 | // MARK: Delegate Methods 191 | 192 | func URLSession( 193 | session: NSURLSession, 194 | downloadTask: NSURLSessionDownloadTask, 195 | didFinishDownloadingToURL location: NSURL) 196 | { 197 | if let downloadTaskDidFinishDownloadingToURL = downloadTaskDidFinishDownloadingToURL { 198 | do { 199 | let destination = downloadTaskDidFinishDownloadingToURL(session, downloadTask, location) 200 | try NSFileManager.defaultManager().moveItemAtURL(location, toURL: destination) 201 | } catch { 202 | self.error = error as NSError 203 | } 204 | } 205 | } 206 | 207 | func URLSession( 208 | session: NSURLSession, 209 | downloadTask: NSURLSessionDownloadTask, 210 | didWriteData bytesWritten: Int64, 211 | totalBytesWritten: Int64, 212 | totalBytesExpectedToWrite: Int64) 213 | { 214 | if initialResponseTime == nil { initialResponseTime = CFAbsoluteTimeGetCurrent() } 215 | 216 | if let downloadTaskDidWriteData = downloadTaskDidWriteData { 217 | downloadTaskDidWriteData( 218 | session, 219 | downloadTask, 220 | bytesWritten, 221 | totalBytesWritten, 222 | totalBytesExpectedToWrite 223 | ) 224 | } else { 225 | progress.totalUnitCount = totalBytesExpectedToWrite 226 | progress.completedUnitCount = totalBytesWritten 227 | 228 | downloadProgress?(bytesWritten, totalBytesWritten, totalBytesExpectedToWrite) 229 | } 230 | } 231 | 232 | func URLSession( 233 | session: NSURLSession, 234 | downloadTask: NSURLSessionDownloadTask, 235 | didResumeAtOffset fileOffset: Int64, 236 | expectedTotalBytes: Int64) 237 | { 238 | if let downloadTaskDidResumeAtOffset = downloadTaskDidResumeAtOffset { 239 | downloadTaskDidResumeAtOffset(session, downloadTask, fileOffset, expectedTotalBytes) 240 | } else { 241 | progress.totalUnitCount = expectedTotalBytes 242 | progress.completedUnitCount = fileOffset 243 | } 244 | } 245 | } 246 | } 247 | -------------------------------------------------------------------------------- /Brainwaves/Pods/Alamofire/Source/Error.swift: -------------------------------------------------------------------------------- 1 | // Error.swift 2 | // 3 | // Copyright (c) 2014–2016 Alamofire Software Foundation (http://alamofire.org/) 4 | // 5 | // Permission is hereby granted, free of charge, to any person obtaining a copy 6 | // of this software and associated documentation files (the "Software"), to deal 7 | // in the Software without restriction, including without limitation the rights 8 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | // copies of the Software, and to permit persons to whom the Software is 10 | // furnished to do so, subject to the following conditions: 11 | // 12 | // The above copyright notice and this permission notice shall be included in 13 | // all copies or substantial portions of the Software. 14 | // 15 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | // THE SOFTWARE. 22 | 23 | import Foundation 24 | 25 | /// The `Error` struct provides a convenience for creating custom Alamofire NSErrors. 26 | public struct Error { 27 | /// The domain used for creating all Alamofire errors. 28 | public static let Domain = "com.alamofire.error" 29 | 30 | /// The custom error codes generated by Alamofire. 31 | public enum Code: Int { 32 | case InputStreamReadFailed = -6000 33 | case OutputStreamWriteFailed = -6001 34 | case ContentTypeValidationFailed = -6002 35 | case StatusCodeValidationFailed = -6003 36 | case DataSerializationFailed = -6004 37 | case StringSerializationFailed = -6005 38 | case JSONSerializationFailed = -6006 39 | case PropertyListSerializationFailed = -6007 40 | } 41 | 42 | /** 43 | Creates an `NSError` with the given error code and failure reason. 44 | 45 | - parameter code: The error code. 46 | - parameter failureReason: The failure reason. 47 | 48 | - returns: An `NSError` with the given error code and failure reason. 49 | */ 50 | public static func errorWithCode(code: Code, failureReason: String) -> NSError { 51 | return errorWithCode(code.rawValue, failureReason: failureReason) 52 | } 53 | 54 | /** 55 | Creates an `NSError` with the given error code and failure reason. 56 | 57 | - parameter code: The error code. 58 | - parameter failureReason: The failure reason. 59 | 60 | - returns: An `NSError` with the given error code and failure reason. 61 | */ 62 | public static func errorWithCode(code: Int, failureReason: String) -> NSError { 63 | let userInfo = [NSLocalizedFailureReasonErrorKey: failureReason] 64 | return NSError(domain: Domain, code: code, userInfo: userInfo) 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /Brainwaves/Pods/Alamofire/Source/NetworkReachabilityManager.swift: -------------------------------------------------------------------------------- 1 | // NetworkReachabilityManager.swift 2 | // 3 | // Copyright (c) 2014–2016 Alamofire Software Foundation (http://alamofire.org/) 4 | // 5 | // Permission is hereby granted, free of charge, to any person obtaining a copy 6 | // of this software and associated documentation files (the "Software"), to deal 7 | // in the Software without restriction, including without limitation the rights 8 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | // copies of the Software, and to permit persons to whom the Software is 10 | // furnished to do so, subject to the following conditions: 11 | // 12 | // The above copyright notice and this permission notice shall be included in 13 | // all copies or substantial portions of the Software. 14 | // 15 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | // THE SOFTWARE. 22 | 23 | #if !os(watchOS) 24 | 25 | import Foundation 26 | import SystemConfiguration 27 | 28 | /** 29 | The `NetworkReachabilityManager` class listens for reachability changes of hosts and addresses for both WWAN and 30 | WiFi network interfaces. 31 | 32 | Reachability can be used to determine background information about why a network operation failed, or to retry 33 | network requests when a connection is established. It should not be used to prevent a user from initiating a network 34 | request, as it's possible that an initial request may be required to establish reachability. 35 | */ 36 | public class NetworkReachabilityManager { 37 | /** 38 | Defines the various states of network reachability. 39 | 40 | - Unknown: It is unknown whether the network is reachable. 41 | - NotReachable: The network is not reachable. 42 | - ReachableOnWWAN: The network is reachable over the WWAN connection. 43 | - ReachableOnWiFi: The network is reachable over the WiFi connection. 44 | */ 45 | public enum NetworkReachabilityStatus { 46 | case Unknown 47 | case NotReachable 48 | case Reachable(ConnectionType) 49 | } 50 | 51 | /** 52 | Defines the various connection types detected by reachability flags. 53 | 54 | - EthernetOrWiFi: The connection type is either over Ethernet or WiFi. 55 | - WWAN: The connection type is a WWAN connection. 56 | */ 57 | public enum ConnectionType { 58 | case EthernetOrWiFi 59 | case WWAN 60 | } 61 | 62 | /// A closure executed when the network reachability status changes. The closure takes a single argument: the 63 | /// network reachability status. 64 | public typealias Listener = NetworkReachabilityStatus -> Void 65 | 66 | // MARK: - Properties 67 | 68 | /// Whether the network is currently reachable. 69 | public var isReachable: Bool { return isReachableOnWWAN || isReachableOnEthernetOrWiFi } 70 | 71 | /// Whether the network is currently reachable over the WWAN interface. 72 | public var isReachableOnWWAN: Bool { return networkReachabilityStatus == .Reachable(.WWAN) } 73 | 74 | /// Whether the network is currently reachable over Ethernet or WiFi interface. 75 | public var isReachableOnEthernetOrWiFi: Bool { return networkReachabilityStatus == .Reachable(.EthernetOrWiFi) } 76 | 77 | /// The current network reachability status. 78 | public var networkReachabilityStatus: NetworkReachabilityStatus { 79 | guard let flags = self.flags else { return .Unknown } 80 | return networkReachabilityStatusForFlags(flags) 81 | } 82 | 83 | /// The dispatch queue to execute the `listener` closure on. 84 | public var listenerQueue: dispatch_queue_t = dispatch_get_main_queue() 85 | 86 | /// A closure executed when the network reachability status changes. 87 | public var listener: Listener? 88 | 89 | private var flags: SCNetworkReachabilityFlags? { 90 | var flags = SCNetworkReachabilityFlags() 91 | 92 | if SCNetworkReachabilityGetFlags(reachability, &flags) { 93 | return flags 94 | } 95 | 96 | return nil 97 | } 98 | 99 | private let reachability: SCNetworkReachability 100 | private var previousFlags: SCNetworkReachabilityFlags 101 | 102 | // MARK: - Initialization 103 | 104 | /** 105 | Creates a `NetworkReachabilityManager` instance with the specified host. 106 | 107 | - parameter host: The host used to evaluate network reachability. 108 | 109 | - returns: The new `NetworkReachabilityManager` instance. 110 | */ 111 | public convenience init?(host: String) { 112 | guard let reachability = SCNetworkReachabilityCreateWithName(nil, host) else { return nil } 113 | self.init(reachability: reachability) 114 | } 115 | 116 | /** 117 | Creates a `NetworkReachabilityManager` instance with the default socket IPv4 or IPv6 address. 118 | 119 | - returns: The new `NetworkReachabilityManager` instance. 120 | */ 121 | public convenience init?() { 122 | if #available(iOS 9.0, OSX 10.10, *) { 123 | var address = sockaddr_in6() 124 | address.sin6_len = UInt8(sizeofValue(address)) 125 | address.sin6_family = sa_family_t(AF_INET6) 126 | 127 | guard let reachability = withUnsafePointer(&address, { 128 | SCNetworkReachabilityCreateWithAddress(nil, UnsafePointer($0)) 129 | }) else { return nil } 130 | 131 | self.init(reachability: reachability) 132 | } else { 133 | var address = sockaddr_in() 134 | address.sin_len = UInt8(sizeofValue(address)) 135 | address.sin_family = sa_family_t(AF_INET) 136 | 137 | guard let reachability = withUnsafePointer(&address, { 138 | SCNetworkReachabilityCreateWithAddress(nil, UnsafePointer($0)) 139 | }) else { return nil } 140 | 141 | self.init(reachability: reachability) 142 | } 143 | } 144 | 145 | private init(reachability: SCNetworkReachability) { 146 | self.reachability = reachability 147 | self.previousFlags = SCNetworkReachabilityFlags() 148 | } 149 | 150 | deinit { 151 | stopListening() 152 | } 153 | 154 | // MARK: - Listening 155 | 156 | /** 157 | Starts listening for changes in network reachability status. 158 | 159 | - returns: `true` if listening was started successfully, `false` otherwise. 160 | */ 161 | public func startListening() -> Bool { 162 | var context = SCNetworkReachabilityContext(version: 0, info: nil, retain: nil, release: nil, copyDescription: nil) 163 | context.info = UnsafeMutablePointer(Unmanaged.passUnretained(self).toOpaque()) 164 | 165 | let callbackEnabled = SCNetworkReachabilitySetCallback( 166 | reachability, 167 | { (_, flags, info) in 168 | let reachability = Unmanaged.fromOpaque(COpaquePointer(info)).takeUnretainedValue() 169 | reachability.notifyListener(flags) 170 | }, 171 | &context 172 | ) 173 | 174 | let queueEnabled = SCNetworkReachabilitySetDispatchQueue(reachability, listenerQueue) 175 | 176 | dispatch_async(listenerQueue) { 177 | self.previousFlags = SCNetworkReachabilityFlags() 178 | self.notifyListener(self.flags ?? SCNetworkReachabilityFlags()) 179 | } 180 | 181 | return callbackEnabled && queueEnabled 182 | } 183 | 184 | /** 185 | Stops listening for changes in network reachability status. 186 | */ 187 | public func stopListening() { 188 | SCNetworkReachabilitySetCallback(reachability, nil, nil) 189 | SCNetworkReachabilitySetDispatchQueue(reachability, nil) 190 | } 191 | 192 | // MARK: - Internal - Listener Notification 193 | 194 | func notifyListener(flags: SCNetworkReachabilityFlags) { 195 | guard previousFlags != flags else { return } 196 | previousFlags = flags 197 | 198 | listener?(networkReachabilityStatusForFlags(flags)) 199 | } 200 | 201 | // MARK: - Internal - Network Reachability Status 202 | 203 | func networkReachabilityStatusForFlags(flags: SCNetworkReachabilityFlags) -> NetworkReachabilityStatus { 204 | guard flags.contains(.Reachable) else { return .NotReachable } 205 | 206 | var networkStatus: NetworkReachabilityStatus = .NotReachable 207 | 208 | if !flags.contains(.ConnectionRequired) { networkStatus = .Reachable(.EthernetOrWiFi) } 209 | 210 | if flags.contains(.ConnectionOnDemand) || flags.contains(.ConnectionOnTraffic) { 211 | if !flags.contains(.InterventionRequired) { networkStatus = .Reachable(.EthernetOrWiFi) } 212 | } 213 | 214 | #if os(iOS) 215 | if flags.contains(.IsWWAN) { networkStatus = .Reachable(.WWAN) } 216 | #endif 217 | 218 | return networkStatus 219 | } 220 | } 221 | 222 | // MARK: - 223 | 224 | extension NetworkReachabilityManager.NetworkReachabilityStatus: Equatable {} 225 | 226 | /** 227 | Returns whether the two network reachability status values are equal. 228 | 229 | - parameter lhs: The left-hand side value to compare. 230 | - parameter rhs: The right-hand side value to compare. 231 | 232 | - returns: `true` if the two values are equal, `false` otherwise. 233 | */ 234 | public func ==( 235 | lhs: NetworkReachabilityManager.NetworkReachabilityStatus, 236 | rhs: NetworkReachabilityManager.NetworkReachabilityStatus) 237 | -> Bool 238 | { 239 | switch (lhs, rhs) { 240 | case (.Unknown, .Unknown): 241 | return true 242 | case (.NotReachable, .NotReachable): 243 | return true 244 | case let (.Reachable(lhsConnectionType), .Reachable(rhsConnectionType)): 245 | return lhsConnectionType == rhsConnectionType 246 | default: 247 | return false 248 | } 249 | } 250 | 251 | #endif 252 | -------------------------------------------------------------------------------- /Brainwaves/Pods/Alamofire/Source/Notifications.swift: -------------------------------------------------------------------------------- 1 | // Notifications.swift 2 | // 3 | // Copyright (c) 2014–2016 Alamofire Software Foundation (http://alamofire.org/) 4 | // 5 | // Permission is hereby granted, free of charge, to any person obtaining a copy 6 | // of this software and associated documentation files (the "Software"), to deal 7 | // in the Software without restriction, including without limitation the rights 8 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | // copies of the Software, and to permit persons to whom the Software is 10 | // furnished to do so, subject to the following conditions: 11 | // 12 | // The above copyright notice and this permission notice shall be included in 13 | // all copies or substantial portions of the Software. 14 | // 15 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | // THE SOFTWARE. 22 | 23 | import Foundation 24 | 25 | /// Contains all the `NSNotification` names posted by Alamofire with descriptions of each notification's payload. 26 | public struct Notifications { 27 | /// Used as a namespace for all `NSURLSessionTask` related notifications. 28 | public struct Task { 29 | /// Notification posted when an `NSURLSessionTask` is resumed. The notification `object` contains the resumed 30 | /// `NSURLSessionTask`. 31 | public static let DidResume = "com.alamofire.notifications.task.didResume" 32 | 33 | /// Notification posted when an `NSURLSessionTask` is suspended. The notification `object` contains the 34 | /// suspended `NSURLSessionTask`. 35 | public static let DidSuspend = "com.alamofire.notifications.task.didSuspend" 36 | 37 | /// Notification posted when an `NSURLSessionTask` is cancelled. The notification `object` contains the 38 | /// cancelled `NSURLSessionTask`. 39 | public static let DidCancel = "com.alamofire.notifications.task.didCancel" 40 | 41 | /// Notification posted when an `NSURLSessionTask` is completed. The notification `object` contains the 42 | /// completed `NSURLSessionTask`. 43 | public static let DidComplete = "com.alamofire.notifications.task.didComplete" 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /Brainwaves/Pods/Alamofire/Source/ParameterEncoding.swift: -------------------------------------------------------------------------------- 1 | // ParameterEncoding.swift 2 | // 3 | // Copyright (c) 2014–2016 Alamofire Software Foundation (http://alamofire.org/) 4 | // 5 | // Permission is hereby granted, free of charge, to any person obtaining a copy 6 | // of this software and associated documentation files (the "Software"), to deal 7 | // in the Software without restriction, including without limitation the rights 8 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | // copies of the Software, and to permit persons to whom the Software is 10 | // furnished to do so, subject to the following conditions: 11 | // 12 | // The above copyright notice and this permission notice shall be included in 13 | // all copies or substantial portions of the Software. 14 | // 15 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | // THE SOFTWARE. 22 | 23 | import Foundation 24 | 25 | /** 26 | HTTP method definitions. 27 | 28 | See https://tools.ietf.org/html/rfc7231#section-4.3 29 | */ 30 | public enum Method: String { 31 | case OPTIONS, GET, HEAD, POST, PUT, PATCH, DELETE, TRACE, CONNECT 32 | } 33 | 34 | // MARK: ParameterEncoding 35 | 36 | /** 37 | Used to specify the way in which a set of parameters are applied to a URL request. 38 | 39 | - `URL`: Creates a query string to be set as or appended to any existing URL query for `GET`, `HEAD`, 40 | and `DELETE` requests, or set as the body for requests with any other HTTP method. The 41 | `Content-Type` HTTP header field of an encoded request with HTTP body is set to 42 | `application/x-www-form-urlencoded; charset=utf-8`. Since there is no published specification 43 | for how to encode collection types, the convention of appending `[]` to the key for array 44 | values (`foo[]=1&foo[]=2`), and appending the key surrounded by square brackets for nested 45 | dictionary values (`foo[bar]=baz`). 46 | 47 | - `URLEncodedInURL`: Creates query string to be set as or appended to any existing URL query. Uses the same 48 | implementation as the `.URL` case, but always applies the encoded result to the URL. 49 | 50 | - `JSON`: Uses `NSJSONSerialization` to create a JSON representation of the parameters object, which is 51 | set as the body of the request. The `Content-Type` HTTP header field of an encoded request is 52 | set to `application/json`. 53 | 54 | - `PropertyList`: Uses `NSPropertyListSerialization` to create a plist representation of the parameters object, 55 | according to the associated format and write options values, which is set as the body of the 56 | request. The `Content-Type` HTTP header field of an encoded request is set to 57 | `application/x-plist`. 58 | 59 | - `Custom`: Uses the associated closure value to construct a new request given an existing request and 60 | parameters. 61 | */ 62 | public enum ParameterEncoding { 63 | case URL 64 | case URLEncodedInURL 65 | case JSON 66 | case PropertyList(NSPropertyListFormat, NSPropertyListWriteOptions) 67 | case Custom((URLRequestConvertible, [String: AnyObject]?) -> (NSMutableURLRequest, NSError?)) 68 | 69 | /** 70 | Creates a URL request by encoding parameters and applying them onto an existing request. 71 | 72 | - parameter URLRequest: The request to have parameters applied. 73 | - parameter parameters: The parameters to apply. 74 | 75 | - returns: A tuple containing the constructed request and the error that occurred during parameter encoding, 76 | if any. 77 | */ 78 | public func encode( 79 | URLRequest: URLRequestConvertible, 80 | parameters: [String: AnyObject]?) 81 | -> (NSMutableURLRequest, NSError?) 82 | { 83 | var mutableURLRequest = URLRequest.URLRequest 84 | 85 | guard let parameters = parameters else { return (mutableURLRequest, nil) } 86 | 87 | var encodingError: NSError? = nil 88 | 89 | switch self { 90 | case .URL, .URLEncodedInURL: 91 | func query(parameters: [String: AnyObject]) -> String { 92 | var components: [(String, String)] = [] 93 | 94 | for key in parameters.keys.sort(<) { 95 | let value = parameters[key]! 96 | components += queryComponents(key, value) 97 | } 98 | 99 | return (components.map { "\($0)=\($1)" } as [String]).joinWithSeparator("&") 100 | } 101 | 102 | func encodesParametersInURL(method: Method) -> Bool { 103 | switch self { 104 | case .URLEncodedInURL: 105 | return true 106 | default: 107 | break 108 | } 109 | 110 | switch method { 111 | case .GET, .HEAD, .DELETE: 112 | return true 113 | default: 114 | return false 115 | } 116 | } 117 | 118 | if let method = Method(rawValue: mutableURLRequest.HTTPMethod) where encodesParametersInURL(method) { 119 | if let 120 | URLComponents = NSURLComponents(URL: mutableURLRequest.URL!, resolvingAgainstBaseURL: false) 121 | where !parameters.isEmpty 122 | { 123 | let percentEncodedQuery = (URLComponents.percentEncodedQuery.map { $0 + "&" } ?? "") + query(parameters) 124 | URLComponents.percentEncodedQuery = percentEncodedQuery 125 | mutableURLRequest.URL = URLComponents.URL 126 | } 127 | } else { 128 | if mutableURLRequest.valueForHTTPHeaderField("Content-Type") == nil { 129 | mutableURLRequest.setValue( 130 | "application/x-www-form-urlencoded; charset=utf-8", 131 | forHTTPHeaderField: "Content-Type" 132 | ) 133 | } 134 | 135 | mutableURLRequest.HTTPBody = query(parameters).dataUsingEncoding( 136 | NSUTF8StringEncoding, 137 | allowLossyConversion: false 138 | ) 139 | } 140 | case .JSON: 141 | do { 142 | let options = NSJSONWritingOptions() 143 | let data = try NSJSONSerialization.dataWithJSONObject(parameters, options: options) 144 | 145 | if mutableURLRequest.valueForHTTPHeaderField("Content-Type") == nil { 146 | mutableURLRequest.setValue("application/json", forHTTPHeaderField: "Content-Type") 147 | } 148 | 149 | mutableURLRequest.HTTPBody = data 150 | } catch { 151 | encodingError = error as NSError 152 | } 153 | case .PropertyList(let format, let options): 154 | do { 155 | let data = try NSPropertyListSerialization.dataWithPropertyList( 156 | parameters, 157 | format: format, 158 | options: options 159 | ) 160 | 161 | if mutableURLRequest.valueForHTTPHeaderField("Content-Type") == nil { 162 | mutableURLRequest.setValue("application/x-plist", forHTTPHeaderField: "Content-Type") 163 | } 164 | 165 | mutableURLRequest.HTTPBody = data 166 | } catch { 167 | encodingError = error as NSError 168 | } 169 | case .Custom(let closure): 170 | (mutableURLRequest, encodingError) = closure(mutableURLRequest, parameters) 171 | } 172 | 173 | return (mutableURLRequest, encodingError) 174 | } 175 | 176 | /** 177 | Creates percent-escaped, URL encoded query string components from the given key-value pair using recursion. 178 | 179 | - parameter key: The key of the query component. 180 | - parameter value: The value of the query component. 181 | 182 | - returns: The percent-escaped, URL encoded query string components. 183 | */ 184 | public func queryComponents(key: String, _ value: AnyObject) -> [(String, String)] { 185 | var components: [(String, String)] = [] 186 | 187 | if let dictionary = value as? [String: AnyObject] { 188 | for (nestedKey, value) in dictionary { 189 | components += queryComponents("\(key)[\(nestedKey)]", value) 190 | } 191 | } else if let array = value as? [AnyObject] { 192 | for value in array { 193 | components += queryComponents("\(key)[]", value) 194 | } 195 | } else { 196 | components.append((escape(key), escape("\(value)"))) 197 | } 198 | 199 | return components 200 | } 201 | 202 | /** 203 | Returns a percent-escaped string following RFC 3986 for a query string key or value. 204 | 205 | RFC 3986 states that the following characters are "reserved" characters. 206 | 207 | - General Delimiters: ":", "#", "[", "]", "@", "?", "/" 208 | - Sub-Delimiters: "!", "$", "&", "'", "(", ")", "*", "+", ",", ";", "=" 209 | 210 | In RFC 3986 - Section 3.4, it states that the "?" and "/" characters should not be escaped to allow 211 | query strings to include a URL. Therefore, all "reserved" characters with the exception of "?" and "/" 212 | should be percent-escaped in the query string. 213 | 214 | - parameter string: The string to be percent-escaped. 215 | 216 | - returns: The percent-escaped string. 217 | */ 218 | public func escape(string: String) -> String { 219 | let generalDelimitersToEncode = ":#[]@" // does not include "?" or "/" due to RFC 3986 - Section 3.4 220 | let subDelimitersToEncode = "!$&'()*+,;=" 221 | 222 | let allowedCharacterSet = NSCharacterSet.URLQueryAllowedCharacterSet().mutableCopy() as! NSMutableCharacterSet 223 | allowedCharacterSet.removeCharactersInString(generalDelimitersToEncode + subDelimitersToEncode) 224 | 225 | var escaped = "" 226 | 227 | //========================================================================================================== 228 | // 229 | // Batching is required for escaping due to an internal bug in iOS 8.1 and 8.2. Encoding more than a few 230 | // hundred Chinense characters causes various malloc error crashes. To avoid this issue until iOS 8 is no 231 | // longer supported, batching MUST be used for encoding. This introduces roughly a 20% overhead. For more 232 | // info, please refer to: 233 | // 234 | // - https://github.com/Alamofire/Alamofire/issues/206 235 | // 236 | //========================================================================================================== 237 | 238 | if #available(iOS 8.3, OSX 10.10, *) { 239 | escaped = string.stringByAddingPercentEncodingWithAllowedCharacters(allowedCharacterSet) ?? string 240 | } else { 241 | let batchSize = 50 242 | var index = string.startIndex 243 | 244 | while index != string.endIndex { 245 | let startIndex = index 246 | let endIndex = index.advancedBy(batchSize, limit: string.endIndex) 247 | let range = startIndex.. { 27 | /// The URL request sent to the server. 28 | public let request: NSURLRequest? 29 | 30 | /// The server's response to the URL request. 31 | public let response: NSHTTPURLResponse? 32 | 33 | /// The data returned by the server. 34 | public let data: NSData? 35 | 36 | /// The result of response serialization. 37 | public let result: Result 38 | 39 | /// The timeline of the complete lifecycle of the `Request`. 40 | public let timeline: Timeline 41 | 42 | /** 43 | Initializes the `Response` instance with the specified URL request, URL response, server data and response 44 | serialization result. 45 | 46 | - parameter request: The URL request sent to the server. 47 | - parameter response: The server's response to the URL request. 48 | - parameter data: The data returned by the server. 49 | - parameter result: The result of response serialization. 50 | - parameter timeline: The timeline of the complete lifecycle of the `Request`. Defaults to `Timeline()`. 51 | 52 | - returns: the new `Response` instance. 53 | */ 54 | public init( 55 | request: NSURLRequest?, 56 | response: NSHTTPURLResponse?, 57 | data: NSData?, 58 | result: Result, 59 | timeline: Timeline = Timeline()) 60 | { 61 | self.request = request 62 | self.response = response 63 | self.data = data 64 | self.result = result 65 | self.timeline = timeline 66 | } 67 | } 68 | 69 | // MARK: - CustomStringConvertible 70 | 71 | extension Response: CustomStringConvertible { 72 | /// The textual representation used when written to an output stream, which includes whether the result was a 73 | /// success or failure. 74 | public var description: String { 75 | return result.debugDescription 76 | } 77 | } 78 | 79 | // MARK: - CustomDebugStringConvertible 80 | 81 | extension Response: CustomDebugStringConvertible { 82 | /// The debug textual representation used when written to an output stream, which includes the URL request, the URL 83 | /// response, the server data and the response serialization result. 84 | public var debugDescription: String { 85 | var output: [String] = [] 86 | 87 | output.append(request != nil ? "[Request]: \(request!)" : "[Request]: nil") 88 | output.append(response != nil ? "[Response]: \(response!)" : "[Response]: nil") 89 | output.append("[Data]: \(data?.length ?? 0) bytes") 90 | output.append("[Result]: \(result.debugDescription)") 91 | output.append("[Timeline]: \(timeline.debugDescription)") 92 | 93 | return output.joinWithSeparator("\n") 94 | } 95 | } 96 | -------------------------------------------------------------------------------- /Brainwaves/Pods/Alamofire/Source/Result.swift: -------------------------------------------------------------------------------- 1 | // Result.swift 2 | // 3 | // Copyright (c) 2014–2016 Alamofire Software Foundation (http://alamofire.org/) 4 | // 5 | // Permission is hereby granted, free of charge, to any person obtaining a copy 6 | // of this software and associated documentation files (the "Software"), to deal 7 | // in the Software without restriction, including without limitation the rights 8 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | // copies of the Software, and to permit persons to whom the Software is 10 | // furnished to do so, subject to the following conditions: 11 | // 12 | // The above copyright notice and this permission notice shall be included in 13 | // all copies or substantial portions of the Software. 14 | // 15 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | // THE SOFTWARE. 22 | 23 | import Foundation 24 | 25 | /** 26 | Used to represent whether a request was successful or encountered an error. 27 | 28 | - Success: The request and all post processing operations were successful resulting in the serialization of the 29 | provided associated value. 30 | - Failure: The request encountered an error resulting in a failure. The associated values are the original data 31 | provided by the server as well as the error that caused the failure. 32 | */ 33 | public enum Result { 34 | case Success(Value) 35 | case Failure(Error) 36 | 37 | /// Returns `true` if the result is a success, `false` otherwise. 38 | public var isSuccess: Bool { 39 | switch self { 40 | case .Success: 41 | return true 42 | case .Failure: 43 | return false 44 | } 45 | } 46 | 47 | /// Returns `true` if the result is a failure, `false` otherwise. 48 | public var isFailure: Bool { 49 | return !isSuccess 50 | } 51 | 52 | /// Returns the associated value if the result is a success, `nil` otherwise. 53 | public var value: Value? { 54 | switch self { 55 | case .Success(let value): 56 | return value 57 | case .Failure: 58 | return nil 59 | } 60 | } 61 | 62 | /// Returns the associated error value if the result is a failure, `nil` otherwise. 63 | public var error: Error? { 64 | switch self { 65 | case .Success: 66 | return nil 67 | case .Failure(let error): 68 | return error 69 | } 70 | } 71 | } 72 | 73 | // MARK: - CustomStringConvertible 74 | 75 | extension Result: CustomStringConvertible { 76 | /// The textual representation used when written to an output stream, which includes whether the result was a 77 | /// success or failure. 78 | public var description: String { 79 | switch self { 80 | case .Success: 81 | return "SUCCESS" 82 | case .Failure: 83 | return "FAILURE" 84 | } 85 | } 86 | } 87 | 88 | // MARK: - CustomDebugStringConvertible 89 | 90 | extension Result: CustomDebugStringConvertible { 91 | /// The debug textual representation used when written to an output stream, which includes whether the result was a 92 | /// success or failure in addition to the value or error. 93 | public var debugDescription: String { 94 | switch self { 95 | case .Success(let value): 96 | return "SUCCESS: \(value)" 97 | case .Failure(let error): 98 | return "FAILURE: \(error)" 99 | } 100 | } 101 | } 102 | -------------------------------------------------------------------------------- /Brainwaves/Pods/Alamofire/Source/Stream.swift: -------------------------------------------------------------------------------- 1 | // Stream.swift 2 | // 3 | // Copyright (c) 2014–2016 Alamofire Software Foundation (http://alamofire.org/) 4 | // 5 | // Permission is hereby granted, free of charge, to any person obtaining a copy 6 | // of this software and associated documentation files (the "Software"), to deal 7 | // in the Software without restriction, including without limitation the rights 8 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | // copies of the Software, and to permit persons to whom the Software is 10 | // furnished to do so, subject to the following conditions: 11 | // 12 | // The above copyright notice and this permission notice shall be included in 13 | // all copies or substantial portions of the Software. 14 | // 15 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | // THE SOFTWARE. 22 | 23 | import Foundation 24 | 25 | #if !os(watchOS) 26 | 27 | @available(iOS 9.0, OSX 10.11, tvOS 9.0, *) 28 | extension Manager { 29 | private enum Streamable { 30 | case Stream(String, Int) 31 | case NetService(NSNetService) 32 | } 33 | 34 | private func stream(streamable: Streamable) -> Request { 35 | var streamTask: NSURLSessionStreamTask! 36 | 37 | switch streamable { 38 | case .Stream(let hostName, let port): 39 | dispatch_sync(queue) { 40 | streamTask = self.session.streamTaskWithHostName(hostName, port: port) 41 | } 42 | case .NetService(let netService): 43 | dispatch_sync(queue) { 44 | streamTask = self.session.streamTaskWithNetService(netService) 45 | } 46 | } 47 | 48 | let request = Request(session: session, task: streamTask) 49 | 50 | delegate[request.delegate.task] = request.delegate 51 | 52 | if startRequestsImmediately { 53 | request.resume() 54 | } 55 | 56 | return request 57 | } 58 | 59 | /** 60 | Creates a request for bidirectional streaming with the given hostname and port. 61 | 62 | - parameter hostName: The hostname of the server to connect to. 63 | - parameter port: The port of the server to connect to. 64 | 65 | :returns: The created stream request. 66 | */ 67 | public func stream(hostName hostName: String, port: Int) -> Request { 68 | return stream(.Stream(hostName, port)) 69 | } 70 | 71 | /** 72 | Creates a request for bidirectional streaming with the given `NSNetService`. 73 | 74 | - parameter netService: The net service used to identify the endpoint. 75 | 76 | - returns: The created stream request. 77 | */ 78 | public func stream(netService netService: NSNetService) -> Request { 79 | return stream(.NetService(netService)) 80 | } 81 | } 82 | 83 | // MARK: - 84 | 85 | @available(iOS 9.0, OSX 10.11, tvOS 9.0, *) 86 | extension Manager.SessionDelegate: NSURLSessionStreamDelegate { 87 | 88 | // MARK: Override Closures 89 | 90 | /// Overrides default behavior for NSURLSessionStreamDelegate method `URLSession:readClosedForStreamTask:`. 91 | public var streamTaskReadClosed: ((NSURLSession, NSURLSessionStreamTask) -> Void)? { 92 | get { 93 | return _streamTaskReadClosed as? (NSURLSession, NSURLSessionStreamTask) -> Void 94 | } 95 | set { 96 | _streamTaskReadClosed = newValue 97 | } 98 | } 99 | 100 | /// Overrides default behavior for NSURLSessionStreamDelegate method `URLSession:writeClosedForStreamTask:`. 101 | public var streamTaskWriteClosed: ((NSURLSession, NSURLSessionStreamTask) -> Void)? { 102 | get { 103 | return _streamTaskWriteClosed as? (NSURLSession, NSURLSessionStreamTask) -> Void 104 | } 105 | set { 106 | _streamTaskWriteClosed = newValue 107 | } 108 | } 109 | 110 | /// Overrides default behavior for NSURLSessionStreamDelegate method `URLSession:betterRouteDiscoveredForStreamTask:`. 111 | public var streamTaskBetterRouteDiscovered: ((NSURLSession, NSURLSessionStreamTask) -> Void)? { 112 | get { 113 | return _streamTaskBetterRouteDiscovered as? (NSURLSession, NSURLSessionStreamTask) -> Void 114 | } 115 | set { 116 | _streamTaskBetterRouteDiscovered = newValue 117 | } 118 | } 119 | 120 | /// Overrides default behavior for NSURLSessionStreamDelegate method `URLSession:streamTask:didBecomeInputStream:outputStream:`. 121 | public var streamTaskDidBecomeInputStream: ((NSURLSession, NSURLSessionStreamTask, NSInputStream, NSOutputStream) -> Void)? { 122 | get { 123 | return _streamTaskDidBecomeInputStream as? (NSURLSession, NSURLSessionStreamTask, NSInputStream, NSOutputStream) -> Void 124 | } 125 | set { 126 | _streamTaskDidBecomeInputStream = newValue 127 | } 128 | } 129 | 130 | // MARK: Delegate Methods 131 | 132 | /** 133 | Tells the delegate that the read side of the connection has been closed. 134 | 135 | - parameter session: The session. 136 | - parameter streamTask: The stream task. 137 | */ 138 | public func URLSession(session: NSURLSession, readClosedForStreamTask streamTask: NSURLSessionStreamTask) { 139 | streamTaskReadClosed?(session, streamTask) 140 | } 141 | 142 | /** 143 | Tells the delegate that the write side of the connection has been closed. 144 | 145 | - parameter session: The session. 146 | - parameter streamTask: The stream task. 147 | */ 148 | public func URLSession(session: NSURLSession, writeClosedForStreamTask streamTask: NSURLSessionStreamTask) { 149 | streamTaskWriteClosed?(session, streamTask) 150 | } 151 | 152 | /** 153 | Tells the delegate that the system has determined that a better route to the host is available. 154 | 155 | - parameter session: The session. 156 | - parameter streamTask: The stream task. 157 | */ 158 | public func URLSession(session: NSURLSession, betterRouteDiscoveredForStreamTask streamTask: NSURLSessionStreamTask) { 159 | streamTaskBetterRouteDiscovered?(session, streamTask) 160 | } 161 | 162 | /** 163 | Tells the delegate that the stream task has been completed and provides the unopened stream objects. 164 | 165 | - parameter session: The session. 166 | - parameter streamTask: The stream task. 167 | - parameter inputStream: The new input stream. 168 | - parameter outputStream: The new output stream. 169 | */ 170 | public func URLSession( 171 | session: NSURLSession, 172 | streamTask: NSURLSessionStreamTask, 173 | didBecomeInputStream inputStream: NSInputStream, 174 | outputStream: NSOutputStream) 175 | { 176 | streamTaskDidBecomeInputStream?(session, streamTask, inputStream, outputStream) 177 | } 178 | } 179 | 180 | #endif 181 | -------------------------------------------------------------------------------- /Brainwaves/Pods/Alamofire/Source/Timeline.swift: -------------------------------------------------------------------------------- 1 | // Timeline.swift 2 | // 3 | // Copyright (c) 2014–2016 Alamofire Software Foundation (http://alamofire.org/) 4 | // 5 | // Permission is hereby granted, free of charge, to any person obtaining a copy 6 | // of this software and associated documentation files (the "Software"), to deal 7 | // in the Software without restriction, including without limitation the rights 8 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | // copies of the Software, and to permit persons to whom the Software is 10 | // furnished to do so, subject to the following conditions: 11 | // 12 | // The above copyright notice and this permission notice shall be included in 13 | // all copies or substantial portions of the Software. 14 | // 15 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | // THE SOFTWARE. 22 | 23 | import Foundation 24 | 25 | /// Responsible for computing the timing metrics for the complete lifecycle of a `Request`. 26 | public struct Timeline { 27 | /// The time the request was initialized. 28 | public let requestStartTime: CFAbsoluteTime 29 | 30 | /// The time the first bytes were received from or sent to the server. 31 | public let initialResponseTime: CFAbsoluteTime 32 | 33 | /// The time when the request was completed. 34 | public let requestCompletedTime: CFAbsoluteTime 35 | 36 | /// The time when the response serialization was completed. 37 | public let serializationCompletedTime: CFAbsoluteTime 38 | 39 | /// The time interval in seconds from the time the request started to the initial response from the server. 40 | public let latency: NSTimeInterval 41 | 42 | /// The time interval in seconds from the time the request started to the time the request completed. 43 | public let requestDuration: NSTimeInterval 44 | 45 | /// The time interval in seconds from the time the request completed to the time response serialization completed. 46 | public let serializationDuration: NSTimeInterval 47 | 48 | /// The time interval in seconds from the time the request started to the time response serialization completed. 49 | public let totalDuration: NSTimeInterval 50 | 51 | /** 52 | Creates a new `Timeline` instance with the specified request times. 53 | 54 | - parameter requestStartTime: The time the request was initialized. Defaults to `0.0`. 55 | - parameter initialResponseTime: The time the first bytes were received from or sent to the server. 56 | Defaults to `0.0`. 57 | - parameter requestCompletedTime: The time when the request was completed. Defaults to `0.0`. 58 | - parameter serializationCompletedTime: The time when the response serialization was completed. Defaults 59 | to `0.0`. 60 | 61 | - returns: The new `Timeline` instance. 62 | */ 63 | public init( 64 | requestStartTime: CFAbsoluteTime = 0.0, 65 | initialResponseTime: CFAbsoluteTime = 0.0, 66 | requestCompletedTime: CFAbsoluteTime = 0.0, 67 | serializationCompletedTime: CFAbsoluteTime = 0.0) 68 | { 69 | self.requestStartTime = requestStartTime 70 | self.initialResponseTime = initialResponseTime 71 | self.requestCompletedTime = requestCompletedTime 72 | self.serializationCompletedTime = serializationCompletedTime 73 | 74 | self.latency = initialResponseTime - requestStartTime 75 | self.requestDuration = requestCompletedTime - requestStartTime 76 | self.serializationDuration = serializationCompletedTime - requestCompletedTime 77 | self.totalDuration = serializationCompletedTime - requestStartTime 78 | } 79 | } 80 | 81 | // MARK: - CustomStringConvertible 82 | 83 | extension Timeline: CustomStringConvertible { 84 | /// The textual representation used when written to an output stream, which includes the latency, the request 85 | /// duration and the total duration. 86 | public var description: String { 87 | let latency = String(format: "%.3f", self.latency) 88 | let requestDuration = String(format: "%.3f", self.requestDuration) 89 | let serializationDuration = String(format: "%.3f", self.serializationDuration) 90 | let totalDuration = String(format: "%.3f", self.totalDuration) 91 | 92 | let timings = [ 93 | "\"Latency\": \(latency) secs", 94 | "\"Request Duration\": \(requestDuration) secs", 95 | "\"Serialization Duration\": \(serializationDuration) secs", 96 | "\"Total Duration\": \(totalDuration) secs" 97 | ] 98 | 99 | return "Timeline: { \(timings.joinWithSeparator(", ")) }" 100 | } 101 | } 102 | 103 | // MARK: - CustomDebugStringConvertible 104 | 105 | extension Timeline: CustomDebugStringConvertible { 106 | /// The textual representation used when written to an output stream, which includes the request start time, the 107 | /// initial response time, the request completed time, the serialization completed time, the latency, the request 108 | /// duration and the total duration. 109 | public var debugDescription: String { 110 | let timings = [ 111 | "\"Request Start Time\": \(requestStartTime)", 112 | "\"Initial Response Time\": \(initialResponseTime)", 113 | "\"Request Completed Time\": \(requestCompletedTime)", 114 | "\"Serialization Completed Time\": \(serializationCompletedTime)", 115 | "\"Latency\": \(latency) secs", 116 | "\"Request Duration\": \(requestDuration) secs", 117 | "\"Serialization Duration\": \(serializationDuration) secs", 118 | "\"Total Duration\": \(totalDuration) secs" 119 | ] 120 | 121 | return "Timeline: { \(timings.joinWithSeparator(", ")) }" 122 | } 123 | } 124 | -------------------------------------------------------------------------------- /Brainwaves/Pods/Alamofire/Source/Validation.swift: -------------------------------------------------------------------------------- 1 | // Validation.swift 2 | // 3 | // Copyright (c) 2014–2016 Alamofire Software Foundation (http://alamofire.org/) 4 | // 5 | // Permission is hereby granted, free of charge, to any person obtaining a copy 6 | // of this software and associated documentation files (the "Software"), to deal 7 | // in the Software without restriction, including without limitation the rights 8 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | // copies of the Software, and to permit persons to whom the Software is 10 | // furnished to do so, subject to the following conditions: 11 | // 12 | // The above copyright notice and this permission notice shall be included in 13 | // all copies or substantial portions of the Software. 14 | // 15 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | // THE SOFTWARE. 22 | 23 | import Foundation 24 | 25 | extension Request { 26 | 27 | /** 28 | Used to represent whether validation was successful or encountered an error resulting in a failure. 29 | 30 | - Success: The validation was successful. 31 | - Failure: The validation failed encountering the provided error. 32 | */ 33 | public enum ValidationResult { 34 | case Success 35 | case Failure(NSError) 36 | } 37 | 38 | /** 39 | A closure used to validate a request that takes a URL request and URL response, and returns whether the 40 | request was valid. 41 | */ 42 | public typealias Validation = (NSURLRequest?, NSHTTPURLResponse) -> ValidationResult 43 | 44 | /** 45 | Validates the request, using the specified closure. 46 | 47 | If validation fails, subsequent calls to response handlers will have an associated error. 48 | 49 | - parameter validation: A closure to validate the request. 50 | 51 | - returns: The request. 52 | */ 53 | public func validate(validation: Validation) -> Self { 54 | delegate.queue.addOperationWithBlock { 55 | if let 56 | response = self.response where self.delegate.error == nil, 57 | case let .Failure(error) = validation(self.request, response) 58 | { 59 | self.delegate.error = error 60 | } 61 | } 62 | 63 | return self 64 | } 65 | 66 | // MARK: - Status Code 67 | 68 | /** 69 | Validates that the response has a status code in the specified range. 70 | 71 | If validation fails, subsequent calls to response handlers will have an associated error. 72 | 73 | - parameter range: The range of acceptable status codes. 74 | 75 | - returns: The request. 76 | */ 77 | public func validate(statusCode acceptableStatusCode: S) -> Self { 78 | return validate { _, response in 79 | if acceptableStatusCode.contains(response.statusCode) { 80 | return .Success 81 | } else { 82 | let failureReason = "Response status code was unacceptable: \(response.statusCode)" 83 | return .Failure(Error.errorWithCode(.StatusCodeValidationFailed, failureReason: failureReason)) 84 | } 85 | } 86 | } 87 | 88 | // MARK: - Content-Type 89 | 90 | private struct MIMEType { 91 | let type: String 92 | let subtype: String 93 | 94 | init?(_ string: String) { 95 | let components: [String] = { 96 | let stripped = string.stringByTrimmingCharactersInSet(NSCharacterSet.whitespaceAndNewlineCharacterSet()) 97 | let split = stripped.substringToIndex(stripped.rangeOfString(";")?.startIndex ?? stripped.endIndex) 98 | return split.componentsSeparatedByString("/") 99 | }() 100 | 101 | if let 102 | type = components.first, 103 | subtype = components.last 104 | { 105 | self.type = type 106 | self.subtype = subtype 107 | } else { 108 | return nil 109 | } 110 | } 111 | 112 | func matches(MIME: MIMEType) -> Bool { 113 | switch (type, subtype) { 114 | case (MIME.type, MIME.subtype), (MIME.type, "*"), ("*", MIME.subtype), ("*", "*"): 115 | return true 116 | default: 117 | return false 118 | } 119 | } 120 | } 121 | 122 | /** 123 | Validates that the response has a content type in the specified array. 124 | 125 | If validation fails, subsequent calls to response handlers will have an associated error. 126 | 127 | - parameter contentType: The acceptable content types, which may specify wildcard types and/or subtypes. 128 | 129 | - returns: The request. 130 | */ 131 | public func validate(contentType acceptableContentTypes: S) -> Self { 132 | return validate { _, response in 133 | guard let validData = self.delegate.data where validData.length > 0 else { return .Success } 134 | 135 | if let 136 | responseContentType = response.MIMEType, 137 | responseMIMEType = MIMEType(responseContentType) 138 | { 139 | for contentType in acceptableContentTypes { 140 | if let acceptableMIMEType = MIMEType(contentType) where acceptableMIMEType.matches(responseMIMEType) { 141 | return .Success 142 | } 143 | } 144 | } else { 145 | for contentType in acceptableContentTypes { 146 | if let MIMEType = MIMEType(contentType) where MIMEType.type == "*" && MIMEType.subtype == "*" { 147 | return .Success 148 | } 149 | } 150 | } 151 | 152 | let failureReason: String 153 | 154 | if let responseContentType = response.MIMEType { 155 | failureReason = ( 156 | "Response content type \"\(responseContentType)\" does not match any acceptable " + 157 | "content types: \(acceptableContentTypes)" 158 | ) 159 | } else { 160 | failureReason = "Response content type was missing and acceptable content type does not match \"*/*\"" 161 | } 162 | 163 | return .Failure(Error.errorWithCode(.ContentTypeValidationFailed, failureReason: failureReason)) 164 | } 165 | } 166 | 167 | // MARK: - Automatic 168 | 169 | /** 170 | Validates that the response has a status code in the default acceptable range of 200...299, and that the content 171 | type matches any specified in the Accept HTTP header field. 172 | 173 | If validation fails, subsequent calls to response handlers will have an associated error. 174 | 175 | - returns: The request. 176 | */ 177 | public func validate() -> Self { 178 | let acceptableStatusCodes: Range = 200..<300 179 | let acceptableContentTypes: [String] = { 180 | if let accept = request?.valueForHTTPHeaderField("Accept") { 181 | return accept.componentsSeparatedByString(",") 182 | } 183 | 184 | return ["*/*"] 185 | }() 186 | 187 | return validate(statusCode: acceptableStatusCodes).validate(contentType: acceptableContentTypes) 188 | } 189 | } 190 | -------------------------------------------------------------------------------- /Brainwaves/Pods/Manifest.lock: -------------------------------------------------------------------------------- 1 | PODS: 2 | - Alamofire (3.3.0) 3 | 4 | DEPENDENCIES: 5 | - Alamofire (~> 3.0) 6 | 7 | SPEC CHECKSUMS: 8 | Alamofire: 9054db4a1b1ca9e363223183e01cea380159a27c 9 | 10 | COCOAPODS: 0.38.2 11 | -------------------------------------------------------------------------------- /Brainwaves/Pods/Pods.xcodeproj/xcuserdata/Nikhil.xcuserdatad/xcschemes/Alamofire.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 32 | 33 | 34 | 35 | 45 | 46 | 47 | 48 | 54 | 55 | 57 | 58 | 61 | 62 | 63 | -------------------------------------------------------------------------------- /Brainwaves/Pods/Pods.xcodeproj/xcuserdata/Nikhil.xcuserdatad/xcschemes/Pods-Brainwaves.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 32 | 33 | 34 | 35 | 45 | 46 | 47 | 48 | 54 | 55 | 57 | 58 | 61 | 62 | 63 | -------------------------------------------------------------------------------- /Brainwaves/Pods/Pods.xcodeproj/xcuserdata/Nikhil.xcuserdatad/xcschemes/xcschememanagement.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | SchemeUserState 6 | 7 | Alamofire.xcscheme 8 | 9 | isShown 10 | 11 | 12 | Pods-Brainwaves.xcscheme 13 | 14 | isShown 15 | 16 | 17 | 18 | SuppressBuildableAutocreation 19 | 20 | 9219B98EB82AD96713EE09393BF3142B 21 | 22 | primary 23 | 24 | 25 | C1256B9A6C84E34942961B033EDF92D2 26 | 27 | primary 28 | 29 | 30 | 31 | 32 | 33 | -------------------------------------------------------------------------------- /Brainwaves/Pods/Target Support Files/Alamofire/Alamofire-Private.xcconfig: -------------------------------------------------------------------------------- 1 | #include "Alamofire.xcconfig" 2 | GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 3 | HEADER_SEARCH_PATHS = "${PODS_ROOT}/Headers/Private" "${PODS_ROOT}/Headers/Private/Alamofire" "${PODS_ROOT}/Headers/Public" 4 | OTHER_SWIFT_FLAGS = $(inherited) "-D" "COCOAPODS" 5 | PODS_ROOT = ${SRCROOT} 6 | SKIP_INSTALL = YES -------------------------------------------------------------------------------- /Brainwaves/Pods/Target Support Files/Alamofire/Alamofire-dummy.m: -------------------------------------------------------------------------------- 1 | #import 2 | @interface PodsDummy_Alamofire : NSObject 3 | @end 4 | @implementation PodsDummy_Alamofire 5 | @end 6 | -------------------------------------------------------------------------------- /Brainwaves/Pods/Target Support Files/Alamofire/Alamofire-prefix.pch: -------------------------------------------------------------------------------- 1 | #ifdef __OBJC__ 2 | #import 3 | #endif 4 | 5 | -------------------------------------------------------------------------------- /Brainwaves/Pods/Target Support Files/Alamofire/Alamofire-umbrella.h: -------------------------------------------------------------------------------- 1 | #import 2 | 3 | 4 | FOUNDATION_EXPORT double AlamofireVersionNumber; 5 | FOUNDATION_EXPORT const unsigned char AlamofireVersionString[]; 6 | 7 | -------------------------------------------------------------------------------- /Brainwaves/Pods/Target Support Files/Alamofire/Alamofire.modulemap: -------------------------------------------------------------------------------- 1 | framework module Alamofire { 2 | umbrella header "Alamofire-umbrella.h" 3 | 4 | export * 5 | module * { export * } 6 | } 7 | -------------------------------------------------------------------------------- /Brainwaves/Pods/Target Support Files/Alamofire/Alamofire.xcconfig: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nikhiljay/brainwaves/42d96dccedf09504589fc9e14e3b470de7f5c0b2/Brainwaves/Pods/Target Support Files/Alamofire/Alamofire.xcconfig -------------------------------------------------------------------------------- /Brainwaves/Pods/Target Support Files/Alamofire/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | ${EXECUTABLE_NAME} 9 | CFBundleIdentifier 10 | org.cocoapods.${PRODUCT_NAME:rfc1034identifier} 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | ${PRODUCT_NAME} 15 | CFBundlePackageType 16 | FMWK 17 | CFBundleShortVersionString 18 | 3.3.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | ${CURRENT_PROJECT_VERSION} 23 | NSPrincipalClass 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /Brainwaves/Pods/Target Support Files/Pods-Brainwaves/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | ${EXECUTABLE_NAME} 9 | CFBundleIdentifier 10 | org.cocoapods.${PRODUCT_NAME:rfc1034identifier} 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | ${PRODUCT_NAME} 15 | CFBundlePackageType 16 | FMWK 17 | CFBundleShortVersionString 18 | 1.0.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | ${CURRENT_PROJECT_VERSION} 23 | NSPrincipalClass 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /Brainwaves/Pods/Target Support Files/Pods-Brainwaves/Pods-Brainwaves-acknowledgements.markdown: -------------------------------------------------------------------------------- 1 | # Acknowledgements 2 | This application makes use of the following third party libraries: 3 | 4 | ## Alamofire 5 | 6 | Copyright (c) 2014–2016 Alamofire Software Foundation (http://alamofire.org/) 7 | 8 | Permission is hereby granted, free of charge, to any person obtaining a copy 9 | of this software and associated documentation files (the "Software"), to deal 10 | in the Software without restriction, including without limitation the rights 11 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 12 | copies of the Software, and to permit persons to whom the Software is 13 | furnished to do so, subject to the following conditions: 14 | 15 | The above copyright notice and this permission notice shall be included in 16 | all copies or substantial portions of the Software. 17 | 18 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 21 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 23 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 24 | THE SOFTWARE. 25 | 26 | Generated by CocoaPods - http://cocoapods.org 27 | -------------------------------------------------------------------------------- /Brainwaves/Pods/Target Support Files/Pods-Brainwaves/Pods-Brainwaves-acknowledgements.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | PreferenceSpecifiers 6 | 7 | 8 | FooterText 9 | This application makes use of the following third party libraries: 10 | Title 11 | Acknowledgements 12 | Type 13 | PSGroupSpecifier 14 | 15 | 16 | FooterText 17 | Copyright (c) 2014–2016 Alamofire Software Foundation (http://alamofire.org/) 18 | 19 | Permission is hereby granted, free of charge, to any person obtaining a copy 20 | of this software and associated documentation files (the "Software"), to deal 21 | in the Software without restriction, including without limitation the rights 22 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 23 | copies of the Software, and to permit persons to whom the Software is 24 | furnished to do so, subject to the following conditions: 25 | 26 | The above copyright notice and this permission notice shall be included in 27 | all copies or substantial portions of the Software. 28 | 29 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 30 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 31 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 32 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 33 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 34 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 35 | THE SOFTWARE. 36 | 37 | Title 38 | Alamofire 39 | Type 40 | PSGroupSpecifier 41 | 42 | 43 | FooterText 44 | Generated by CocoaPods - http://cocoapods.org 45 | Title 46 | 47 | Type 48 | PSGroupSpecifier 49 | 50 | 51 | StringsTable 52 | Acknowledgements 53 | Title 54 | Acknowledgements 55 | 56 | 57 | -------------------------------------------------------------------------------- /Brainwaves/Pods/Target Support Files/Pods-Brainwaves/Pods-Brainwaves-dummy.m: -------------------------------------------------------------------------------- 1 | #import 2 | @interface PodsDummy_Pods_Brainwaves : NSObject 3 | @end 4 | @implementation PodsDummy_Pods_Brainwaves 5 | @end 6 | -------------------------------------------------------------------------------- /Brainwaves/Pods/Target Support Files/Pods-Brainwaves/Pods-Brainwaves-frameworks.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | set -e 3 | 4 | echo "mkdir -p ${CONFIGURATION_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}" 5 | mkdir -p "${CONFIGURATION_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}" 6 | 7 | SWIFT_STDLIB_PATH="${DT_TOOLCHAIN_DIR}/usr/lib/swift/${PLATFORM_NAME}" 8 | 9 | install_framework() 10 | { 11 | if [ -r "${BUILT_PRODUCTS_DIR}/$1" ]; then 12 | local source="${BUILT_PRODUCTS_DIR}/$1" 13 | else 14 | local source="${BUILT_PRODUCTS_DIR}/$(basename "$1")" 15 | fi 16 | 17 | local destination="${CONFIGURATION_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}" 18 | 19 | if [ -L "${source}" ]; then 20 | echo "Symlinked..." 21 | source="$(readlink "${source}")" 22 | fi 23 | 24 | # use filter instead of exclude so missing patterns dont' throw errors 25 | echo "rsync -av --filter \"- CVS/\" --filter \"- .svn/\" --filter \"- .git/\" --filter \"- .hg/\" --filter \"- Headers\" --filter \"- PrivateHeaders\" --filter \"- Modules\" \"${source}\" \"${destination}\"" 26 | rsync -av --filter "- CVS/" --filter "- .svn/" --filter "- .git/" --filter "- .hg/" --filter "- Headers" --filter "- PrivateHeaders" --filter "- Modules" "${source}" "${destination}" 27 | 28 | # Resign the code if required by the build settings to avoid unstable apps 29 | code_sign_if_enabled "${destination}/$(basename "$1")" 30 | 31 | # Embed linked Swift runtime libraries 32 | local basename 33 | basename="$(basename "$1" | sed -E s/\\..+// && exit ${PIPESTATUS[0]})" 34 | local swift_runtime_libs 35 | swift_runtime_libs=$(xcrun otool -LX "${CONFIGURATION_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/${basename}.framework/${basename}" | grep --color=never @rpath/libswift | sed -E s/@rpath\\/\(.+dylib\).*/\\1/g | uniq -u && exit ${PIPESTATUS[0]}) 36 | for lib in $swift_runtime_libs; do 37 | echo "rsync -auv \"${SWIFT_STDLIB_PATH}/${lib}\" \"${destination}\"" 38 | rsync -auv "${SWIFT_STDLIB_PATH}/${lib}" "${destination}" 39 | code_sign_if_enabled "${destination}/${lib}" 40 | done 41 | } 42 | 43 | # Signs a framework with the provided identity 44 | code_sign_if_enabled() { 45 | if [ -n "${EXPANDED_CODE_SIGN_IDENTITY}" -a "${CODE_SIGNING_REQUIRED}" != "NO" -a "${CODE_SIGNING_ALLOWED}" != "NO" ]; then 46 | # Use the current code_sign_identitiy 47 | echo "Code Signing $1 with Identity ${EXPANDED_CODE_SIGN_IDENTITY_NAME}" 48 | echo "/usr/bin/codesign --force --sign ${EXPANDED_CODE_SIGN_IDENTITY} --preserve-metadata=identifier,entitlements \"$1\"" 49 | /usr/bin/codesign --force --sign ${EXPANDED_CODE_SIGN_IDENTITY} --preserve-metadata=identifier,entitlements "$1" 50 | fi 51 | } 52 | 53 | 54 | if [[ "$CONFIGURATION" == "Debug" ]]; then 55 | install_framework 'Pods-Brainwaves/Alamofire.framework' 56 | fi 57 | if [[ "$CONFIGURATION" == "Release" ]]; then 58 | install_framework 'Pods-Brainwaves/Alamofire.framework' 59 | fi 60 | -------------------------------------------------------------------------------- /Brainwaves/Pods/Target Support Files/Pods-Brainwaves/Pods-Brainwaves-resources.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | set -e 3 | 4 | mkdir -p "${CONFIGURATION_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}" 5 | 6 | RESOURCES_TO_COPY=${PODS_ROOT}/resources-to-copy-${TARGETNAME}.txt 7 | > "$RESOURCES_TO_COPY" 8 | 9 | XCASSET_FILES=() 10 | 11 | realpath() { 12 | DIRECTORY="$(cd "${1%/*}" && pwd)" 13 | FILENAME="${1##*/}" 14 | echo "$DIRECTORY/$FILENAME" 15 | } 16 | 17 | install_resource() 18 | { 19 | case $1 in 20 | *.storyboard) 21 | echo "ibtool --reference-external-strings-file --errors --warnings --notices --output-format human-readable-text --compile ${CONFIGURATION_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename \"$1\" .storyboard`.storyboardc ${PODS_ROOT}/$1 --sdk ${SDKROOT}" 22 | ibtool --reference-external-strings-file --errors --warnings --notices --output-format human-readable-text --compile "${CONFIGURATION_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename \"$1\" .storyboard`.storyboardc" "${PODS_ROOT}/$1" --sdk "${SDKROOT}" 23 | ;; 24 | *.xib) 25 | echo "ibtool --reference-external-strings-file --errors --warnings --notices --output-format human-readable-text --compile ${CONFIGURATION_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename \"$1\" .xib`.nib ${PODS_ROOT}/$1 --sdk ${SDKROOT}" 26 | ibtool --reference-external-strings-file --errors --warnings --notices --output-format human-readable-text --compile "${CONFIGURATION_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename \"$1\" .xib`.nib" "${PODS_ROOT}/$1" --sdk "${SDKROOT}" 27 | ;; 28 | *.framework) 29 | echo "mkdir -p ${CONFIGURATION_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}" 30 | mkdir -p "${CONFIGURATION_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}" 31 | echo "rsync -av ${PODS_ROOT}/$1 ${CONFIGURATION_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}" 32 | rsync -av "${PODS_ROOT}/$1" "${CONFIGURATION_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}" 33 | ;; 34 | *.xcdatamodel) 35 | echo "xcrun momc \"${PODS_ROOT}/$1\" \"${CONFIGURATION_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename "$1"`.mom\"" 36 | xcrun momc "${PODS_ROOT}/$1" "${CONFIGURATION_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename "$1" .xcdatamodel`.mom" 37 | ;; 38 | *.xcdatamodeld) 39 | echo "xcrun momc \"${PODS_ROOT}/$1\" \"${CONFIGURATION_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename "$1" .xcdatamodeld`.momd\"" 40 | xcrun momc "${PODS_ROOT}/$1" "${CONFIGURATION_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename "$1" .xcdatamodeld`.momd" 41 | ;; 42 | *.xcmappingmodel) 43 | echo "xcrun mapc \"${PODS_ROOT}/$1\" \"${CONFIGURATION_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename "$1" .xcmappingmodel`.cdm\"" 44 | xcrun mapc "${PODS_ROOT}/$1" "${CONFIGURATION_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename "$1" .xcmappingmodel`.cdm" 45 | ;; 46 | *.xcassets) 47 | ABSOLUTE_XCASSET_FILE=$(realpath "${PODS_ROOT}/$1") 48 | XCASSET_FILES+=("$ABSOLUTE_XCASSET_FILE") 49 | ;; 50 | /*) 51 | echo "$1" 52 | echo "$1" >> "$RESOURCES_TO_COPY" 53 | ;; 54 | *) 55 | echo "${PODS_ROOT}/$1" 56 | echo "${PODS_ROOT}/$1" >> "$RESOURCES_TO_COPY" 57 | ;; 58 | esac 59 | } 60 | 61 | mkdir -p "${CONFIGURATION_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}" 62 | rsync -avr --copy-links --no-relative --exclude '*/.svn/*' --files-from="$RESOURCES_TO_COPY" / "${CONFIGURATION_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}" 63 | if [[ "${ACTION}" == "install" ]]; then 64 | mkdir -p "${INSTALL_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}" 65 | rsync -avr --copy-links --no-relative --exclude '*/.svn/*' --files-from="$RESOURCES_TO_COPY" / "${INSTALL_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}" 66 | fi 67 | rm -f "$RESOURCES_TO_COPY" 68 | 69 | if [[ -n "${WRAPPER_EXTENSION}" ]] && [ "`xcrun --find actool`" ] && [ -n "$XCASSET_FILES" ] 70 | then 71 | case "${TARGETED_DEVICE_FAMILY}" in 72 | 1,2) 73 | TARGET_DEVICE_ARGS="--target-device ipad --target-device iphone" 74 | ;; 75 | 1) 76 | TARGET_DEVICE_ARGS="--target-device iphone" 77 | ;; 78 | 2) 79 | TARGET_DEVICE_ARGS="--target-device ipad" 80 | ;; 81 | *) 82 | TARGET_DEVICE_ARGS="--target-device mac" 83 | ;; 84 | esac 85 | 86 | # Find all other xcassets (this unfortunately includes those of path pods and other targets). 87 | OTHER_XCASSETS=$(find "$PWD" -iname "*.xcassets" -type d) 88 | while read line; do 89 | if [[ $line != "`realpath $PODS_ROOT`*" ]]; then 90 | XCASSET_FILES+=("$line") 91 | fi 92 | done <<<"$OTHER_XCASSETS" 93 | 94 | printf "%s\0" "${XCASSET_FILES[@]}" | xargs -0 xcrun actool --output-format human-readable-text --notices --warnings --platform "${PLATFORM_NAME}" --minimum-deployment-target "${IPHONEOS_DEPLOYMENT_TARGET}" ${TARGET_DEVICE_ARGS} --compress-pngs --compile "${BUILT_PRODUCTS_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}" 95 | fi 96 | -------------------------------------------------------------------------------- /Brainwaves/Pods/Target Support Files/Pods-Brainwaves/Pods-Brainwaves-umbrella.h: -------------------------------------------------------------------------------- 1 | #import 2 | 3 | 4 | FOUNDATION_EXPORT double Pods_BrainwavesVersionNumber; 5 | FOUNDATION_EXPORT const unsigned char Pods_BrainwavesVersionString[]; 6 | 7 | -------------------------------------------------------------------------------- /Brainwaves/Pods/Target Support Files/Pods-Brainwaves/Pods-Brainwaves.debug.xcconfig: -------------------------------------------------------------------------------- 1 | GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 2 | LD_RUNPATH_SEARCH_PATHS = $(inherited) '@executable_path/Frameworks' '@loader_path/Frameworks' 3 | OTHER_CFLAGS = $(inherited) -iquote "$CONFIGURATION_BUILD_DIR/Alamofire.framework/Headers" 4 | OTHER_LDFLAGS = $(inherited) -framework "Alamofire" 5 | OTHER_SWIFT_FLAGS = $(inherited) "-D" "COCOAPODS" 6 | PODS_FRAMEWORK_BUILD_PATH = $(BUILD_DIR)/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)/Pods-Brainwaves 7 | PODS_ROOT = ${SRCROOT}/Pods -------------------------------------------------------------------------------- /Brainwaves/Pods/Target Support Files/Pods-Brainwaves/Pods-Brainwaves.modulemap: -------------------------------------------------------------------------------- 1 | framework module Pods_Brainwaves { 2 | umbrella header "Pods-Brainwaves-umbrella.h" 3 | 4 | export * 5 | module * { export * } 6 | } 7 | -------------------------------------------------------------------------------- /Brainwaves/Pods/Target Support Files/Pods-Brainwaves/Pods-Brainwaves.release.xcconfig: -------------------------------------------------------------------------------- 1 | GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 2 | LD_RUNPATH_SEARCH_PATHS = $(inherited) '@executable_path/Frameworks' '@loader_path/Frameworks' 3 | OTHER_CFLAGS = $(inherited) -iquote "$CONFIGURATION_BUILD_DIR/Alamofire.framework/Headers" 4 | OTHER_LDFLAGS = $(inherited) -framework "Alamofire" 5 | OTHER_SWIFT_FLAGS = $(inherited) "-D" "COCOAPODS" 6 | PODS_FRAMEWORK_BUILD_PATH = $(BUILD_DIR)/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)/Pods-Brainwaves 7 | PODS_ROOT = ${SRCROOT}/Pods -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Measuring Brainwaves 2 | 3 | [![GitHub version](https://img.shields.io/badge/version-1.0-blue.svg)](https://github.com/nikhiljay/brainwaves/releases) 4 | ![](https://img.shields.io/badge/platform-ios%20%7C%20osx-lightgray.svg) 5 | ![](https://img.shields.io/badge/dependencies-up%20to%20date-brightgreen.svg) 6 | 7 | This is my project for Advanced Authentic Research (AAR). Follow the progress of this project on my blog. This project uses emokit which is an open source driver used to access the Emotiv Device raw data. 8 | 9 | ![](https://pugiblog.files.wordpress.com/2015/12/section1-epoc.png) 10 | 11 | ## Extracting the Raw Data 12 | 13 | 1) Download the repository 14 | 15 | ``` 16 | $ git clone https://github.com/nikhiljay/brainwaves.git 17 | ``` 18 | 19 | 2) Plug in your Emotiv's USB dongle. 20 | 21 | 3) Find the Serial Number of the Emotiv by downloading HIDAPI. 22 | 23 | ``` 24 | $ git clone https://github.com/signal11/hidapi.git 25 | $ cd hidapi 26 | ``` 27 | 28 | 4) In the HIDAPI go to the directory that corresponds to your operating system and run: 29 | 30 | ``` 31 | $ make -f Makefile-manual 32 | ``` 33 | 34 | 5) A hidtest file should be created in the same directory. Open the hidtest to run it. On linux, you must run this using sudo. 35 | 36 | 6) The output should be a list of devices that are connected to the computer. Look at the Emotiv device information and copy the Serial Number. 37 | 38 | 7) In the brianwaves project, go to the emokit directory. 39 | 40 | ``` 41 | $ cd emokit/python/emokit 42 | ``` 43 | 44 | 8) Open "emotiv.py" and paste the serial number on line 361 where it says: 45 | 46 | ``` 47 | serial_number="" 48 | ``` 49 | 50 | 10) Run the "emotiv.py" file. 51 | 52 | ``` 53 | $ python emotiv.py 54 | ``` 55 | 56 | 11) If there are any dependencies that need to be installed used the "pip" command. 57 | 58 | ``` 59 | $ sudo pip install [missing dependency goes here] 60 | ``` 61 | 62 | 12) Install all dependencies until the following error is produced: 63 | 64 | ``` 65 | Traceback (most recent call last): 66 | File "emotiv.py", line 674, in 67 | a.setup() 68 | File "emotiv.py", line 432, in setup 69 | self.setup_darwin() 70 | File "emotiv.py", line 537, in setup_darwin 71 | hidraw = hid.device(0x21a1, 0x0001) 72 | File "hid.pyx", line 45, in hid.device.__cinit__ (hid.c:1280) 73 | ``` 74 | 75 | 9) Turn on the Emotiv and try again. A succesful output should be printed: 76 | 77 | ![](http://i.imgur.com/kKuvuHlm.png) 78 | 79 | These electrodes in the picture above represent certain parts of the brain shown here: 80 | 81 | ![](http://i.imgur.com/xTtsqc7m.jpg) 82 | 83 | ## Displaying Data on an iOS Device 84 | 85 | After extracting the Emotiv data, I sent the data as a JSON file to a local server. Then, I created an iOS app and used Alamofire to get request the data from the server. I created the app so that it would display the raw data on the iOS device. Here is what it looks like so far: 86 | 87 | ![](https://media.giphy.com/media/nWbdCoU9LZfVe/giphy.gif) 88 | -------------------------------------------------------------------------------- /emokit/.gitignore: -------------------------------------------------------------------------------- 1 | *build* 2 | *.pyc -------------------------------------------------------------------------------- /emokit/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required (VERSION 2.6) 2 | PROJECT(emokit) 3 | 4 | SET(BUILD_SHARED_LIBS false) 5 | IF($ENV{EMOKIT_BUILD_SHARED_LIBS}) 6 | SET(BUILD_SHARED_LIBS true) 7 | ENDIF() 8 | 9 | SET(LIBEMOKIT_HEADERS 10 | ${CMAKE_SOURCE_DIR}/include/emokit/emokit.h 11 | ) 12 | 13 | LIST(APPEND CMAKE_MODULE_PATH ${CMAKE_SOURCE_DIR}/cmake_modules) 14 | SET(EXECUTABLE_OUTPUT_PATH ${CMAKE_BINARY_DIR}/bin) 15 | SET(LIBRARY_OUTPUT_PATH ${CMAKE_BINARY_DIR}/lib) 16 | 17 | FIND_PACKAGE(Mcrypt REQUIRED) 18 | FIND_PACKAGE(HIDAPI REQUIRED) 19 | 20 | SET(LIBS ${Mcrypt_LIBS} ${HIDAPI_LIBRARIES}) 21 | 22 | IF(LINUX) 23 | SET(LIBS ${LIBS} udev) 24 | ELSEIF(APPLE) 25 | SET(LIBS ${LIBS} "-framework IOKit" "-framework CoreFoundation") 26 | ENDIF() 27 | 28 | 29 | MESSAGE(STATUS ${LIBS}) 30 | INCLUDE_DIRECTORIES(${HIDAPI_INCLUDE_DIR} ${Mcrypt_INCLUDE_DIR} ${CMAKE_SOURCE_DIR}/include) 31 | 32 | ADD_SUBDIRECTORY(src) 33 | ADD_SUBDIRECTORY(examples/emokitd) 34 | ADD_SUBDIRECTORY(examples/contact) 35 | ADD_SUBDIRECTORY(examples/emokit_osc) 36 | 37 | ########################################## 38 | ## PKGCONFIG file ### 39 | ########################################## 40 | 41 | IF(LINUX) 42 | IF (EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/emokit.pc.in") 43 | MESSAGE(STATUS "configured ${CMAKE_CURRENT_SOURCE_DIR}/emokit.pc.in --> ${CMAKE_CURRENT_BINARY_DIR}/emokit.pc") 44 | CONFIGURE_FILE(${CMAKE_CURRENT_SOURCE_DIR}/emokit.pc.in 45 | ${CMAKE_CURRENT_BINARY_DIR}/emokit.pc 46 | @ONLY ) 47 | 48 | INSTALL(FILES 49 | ${CMAKE_CURRENT_BINARY_DIR}/emokit.pc 50 | DESTINATION lib/pkgconfig 51 | ) 52 | ENDIF(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/emokit.pc.in") 53 | ENDIF() 54 | -------------------------------------------------------------------------------- /emokit/FAQ.md: -------------------------------------------------------------------------------- 1 | Emokit FAQ 2 | ========== 3 | 4 | * What data does emokit give me? 5 | 6 | The raw channels of the headset 7 | 8 | Battery power of the headset (in development at time of FAQ writing) 9 | 10 | Signal quality of each connection on the headset (in development at time of FAQ writing) 11 | 12 | * What data does emokit not give me? 13 | 14 | Processed data that can tell you moods or muscles or whatever. 15 | 16 | Basically, if you aren't up to doing a bit of DSP and aren't really 17 | educated in mathematics and neuroscience, you should use emokit under 18 | another library that will do the geekery for you. We publish emokit as 19 | a low level access tool, nothing more. 20 | 21 | * Does emokit work with all emotiv headsets? 22 | 23 | As far as we know, yes. If it doesn't work with yours, file an issue 24 | on the github project (http://github.com/openyou/emokit/issues) 25 | 26 | * I heard you need to know your key or something? 27 | 28 | That doesn't apply anymore. Emokit should work with all headsets and 29 | dongles. If it doesn't, file an issue (http://github.com/openyou/emokit/issues). 30 | 31 | * So I really don't need to know my key or whatever now? 32 | 33 | You shouldn't. It should "just work". So please stop asking. 34 | 35 | * OPTIONAL READING: The history of the key generation, and why you used to need keys 36 | 37 | When emokit first came out (For more information on this, check out 38 | Announcement.md in the doc directory), we only knew part of how the 39 | encryption worked, mainly because Daeken finished the first round, 40 | qDot took things over, and then neither of them had time to do 41 | anything for a while. So there was a lot of news that went around of 42 | "only certain headsets/keys work", so on and so forth. 43 | 44 | We managed to get lucky with the method for a while, because Emotiv 45 | was reusing keys on USB dongles, so one key would work for many 46 | headsets. Once Emotiv learned of this, they just had to switch out the 47 | firmware flashing on their keys, and emokit no longer worked. 48 | 49 | In late 2011, Daeken finished the key generation code, which means 50 | emokit should now work for any USB key. Note that the encryption 51 | happens on the USB KEY, not the headset. So it's actually tied to 52 | whatever you have plugged in regardless of the headset. 53 | 54 | -------------------------------------------------------------------------------- /emokit/INSTALL: -------------------------------------------------------------------------------- 1 | Installation instructions for Linux (assuming ubuntu/debian packages) 2 | 3 | 4 | CMAKE 5 | Download : http://www.cmake.org/cmake/resources/software.html 6 | Go in the download folder and execute : 7 | 8 | To install cmake you need a working C++ compiler 9 | sudo apt-get install g++ 10 | 11 | tar xzvf cmake-2.8.10.2.tar.gz 12 | cd cmake-2.8.10.2.tar.gz 13 | ./bootstrap 14 | make 15 | sudo make install 16 | 17 | 18 | MCRYPT 19 | First install the dependencies : 20 | sudo apt-get install libmcrypt-dev libmhash-dev git 21 | 22 | Download : http://sourceforge.net/projects/mcrypt/files/latest/download 23 | Go in the download folder and execute : 24 | 25 | tar xzvf mcrypt-2.6.8.tar.gz 26 | cd mcrypt-2.6.8/ 27 | ./configure 28 | make 29 | make install 30 | 31 | 32 | HIPAPI 33 | First install the dependencies : 34 | sudo apt-get install libudev-dev libusb-1.0-0-dev libtool dh-autoreconf 35 | 36 | Download : https://github.com/signal11/hidapi/archive/master.zip 37 | IT WILL NOT WORK if you downloaded from: hidapi-0.7.0.zip from https://github.com/signal11/hidapi/downloads or the command git clone git://github.com/signal11/hidapi.git 38 | Extract the zip file and use the following commands : 39 | 40 | unzip hidapid-master.zip 41 | cd hidapid-master 42 | ./bootstrap 43 | ./configure 44 | make 45 | sudo make install 46 | 47 | 48 | EMOKIT 49 | Download https://github.com/openyou/emokit/archive/master.zip 50 | 51 | unzip emokit-master.zip 52 | cd emokit-master 53 | cmake . 54 | make 55 | 56 | This will build a static library. If you want to build a shared library 57 | instead, set the environment variable EMOKIT_BUILD_SHARED_LIBS. 58 | 59 | If you get: 60 | $ cmake . 61 | -- Found mcrypt: /usr/lib/libmcrypt.so 62 | -- Found HIDAPI: /usr/local/lib/libhidapi-hidraw.so 63 | -- /usr/lib/libmcrypt.so/usr/local/lib/libhidapi-hidraw.so 64 | -- oscpack NOT found. 65 | -- oscpack not found, not building emokit osc server 66 | -- Configuring done 67 | -- Generating done 68 | -- Build files have been written to: /emokit-master 69 | 70 | sudo apt-get install liboscpack* 71 | 72 | $ cmake . 73 | -- Found mcrypt: /usr/lib/libmcrypt.so 74 | -- /usr/lib/libmcrypt.so/usr/local/lib/libhidapi-hidraw.so 75 | -- Found oscpack: /usr/lib/liboscpack.so 76 | -- Configuring done 77 | -- Generating done 78 | -- Build files have been written to: /emokit-master 79 | 80 | If you try to run a python example and get 81 | ImportError: No module named gevent 82 | 83 | sudo pip install gevent 84 | sudo pip install greenlet 85 | -------------------------------------------------------------------------------- /emokit/LICENSE: -------------------------------------------------------------------------------- 1 | Aes.py copyright 2001 Bram Cohen and released into the public domain. 2 | 3 | Everything else: 4 | 5 | In countries where it's respected, everything is released into the 6 | public domain; otherwise it's released under the following terms: 7 | 8 | Copyright (c) 2010-2012, Cody Brocious, Kyle Machulis/Nonpolynomial Labs 9 | 10 | All rights reserved. 11 | 12 | Redistribution and use in source and binary forms, with or without 13 | modification, are permitted provided that the following conditions are met: 14 | * Redistributions of source code must retain the above copyright 15 | notice, this list of conditions and the following disclaimer. 16 | * Redistributions in binary form must reproduce the above copyright 17 | notice, this list of conditions and the following disclaimer in the 18 | documentation and/or other materials provided with the distribution. 19 | * The names of its contributors may not be used to endorse or promote products 20 | derived from this software without specific prior written permission. 21 | 22 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 23 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 24 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 25 | DISCLAIMED. IN NO EVENT SHALL Cody Brocious BE LIABLE FOR ANY 26 | DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 27 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 28 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 29 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 30 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 31 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -------------------------------------------------------------------------------- /emokit/README.md: -------------------------------------------------------------------------------- 1 | Emokit 2 | ====== 3 | 4 | Reverse engineering and original code written by 5 | 6 | * Cody Brocious (http://github.com/daeken) 7 | * Kyle Machulis (http://github.com/qdot) 8 | 9 | Contributions by 10 | 11 | * Severin Lemaignan - Base C Library and mcrypt functionality 12 | * Sharif Olorin (http://github.com/fractalcat) - hidapi support 13 | * Bill Schumacher (http://github.com/bschumacher) - Fixed the Python library 14 | 15 | Description 16 | =========== 17 | 18 | Emokit is a set of language for user space access to the raw stream 19 | data from the Emotiv EPOC headset. Note that this will not give you 20 | processed data (i.e. anything available in the Emo Suites in the 21 | software), just the raw sensor data. 22 | 23 | The C library is backed by hidapi, and should work on any platform 24 | that hidapi also works on. 25 | 26 | Information 27 | =========== 28 | 29 | FAQ (READ BEFORE FILING ISSUES): https://github.com/openyou/emokit/blob/master/FAQ.md 30 | 31 | If you have a problem not covered in the FAQ, file it as an 32 | issue on the github project. 33 | 34 | PLEASE DO NOT EMAIL OR OTHERWISE CONTACT THE DEVELOPERS DIRECTLY. 35 | Seriously. I'm sick of email and random facebook friendings asking for 36 | help. What happens on the project stays on the project. 37 | 38 | Issues: http://github.com/openyou/emokit/issues 39 | 40 | If you are using the Python library and a research headset you may have 41 | to change the is_research variable in emotiv.py's setup_crypto function. 42 | 43 | Required Libraries 44 | ================== 45 | 46 | Python 47 | ------ 48 | 49 | * pywinhid (Windows Only) - https://pypi.python.org/pypi/pywinusb/ 50 | * (OS X) HIDAPI - http://www.signal11.us/oss/hidapi/ 51 | * (OS X) cython-hidapi - https://github.com/gbishop/cython-hidapi 52 | * pycrypto - https://www.dlitz.net/software/pycrypto/ 53 | * gevent - http://gevent.org 54 | * realpath - http://? sudo apt-get install realpath 55 | 56 | C Language 57 | ---------- 58 | 59 | * CMake - http://www.cmake.org 60 | * libmcrypt - https://sourceforge.net/projects/mcrypt/ 61 | * hidapi - http://www.signal11.us/oss/hidapi/ 62 | 63 | Usage 64 | ===== 65 | 66 | C library 67 | --------- 68 | 69 | See emokitd.c example 70 | 71 | Python library 72 | -------------- 73 | 74 | Code: 75 | 76 | import emotiv 77 | import platform 78 | if platform.system() == "Windows": 79 | import socket 80 | import gevent 81 | 82 | if __name__ == "__main__": 83 | headset = emotiv.Emotiv() 84 | gevent.spawn(headset.setup) 85 | gevent.sleep(0) 86 | try: 87 | while True: 88 | packet = headset.dequeue() 89 | print packet.gyro_x, packet.gyro_y 90 | gevent.sleep(0) 91 | except KeyboardInterrupt: 92 | headset.close() 93 | finally: 94 | headset.close() 95 | 96 | 97 | Bindings 98 | ======== 99 | 100 | Go: https://github.com/fractalcat/emogo 101 | 102 | Platform Specifics Issues 103 | ========================= 104 | 105 | Linux 106 | ----- 107 | 108 | Due to the way hidapi works, the linux version of emokit can run using 109 | either hidraw calls or libusb. These will require different udev rules 110 | for each. We've tried to cover both (as based on hidapi's example udev 111 | file), but your mileage may vary. If you have problems, please post 112 | them to the github issues page (http://github.com/openyou/emokit/issues). 113 | 114 | Your kernel may not support /dev/hidraw devices by default, such as an RPi. 115 | To fix that re-comiple your kernel with /dev/hidraw support 116 | 117 | OS X 118 | ---- 119 | Recent OS versions no longer allow usb devices to become unclaimed by the kernel. 120 | You must use a HIDAPI library. 121 | 122 | The render.py file uses pygame, visit http://pygame.org/wiki/MacCompile 123 | Do not export the architecture compiler flags for recent 64bit versions of OS X. 124 | 125 | 126 | Credits - Cody 127 | ============== 128 | 129 | Huge thanks to everyone who donated to the fund drive that got the 130 | hardware into my hands to build this. 131 | 132 | Thanks to Bryan Bishop and the other guys in #hplusroadmap on Freenode 133 | for your help and support. 134 | 135 | And as always, thanks to my friends and family for supporting me and 136 | suffering through my obsession of the week. 137 | 138 | Credits - Kyle 139 | ============== 140 | 141 | Kyle would like to thank Cody for doing the hard part. 142 | 143 | He would also like to thank emotiv for putting emo on the front of 144 | everything because it's god damn hilarious. I mean, really, Emo 145 | Suites? Saddest hotel EVER. 146 | 147 | # Frequently asked questions 148 | 149 | - *What unit is the data I'm getting back in? How do I get volts out of 150 | it?* 151 | 152 | One least-significant-bit of the fourteen-bit value you get back is 153 | 0.51 microvolts. See the 154 | [specification](http://emotiv.com/upload/manual/EPOCSpecifications.pdf) 155 | for more details. -------------------------------------------------------------------------------- /emokit/cmake_modules/FindHIDAPI.cmake: -------------------------------------------------------------------------------- 1 | # - try to find HIDAPI library 2 | # from http://www.signal11.us/oss/hidapi/ 3 | # 4 | # Cache Variables: (probably not for direct use in your scripts) 5 | # HIDAPI_INCLUDE_DIR 6 | # HIDAPI_LIBRARY 7 | # 8 | # Non-cache variables you might use in your CMakeLists.txt: 9 | # HIDAPI_FOUND 10 | # HIDAPI_INCLUDE_DIRS 11 | # HIDAPI_LIBRARIES 12 | # 13 | # Requires these CMake modules: 14 | # FindPackageHandleStandardArgs (known included with CMake >=2.6.2) 15 | # 16 | # Original Author: 17 | # 2009-2010 Ryan Pavlik 18 | # http://academic.cleardefinition.com 19 | # Iowa State University HCI Graduate Program/VRAC 20 | # 21 | # Copyright Iowa State University 2009-2010. 22 | # Distributed under the Boost Software License, Version 1.0. 23 | # (See accompanying file LICENSE_1_0.txt or copy at 24 | # http://www.boost.org/LICENSE_1_0.txt) 25 | 26 | find_library(HIDAPI_LIBRARY 27 | NAMES hidapi hidapi-hidraw hidapi-libusb) 28 | 29 | find_path(HIDAPI_INCLUDE_DIR 30 | NAMES hidapi/hidapi.h) 31 | 32 | include(FindPackageHandleStandardArgs) 33 | find_package_handle_standard_args(HIDAPI 34 | DEFAULT_MSG 35 | HIDAPI_LIBRARY 36 | HIDAPI_INCLUDE_DIR) 37 | 38 | if(HIDAPI_FOUND) 39 | set(HIDAPI_LIBRARIES "${HIDAPI_LIBRARY}") 40 | 41 | set(HIDAPI_INCLUDE_DIRS "${HIDAPI_INCLUDE_DIR}") 42 | endif() 43 | 44 | mark_as_advanced(HIDAPI_INCLUDE_DIR HIDAPI_LIBRARY) 45 | -------------------------------------------------------------------------------- /emokit/cmake_modules/FindMcrypt.cmake: -------------------------------------------------------------------------------- 1 | # - Find Mcrypt (a cross platform RPC lib/tool) 2 | # This module defines 3 | # Mcrypt_INCLUDE_DIR, where to find Mcrypt headers 4 | # Mcrypt_LIBS, Mcrypt libraries 5 | # Mcrypt_FOUND, If false, do not try to use Mcrypt 6 | 7 | find_path(Mcrypt_INCLUDE_DIR mcrypt.h PATHS 8 | /usr/local/include 9 | /opt/local/include 10 | ) 11 | 12 | 13 | #find_library can't seem to find a 64-bit binary if the 32-bit isn't there 14 | 15 | set(Mcrypt_LIB_PATHS /usr/local/lib /opt/local/lib /usr/lib64) 16 | find_library(Mcrypt_LIB NAMES mcrypt PATHS ${Mcrypt_LIB_PATHS}) 17 | 18 | if (Mcrypt_LIB AND Mcrypt_INCLUDE_DIR) 19 | set(Mcrypt_FOUND TRUE) 20 | set(Mcrypt_LIBS ${Mcrypt_LIB}) 21 | else () 22 | set(Mcrypt_FOUND FALSE) 23 | endif () 24 | 25 | if (Mcrypt_FOUND) 26 | if (NOT Mcrypt_FIND_QUIETLY) 27 | message(STATUS "Found mcrypt: ${Mcrypt_LIBS}") 28 | endif () 29 | else () 30 | if (Mcrypt_FIND_REQUIRED) 31 | message(FATAL_ERROR "Could NOT find mcrypt library.") 32 | endif () 33 | message(STATUS "mcrypt NOT found.") 34 | endif () 35 | 36 | mark_as_advanced( 37 | Mcrypt_LIB 38 | Mcrypt_INCLUDE_DIR 39 | ) 40 | -------------------------------------------------------------------------------- /emokit/cmake_modules/Findlibusb-1.0.cmake: -------------------------------------------------------------------------------- 1 | # - Try to find libusb-1.0 2 | # Once done this will define 3 | # 4 | # LIBUSB_1_FOUND - system has libusb 5 | # LIBUSB_1_INCLUDE_DIRS - the libusb include directory 6 | # LIBUSB_1_LIBRARIES - Link these to use libusb 7 | # LIBUSB_1_DEFINITIONS - Compiler switches required for using libusb 8 | # 9 | # Adapted from cmake-modules Google Code project 10 | # 11 | # Copyright (c) 2006 Andreas Schneider 12 | # 13 | # (Changes for libusb) Copyright (c) 2008 Kyle Machulis 14 | # 15 | # Redistribution and use is allowed according to the terms of the New BSD license. 16 | # For details see the accompanying COPYING-CMAKE-SCRIPTS file. 17 | # 18 | 19 | 20 | if (LIBUSB_1_LIBRARIES AND LIBUSB_1_INCLUDE_DIRS) 21 | # in cache already 22 | set(LIBUSB_FOUND TRUE) 23 | else (LIBUSB_1_LIBRARIES AND LIBUSB_1_INCLUDE_DIRS) 24 | find_path(LIBUSB_1_INCLUDE_DIR 25 | NAMES 26 | libusb.h 27 | PATHS 28 | /usr/include 29 | /usr/local/include 30 | /opt/local/include 31 | /sw/include 32 | PATH_SUFFIXES 33 | libusb-1.0 34 | ) 35 | 36 | find_library(LIBUSB_1_LIBRARY 37 | NAMES 38 | usb-1.0 39 | PATHS 40 | /usr/lib 41 | /usr/local/lib 42 | /opt/local/lib 43 | /sw/lib 44 | ) 45 | 46 | set(LIBUSB_1_INCLUDE_DIRS 47 | ${LIBUSB_1_INCLUDE_DIR} 48 | ) 49 | set(LIBUSB_1_LIBRARIES 50 | ${LIBUSB_1_LIBRARY} 51 | ) 52 | 53 | if (LIBUSB_1_INCLUDE_DIRS AND LIBUSB_1_LIBRARIES) 54 | set(LIBUSB_1_FOUND TRUE) 55 | endif (LIBUSB_1_INCLUDE_DIRS AND LIBUSB_1_LIBRARIES) 56 | 57 | if (LIBUSB_1_FOUND) 58 | if (NOT libusb_1_FIND_QUIETLY) 59 | message(STATUS "Found libusb-1.0:") 60 | message(STATUS " - Includes: ${LIBUSB_1_INCLUDE_DIRS}") 61 | message(STATUS " - Libraries: ${LIBUSB_1_LIBRARIES}") 62 | endif (NOT libusb_1_FIND_QUIETLY) 63 | else (LIBUSB_1_FOUND) 64 | if (libusb_1_FIND_REQUIRED) 65 | message(FATAL_ERROR "Could not find libusb") 66 | endif (libusb_1_FIND_REQUIRED) 67 | endif (LIBUSB_1_FOUND) 68 | 69 | # show the LIBUSB_1_INCLUDE_DIRS and LIBUSB_1_LIBRARIES variables only in the advanced view 70 | mark_as_advanced(LIBUSB_1_INCLUDE_DIRS LIBUSB_1_LIBRARIES) 71 | 72 | endif (LIBUSB_1_LIBRARIES AND LIBUSB_1_INCLUDE_DIRS) -------------------------------------------------------------------------------- /emokit/doc/Announcement.md: -------------------------------------------------------------------------------- 1 | Intro 2 | ===== 3 | 4 | I've been interested in the [Emotiv EPOC](http://emotiv.com/) headset for a while; a $300 14-sensor EEG. It's intended for gaming, but it's quite high quality. There's a research SDK available for $750, but it's Windows-only and totally proprietary. I decided to hack it, and open the consumer headset up to development. Thanks to [donations](http://pledgie.com/campaigns/12906) I got some hardware in hand this weekend. 5 | 6 | I'm happy to announce the Emokit project, an open source interface to the EPOC. The goal is to open it up to development and enable new products and research. For the first time, we have access to a high-quality EEG for $300 -- this is huge. 7 | 8 | Code 9 | ==== 10 | 11 | The code is available on github on the [daeken/Emokit](http://github.com/daeken/Emokit) repository. There's a Python library for interacting with the EPOC, as well as a renderer that will graph the sensor data. 12 | 13 | ![Graph in debug mode](http://i53.tinypic.com/34yyy47.jpg) 14 | 15 | Where things are right now 16 | ========================== 17 | 18 | You can access raw EEG data from the Emotiv EPOC on Windows, Linux, and OS X from Python. Sensor locations can be found at https://github.com/bschumacher/emokit-1/wiki/Sensor-Locations. Word of warning: this project is less than 48 hours old (I just got hardware in my hands Saturday night) and has only been run by me on Windows due to a dead Linux box. It's very much alpha quality right now -- don't trust it. 19 | 20 | How it happened 21 | =============== 22 | 23 | The first step was to figure out how exactly the PC communicates with it. This part was straightforward; it's a USB device with VID=21A1, PID=0001 (note: from walking through the device enum code in the EDK, it seems that PID=0002 might be the development headset, but that's totally unverified). It presents two HID interfaces, "EPOC BCI" and "Brain Waves". Reading data off the "Brain Waves" interface gives you reports of 32 bytes at a time; "EPOC BCI" I'm unsure about. 24 | 25 | Next step was to read some data off the wire and figure out what's going on. I utilized the pywinusb.hid library for this. It was immediately apparent that it's encrypted, so figuring out what the crypto was became the top priority. This took a couple hours due to a few red herrings and failed approaches, but here's what it boiled down to: 26 | 27 | - Throw EmotivControlPanel.exe into IDA. 28 | - Throw EmotivControlPanel.exe into PeID and run the Krypto Analyzer plugin on it. 29 | - You'll see a Rijndael S-Box (used for AES encryption and key schedule initialization) come up from KAnal. 30 | - Using IDA, go to the S-Box address. 31 | - You'll see a single function that references the S-Box -- this is the key initialization code (*not* encryption, as I originally thought). 32 | - Use a debugger (I used the debugger built into IDA for simplicity's sake) and attach to the beginning of the key init function. 33 | - You'll see two arguments: a 16-byte key and an integer containing `16`. 34 | 35 | So that you don't have to do that yourself, here's the key: 31003554381037423100354838003750 or `1\x005T8\x107B1\x005H8\x007P`. Given that, decrypting the data is trivial: it's simply 128-bit AES in ECB mode, block size of 16 bytes. 36 | 37 | The first byte of each report is a counter that goes from 0-127 then to 233, then cycles back to 0. Once this was determined, I figured out the gyro data. To do that, I broke out pygame and wrote a simple app that drew a rectangle at the X and Y coords coming from two bytes of the records. I pretty quickly figured out that the X coord from the gyro is byte 29 and the Y coord is byte 30. The EPOC has some sort of logic in it to reset the gyro baseline levels, but I'm not sure on the details there; the baseline I'm seeing generally (not perfect) is roughly 102 for X and 204 for Y. This lets you get control from the gyro fairly easy. 38 | 39 | That accounts for 3 bytes of the packet, but we have 14 sensors. If you assume that each sensor is represented by 2 bytes of data, that gives us 28 bytes for sensor data. 32 - 28 == 4, so what's the extra byte? Looking at byte 15, it's pretty clear that it's (almost) always zero -- the only time it's non-zero is the very first report from the device. I have absolutely no idea what this is. 40 | 41 | From here, all we have is data from the sensors. Another quick script with pygame and boom, we have a graph renderer for this data. 42 | 43 | However, here's where it gets tough. Figuring out which bytes correspond to which sensors is difficult, because effectively all the signal processing and filtering happens on the PC side, meaning it's not in this library yet. Figuring out the high bytes (which are less noisy and change less frequently) isn't terribly difficult, and I've identified a few of them, but there's a lot of work to be done still. 44 | 45 | What needs to be done 46 | ===================== 47 | 48 | Reversing-wise: 49 | 50 | - Determine which bytes correspond to which signals -- I'm sure someone more knowledgable than myself can do this no problem 51 | - Figure out how the sensor quality is transmitted -- according to some data on the research SDK, there's 4 bits per sensor that give you the signal quality (0=none, 1=very poor, 2=poor, 3=decent, 4=good, 5=very good) 52 | - Figure out how to read the battery meter 53 | 54 | Emokit-wise: 55 | 56 | - Linux and OS X support haven't been tested at all, but they should be good to go 57 | - Build a C library for working with the EPOC 58 | - Build an acquisition module for [OpenViBE](http://openvibe.inria.fr/) 59 | 60 | Get involved 61 | ================ 62 | 63 | Contact us 64 | ---------- 65 | 66 | I've started the [#emokit channel on Freenode](irc://irc.freenode.net/emokit) and I'm idling there (nick=Daeken). 67 | 68 | How you can help 69 | ---------------- 70 | 71 | I'm about to get started on an acquisition module for OpenViBE, but someone more knowledgable than myself could probably do this far more quickly. However, the reversing side of things -- particularly figuring out the sensor bytes -- would be much more useful. 72 | 73 | Summary 74 | ======= 75 | 76 | I hope that the Emokit project will open new research that was never possible before, and I can't wait to see what people do with this. Let me know if you have any questions or comments. 77 | 78 | Happy Hacking, 79 | - Cody Brocious (Daeken) 80 | -------------------------------------------------------------------------------- /emokit/doc/emotiv_protocol.asciidoc: -------------------------------------------------------------------------------- 1 | = Emotiv EEG Protocol Documentation 2 | 3 | By Daeken, Eguru, qDot 4 | Version 1.0, 2012-05-26 5 | 6 | == Introduction 7 | 8 | This document gives an overview of the communications and obfuscation 9 | mechanisms for the Emotiv EEG Headset. It covers the raw data 10 | transmission protocols, as well as the techniques used to lock down 11 | the system. 12 | 13 | This document does not cover the inner working of any of the Emotiv 14 | SDK or Suites used on top of the raw data. It exists mainly for those 15 | interested in doing research with raw wave processing software such as 16 | OpenVibe and BrainBay. 17 | 18 | == Communications Mechanisms 19 | 20 | The Emotiv EEG communicates via a proprietary wireless protocol to a 21 | USB dongle hooked to the host computer. The USB dongle identifies as a 22 | USB HID device, emitting 32-byte reports at a rate of 128hz when the 23 | headset is on and in range. No data is ever written to the dongle or 24 | head, only read from them. 25 | 26 | Each report contains the following information: 27 | 28 | * Packet Counter 29 | * Battery Level 30 | * Contact Quality 31 | * Contact Sensor Readings 32 | * Gyro Sensor Readings 33 | 34 | == Cryptography 35 | 36 | === Information and History 37 | 38 | To ensure that raw data is only read by those that have paid for the 39 | raw data license, each USB dongle encrypts incoming wireless data via 40 | AES against a key composed of the Serial Number (relayed in the USB 41 | feature report descriptor for the HID endpoint) of the dongle before 42 | emitting it as an HID report. It is assumed that data coming to the 43 | dongle from the wireless protocol is unencrypted, and all encryption 44 | happens on the dongle. 45 | 46 | While one would figure that dongles would have unique serials, this 47 | was not necessarily the case for the first year or so of emotiv 48 | development, and cracked decryption keys could be passed around as 49 | long as serials for USB dongles matched. However, later headsets now 50 | have unique serials per USB dongle. 51 | 52 | Initial key extraction techniques can be found at "Announcement.md" 53 | documentation in the emokit repository. 54 | 55 | === Key Strategy 56 | 57 | To create a 128-bit key to decrypt incoming data from the usb dongle, 58 | we first need to request a feature report from the device that 59 | contains whether the device is a consumer or research headset. This 60 | fact changes the makeup of the key. 61 | 62 | Serial numbers are fetched via the feature report for the HID 63 | endpoint. Serial numbers are 16 byte strings of the format: 64 | 65 | ------- 66 | SNXXXXXXXXXXYYYY 67 | ------- 68 | 69 | Where Xs and Ys are usually numbers. The last 4 characters of the 70 | serial number are what are used to create the key. It's interesting to 71 | note that sometimes serials have dates embedded in them, i.e. 72 | 73 | ------- 74 | SN20120526998912 75 | ------- 76 | 77 | The date is probably the day the usb dongle was flashed. 78 | 79 | For the research headset, the key is composed of the following values: 80 | 81 | ------- 82 | [15] 0x00 [14] 0x54 [13] 0x10 [12] 0x42 [15] 0x00 [14] 0x48 [13] 0x00 [12] 0x50 83 | ------- 84 | 85 | For the consumer headset, the key is composed of the following values: 86 | 87 | ------- 88 | [15] 0x00 [14] 0x48 [13] 0x00 [12] 0x54 [15] 0x10 [14] 0x42 [13] 0x00 [12] 0x50 89 | ------- 90 | 91 | Where the numbers in brackets are indexes of the serial string 92 | retrieved from the USB feature report descriptor. So for instance, if 93 | a serial number for a consumer headset is 94 | 95 | ------- 96 | SN20120526998912 97 | ------- 98 | 99 | The characters we're interested in are the last 4: 100 | 101 | ------- 102 | 8 [0x38] 9 [0x39] 1 [0x31] 2 [0x32] 103 | ------- 104 | 105 | Then the resulting crypto key will be 106 | 107 | ------- 108 | 0x32 0x00 0x31 0x48 0x39 0x00 0x38 0x54 0x32 0x10 0x31 0x42 0x39 0x00 0x38 0x50 109 | ------- 110 | 111 | == Packet Analysis 112 | 113 | 32-byte packets are received from the USB device at 128hz. Update 114 | rates within that packet are: 115 | 116 | * Sensor Data - 128hz 117 | * Gyro Data - 128hz 118 | * Battery - 1hz 119 | * Sensor Quality - 1hz-16hz (Depending on sensor) 120 | 121 | === Packet Layout 122 | 123 | An Overview of the 256-bit Packet Layout: 124 | 125 | |============================= 126 | | Bit Indexes | Used for 127 | | 0:7 | Counter/Battery 128 | | 8:21 | F3 Data 129 | | 22:35 | FC5 Data 130 | | 36:49 | AF3 Data 131 | | 50:63 | F7 Data 132 | | 64:77 | T7 Data 133 | | 78:91 | P7 Data 134 | | 92:105 | O1 Data 135 | | 107:120 | Connection Quality (Rotating) 136 | | 121:133 | ? 137 | | 134:147 | O2 Data 138 | | 148:161 | P8 Data 139 | | 162:175 | T8 Data 140 | | 176:189 | F8 Data 141 | | 190:203 | AF4 Data 142 | | 204:217 | FC6 Data 143 | | 218:231 | F4 Data 144 | | 233:239 | Gyro X 145 | | 240:247 | Gyro Y 146 | | 248:255 | ? 147 | |============================= 148 | 149 | === Counter and Battery 150 | 151 | The first byte of each packet can denote one of two things: the packet 152 | count, or the battery power level. 153 | 154 | Packet count makes up the lower 7 bits of the first byte. If the 155 | highest bit is a 1, then the battery level is being relayed. This 156 | happens once per second. 157 | 158 | Packet count goes from 0-127, then transmits a battery power packet, 159 | then wraps back to 0. This can be used to detect dropped packets. The 160 | battery power packet will always have the highest bit set to 1. 161 | 162 | Battery count is read via this table: 163 | 164 | |============================ 165 | | Value | Battery Level (%) 166 | | >= 248 | ~100 167 | | 247 | 99.93 168 | | 246 | 97.02 169 | | 245 | 93.40 170 | | 244 | 89.45 171 | | 243 | 85.23 172 | | 242 | 81.89 173 | | 241 | 76.77 174 | | 240 | 71.54 175 | | 239 | 66.59 176 | | 238 | 61.92 177 | | 237 | 55.37 178 | | 236 | 45.93 179 | | 235 | 32.34 180 | | 234 | 20.43 181 | | 233 | 12.37 182 | | 232 | 5.08 183 | | 231 | 3.63 184 | | 230 | 2.80 185 | | 229 | 2.05 186 | | 228 | 1.42 187 | | 227 | 0.88 188 | | 226 | 0.42 189 | | 225 | 0 190 | | < 225 | ~0 191 | |============================ 192 | 193 | === Contact Readings 194 | 195 | Readings from the contacts are available as 14 bit values, with each 196 | sensor sending at 128hz. The values are interspered throughout the 197 | packet. See the Packet Layout section for which sensors are covered by 198 | each bit range. 199 | 200 | === Contact Quality 201 | 202 | Contact quality consists of 14 bits, and refers to the contact quality 203 | of the sensor as an amplitude of its calibration signal. The sensor 204 | context of the field changes based on the value of the packet counter 205 | in the first byte. For instance, a counter value of 1 means the packet 206 | is showing the quality for sensor FC5, while a counter value of 2 207 | means that the packet is showing the quality for sensor AF3, and 208 | so on. 209 | 210 | The following list shows the order that the sensors are listed in, in 211 | relation to the counter, starting with counter = 0. 212 | 213 | |============================ 214 | | Counter Index | Contact 215 | | 0 | F3 216 | | 1 | FC5 217 | | 2 | AF3 218 | | 3 | F7 219 | | 4 | T7 220 | | 5 | P7 221 | | 6 | O1 222 | | 7 | O2 223 | | 8 | P8 224 | | 9 | T8 225 | | 10 | F8 226 | | 11 | AF4 227 | | 12 | FC6 228 | | 13 | F4 229 | | 14 | F8 230 | | 15 | AF4 231 | | 16-63 | Unknown? 232 | | 64 | F3 233 | | 65 | FC5 234 | | 66 | AF3 235 | | 67 | F7 236 | | 68 | T7 237 | | 69 | P7 238 | | 70 | O1 239 | | 71 | O2 240 | | 72 | P8 241 | | 73 | T8 242 | | 74 | F8 243 | | 75 | AF4 244 | | 76 | FC6 245 | | 77 | F4 246 | | 78 | F8 247 | | 79 | AF4 248 | | 80 | FC6 249 | | .. | 77-80 Pattern repeats until counter hits 127 250 | |============================ 251 | 252 | To get a useful reading, divide each readout by ~540. A value of 253 | 0.8-1.0 means a "good" contact. 254 | 255 | === Gyros 256 | 257 | Gyro readings are available for 2 axes (head turned left/right and 258 | foreward/back). These are 8-bit values that update at a rate of 128hz, 259 | with 7-bits of resolution on either side of the median point for the 260 | turn. 261 | -------------------------------------------------------------------------------- /emokit/doc/usbinfo.txt: -------------------------------------------------------------------------------- 1 | Bus 002 Device 003: ID 21a1:0001 2 | Device Descriptor: 3 | bLength 18 4 | bDescriptorType 1 5 | bcdUSB 2.00 6 | bDeviceClass 0 (Defined at Interface level) 7 | bDeviceSubClass 0 8 | bDeviceProtocol 0 9 | bMaxPacketSize0 8 10 | idVendor 0x21a1 11 | idProduct 0x0001 12 | bcdDevice 0.03 13 | iManufacturer 1 14 | iProduct 2 15 | iSerial 3 16 | bNumConfigurations 1 17 | Configuration Descriptor: 18 | bLength 9 19 | bDescriptorType 2 20 | wTotalLength 59 21 | bNumInterfaces 2 22 | bConfigurationValue 1 23 | iConfiguration 0 24 | bmAttributes 0x80 25 | (Bus Powered) 26 | MaxPower 100mA 27 | Interface Descriptor: 28 | bLength 9 29 | bDescriptorType 4 30 | bInterfaceNumber 0 31 | bAlternateSetting 0 32 | bNumEndpoints 1 33 | bInterfaceClass 3 Human Interface Device 34 | bInterfaceSubClass 0 No Subclass 35 | bInterfaceProtocol 0 None 36 | iInterface 0 37 | HID Device Descriptor: 38 | bLength 9 39 | bDescriptorType 33 40 | bcdHID 1.11 41 | bCountryCode 33 US 42 | bNumDescriptors 1 43 | bDescriptorType 34 Report 44 | wDescriptorLength 20 45 | Report Descriptors: 46 | ** UNAVAILABLE ** 47 | Endpoint Descriptor: 48 | bLength 7 49 | bDescriptorType 5 50 | bEndpointAddress 0x81 EP 1 IN 51 | bmAttributes 3 52 | Transfer Type Interrupt 53 | Synch Type None 54 | Usage Type Data 55 | wMaxPacketSize 0x0008 1x 8 bytes 56 | bInterval 1 57 | Interface Descriptor: 58 | bLength 9 59 | bDescriptorType 4 60 | bInterfaceNumber 1 61 | bAlternateSetting 0 62 | bNumEndpoints 1 63 | bInterfaceClass 3 Human Interface Device 64 | bInterfaceSubClass 0 No Subclass 65 | bInterfaceProtocol 0 None 66 | iInterface 4 67 | HID Device Descriptor: 68 | bLength 9 69 | bDescriptorType 33 70 | bcdHID 1.11 71 | bCountryCode 0 Not supported 72 | bNumDescriptors 1 73 | bDescriptorType 34 Report 74 | wDescriptorLength 28 75 | Report Descriptors: 76 | ** UNAVAILABLE ** 77 | Endpoint Descriptor: 78 | bLength 7 79 | bDescriptorType 5 80 | bEndpointAddress 0x82 EP 2 IN 81 | bmAttributes 3 82 | Transfer Type Interrupt 83 | Synch Type None 84 | Usage Type Data 85 | wMaxPacketSize 0x0020 1x 32 bytes 86 | bInterval 1 87 | can't get device qualifier: Operation not permitted 88 | can't get debug descriptor: Operation not permitted 89 | cannot read device status, Operation not permitted (1) 90 | -------------------------------------------------------------------------------- /emokit/examples/contact/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | ################################################## 2 | # epoc contact # 3 | ################################################## 4 | 5 | add_executable (contact contact.c) 6 | ADD_DEPENDENCIES(contact emokit) 7 | target_link_libraries (contact emokit ${LIBS}) 8 | 9 | SET_TARGET_PROPERTIES(contact PROPERTIES 10 | INSTALL_RPATH_USE_LINK_PATH TRUE 11 | INSTALL_RPATH ${CMAKE_INSTALL_PREFIX}/lib 12 | BUILD_WITH_INSTALL_RPATH TRUE ) 13 | 14 | INSTALL (TARGETS contact 15 | RUNTIME DESTINATION bin 16 | ) 17 | -------------------------------------------------------------------------------- /emokit/examples/contact/contact.c: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | Get real-time contact quality readings 4 | 5 | */ 6 | 7 | #include 8 | #include 9 | #include 10 | #include "emokit/emokit.h" 11 | 12 | int quit; 13 | void cleanup(int i){ 14 | fprintf(stdout,"Shutting down\n"); 15 | quit=1; 16 | } 17 | 18 | int main(int argc, char **argv) 19 | { 20 | struct emokit_device* d; 21 | signal(SIGINT, cleanup); //trap cntrl c 22 | 23 | 24 | quit=0; 25 | 26 | d = emokit_create(); 27 | int count=emokit_get_count(d, EMOKIT_VID, EMOKIT_PID); 28 | printf("Current epoc devices connected: %d\n", count ); 29 | int r = emokit_open(d, EMOKIT_VID, EMOKIT_PID, 1); 30 | if(r != 0) 31 | { 32 | emokit_close(d); 33 | emokit_delete(d); 34 | d = emokit_create(); 35 | r = emokit_open(d, EMOKIT_VID, EMOKIT_PID, 0); 36 | if (r!=0) { 37 | printf("CANNOT CONNECT: %d\n", r); 38 | return 1; 39 | } 40 | } 41 | printf("Connected to headset.\n"); 42 | 43 | r = emokit_read_data_timeout(d,1000); 44 | if (r<=0) { 45 | if(r<0) 46 | fprintf(stderr, "Error reading from headset\n"); 47 | else 48 | fprintf(stderr, "Headset Timeout...\n"); 49 | emokit_close(d); 50 | emokit_delete(d); 51 | return 1; 52 | } 53 | 54 | struct emokit_frame c; 55 | while (!quit) { 56 | int err = emokit_read_data_timeout(d, 1000); 57 | if(err > 0) { 58 | c = emokit_get_next_frame(d); 59 | fprintf(stdout,"\033[H\033[2JPress CTRL+C to exit\n\nContact quality:\nF3 %4d\nFC6 %4d\nP7 %4d\nT8 %4d\nF7 %4d\nF8 %4d\nT7 %4d\nP8 %4d\nAF4 %4d\nF4 %4d\nAF3 %4d\nO2 %4d\nO1 %4d\nFC5 %4d",c.cq.F3, c.cq.FC6, c.cq.P7, c.cq.T8,c.cq.F7, c.cq.F8, c.cq.T7, c.cq.P8, c.cq.AF4, c.cq.F4, c.cq.AF3, c.cq.O2, c.cq.O1, c.cq.FC5); 60 | fflush(stdout); 61 | } else if(err == 0) { 62 | fprintf(stderr, "Headset Timeout...\n"); 63 | } 64 | } 65 | emokit_close(d); 66 | emokit_delete(d); 67 | return 0; 68 | } 69 | 70 | -------------------------------------------------------------------------------- /emokit/examples/emokit_osc/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | LIST(APPEND CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR}) 2 | FIND_PACKAGE(oscpack) 3 | 4 | IF(NOT oscpack_FOUND) 5 | MESSAGE(STATUS "oscpack not found, not building emokit osc server") 6 | ELSE() 7 | INCLUDE_DIRECTORIES(${oscpack_INCLUDE_DIR}) 8 | ADD_EXECUTABLE(emokit_osc emokit_osc.cpp) 9 | ADD_DEPENDENCIES(emokit_osc emokit) 10 | TARGET_LINK_LIBRARIES(emokit_osc ${oscpack_LIBS} emokit ${LIBS}) 11 | ENDIF() 12 | -------------------------------------------------------------------------------- /emokit/examples/emokit_osc/Findoscpack.cmake: -------------------------------------------------------------------------------- 1 | # - Find Mcrypt (a cross platform RPC lib/tool) 2 | # This module defines 3 | # Mcrypt_INCLUDE_DIR, where to find Mcrypt headers 4 | # Mcrypt_LIBS, Mcrypt libraries 5 | # Mcrypt_FOUND, If false, do not try to use Mcrypt 6 | 7 | find_path(oscpack_INCLUDE_DIR oscpack/osc/OscTypes.h PATHS 8 | /usr/local/include 9 | /opt/local/include 10 | ) 11 | 12 | #find_library can't seem to find a 64-bit binary if the 32-bit isn't there 13 | 14 | set(oscpack_LIB_PATHS /usr/local/lib /opt/local/lib /usr/lib64) 15 | find_library(oscpack_LIB NAMES oscpack PATHS ${oscpack_LIB_PATHS}) 16 | 17 | if (oscpack_LIB AND oscpack_INCLUDE_DIR) 18 | set(oscpack_FOUND TRUE) 19 | set(oscpack_LIBS ${oscpack_LIB}) 20 | else () 21 | set(oscpack_FOUND FALSE) 22 | endif () 23 | 24 | if (oscpack_FOUND) 25 | if (NOT oscpack_FIND_QUIETLY) 26 | message(STATUS "Found oscpack: ${oscpack_LIBS}") 27 | endif () 28 | else () 29 | if (oscpack_FIND_REQUIRED) 30 | message(FATAL_ERROR "Could NOT find oscpack library.") 31 | endif () 32 | message(STATUS "oscpack NOT found.") 33 | endif () 34 | 35 | mark_as_advanced( 36 | oscpack_LIB 37 | oscpack_INCLUDE_DIR 38 | ) 39 | -------------------------------------------------------------------------------- /emokit/examples/emokit_osc/emokit_osc.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | Simple example of sending an OSC message using oscpack. 3 | */ 4 | 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include "oscpack/osc/OscOutboundPacketStream.h" 11 | #include "oscpack/ip/UdpSocket.h" 12 | #include "emokit/emokit.h" 13 | 14 | #define ADDRESS "127.0.0.1" 15 | #define PORT 9997 16 | 17 | #define OUTPUT_BUFFER_SIZE 4096 18 | 19 | void sigproc(int i) 20 | { 21 | std::cout << "closing epoc and quitting" << std::endl; 22 | exit(0); 23 | } 24 | 25 | float conv(int v) 26 | { 27 | return (v-8200)/8200.0; 28 | } 29 | 30 | int main(int argc, char* argv[]) 31 | { 32 | signal(SIGINT, sigproc); 33 | #ifndef WIN32 34 | signal(SIGQUIT, sigproc); 35 | #endif 36 | 37 | UdpTransmitSocket transmitSocket( IpEndpointName( ADDRESS, PORT ) ); 38 | 39 | char buffer[OUTPUT_BUFFER_SIZE]; 40 | 41 | 42 | FILE *input; 43 | FILE *output; 44 | 45 | char raw_frame[32]; 46 | struct emokit_frame frame; 47 | emokit_device* d; 48 | uint8_t data[32]; 49 | 50 | d = emokit_create(); 51 | printf("Current epoc devices connected: %d\n", emokit_get_count(d, EMOKIT_VID, EMOKIT_PID)); 52 | if(emokit_open(d, EMOKIT_VID, EMOKIT_PID, 1) != 0) 53 | { 54 | printf("CANNOT CONNECT\n"); 55 | return 1; 56 | } 57 | while(1) 58 | { 59 | int r; 60 | if((r=emokit_read_data_timeout(d, 1000)) > 0) 61 | { 62 | frame = emokit_get_next_frame(d); 63 | osc::OutboundPacketStream p( buffer, OUTPUT_BUFFER_SIZE ); 64 | p << osc::BeginMessage( "/multiplot" ) 65 | << conv(frame.F3) << conv(frame.FC6) << conv(frame.P7) 66 | << conv(frame.T8) << conv(frame.F7) << conv(frame.F8) 67 | << conv(frame.T7) << conv(frame.P8) << conv(frame.AF4) 68 | << conv(frame.F4) << conv(frame.AF3) << conv(frame.O2) 69 | << conv(frame.O1) << conv(frame.FC5) << osc::EndMessage; 70 | 71 | transmitSocket.Send( p.Data(), p.Size() ); 72 | } else if(r == 0) 73 | fprintf(stderr, "Headset Timeout\n"); 74 | else { 75 | fprintf(stderr, "Headset Error\n"); 76 | break; 77 | } 78 | } 79 | 80 | emokit_close(d); 81 | emokit_delete(d); 82 | return 0; 83 | 84 | } 85 | -------------------------------------------------------------------------------- /emokit/examples/emokit_osc/pd/emokit-osc.pd: -------------------------------------------------------------------------------- 1 | #N canvas 861 136 478 400 10; 2 | #X obj 6 -38 udpreceive 9997; 3 | #X obj 6 -6 unpackOSC; 4 | #X obj 76 79 unpack 0 0; 5 | #X floatatom 76 103 5 0 0 0 - - -; 6 | #X floatatom 133 103 5 0 0 0 - - -; 7 | #X obj 6 55 routeOSC /channels /gyro; 8 | #X obj 6 27 routeOSC /epoc; 9 | #X text 68 117 gyro x; 10 | #X text 127 117 gyro y; 11 | #X obj 6 80 s ch; 12 | #X obj 210 -39 r ch; 13 | #X floatatom 210 316 5 0 0 0 - - -; 14 | #X floatatom 225 295 5 0 0 0 - - -; 15 | #X floatatom 240 274 5 0 0 0 - - -; 16 | #X floatatom 256 253 5 0 0 0 - - -; 17 | #X floatatom 271 230 5 0 0 0 - - -; 18 | #X floatatom 287 208 5 0 0 0 - - -; 19 | #X floatatom 349 112 5 0 0 0 - - -; 20 | #X floatatom 302 182 5 0 0 0 - - -; 21 | #X floatatom 318 157 5 0 0 0 - - -; 22 | #X floatatom 333 133 5 0 0 0 - - -; 23 | #X floatatom 364 89 5 0 0 0 - - -; 24 | #X floatatom 380 67 5 0 0 0 - - -; 25 | #X floatatom 395 41 5 0 0 0 - - -; 26 | #X floatatom 411 17 5 0 0 0 - - -; 27 | #X text 245 316 F3; 28 | #X text 259 294 FC6; 29 | #X text 275 274 P7; 30 | #X text 289 253 T8; 31 | #X text 303 229 F7; 32 | #X text 319 208 F8; 33 | #X obj 210 -10 unpack 0 0 0 0 0 0 0 0 0 0 0 0 0 0; 34 | #X text 335 182 T7; 35 | #X text 353 155 P8; 36 | #X text 366 132 AF4; 37 | #X text 382 111 F4; 38 | #X text 397 89 AF3; 39 | #X text 412 67 O2; 40 | #X text 427 42 O1; 41 | #X text 445 18 FC5; 42 | #X connect 0 0 1 0; 43 | #X connect 1 0 6 0; 44 | #X connect 2 0 3 0; 45 | #X connect 2 1 4 0; 46 | #X connect 5 0 9 0; 47 | #X connect 5 1 2 0; 48 | #X connect 6 0 5 0; 49 | #X connect 10 0 31 0; 50 | #X connect 31 0 11 0; 51 | #X connect 31 1 12 0; 52 | #X connect 31 2 13 0; 53 | #X connect 31 3 14 0; 54 | #X connect 31 4 15 0; 55 | #X connect 31 5 16 0; 56 | #X connect 31 6 18 0; 57 | #X connect 31 7 19 0; 58 | #X connect 31 8 20 0; 59 | #X connect 31 9 17 0; 60 | #X connect 31 10 21 0; 61 | #X connect 31 11 22 0; 62 | #X connect 31 12 23 0; 63 | #X connect 31 13 24 0; 64 | -------------------------------------------------------------------------------- /emokit/examples/emokitd/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | ################################################## 2 | # epoc daemon # 3 | ################################################## 4 | 5 | add_executable (emokitd emokitd.c) 6 | ADD_DEPENDENCIES(emokitd emokit) 7 | target_link_libraries (emokitd emokit ${LIBS} pthread) 8 | 9 | SET_TARGET_PROPERTIES(emokitd PROPERTIES 10 | INSTALL_RPATH_USE_LINK_PATH TRUE 11 | INSTALL_RPATH ${CMAKE_INSTALL_PREFIX}/lib 12 | BUILD_WITH_INSTALL_RPATH TRUE ) 13 | 14 | INSTALL (TARGETS emokitd 15 | RUNTIME DESTINATION bin 16 | ) 17 | 18 | -------------------------------------------------------------------------------- /emokit/examples/emokitd/emokitd.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | #include "emokit/emokit.h" 15 | 16 | #include "emokitd.h" 17 | 18 | sigset_t mask; 19 | 20 | typedef struct emokit_device emokit_device; 21 | 22 | void fatal_err(const char *msg) { 23 | syslog(LOG_INFO, msg); 24 | exit(1); 25 | } 26 | 27 | void init_fatal_err(const char *msg) { 28 | printf("Fatal: %s\n", msg); 29 | exit(1); 30 | } 31 | 32 | void *thr_signal_handler(void *arg) { 33 | int sig; 34 | for (;;) { 35 | if (sigwait(&mask, &sig) != 0) { 36 | fatal_err("sigwait failed."); 37 | } 38 | switch (sig) { 39 | case SIGTERM: 40 | syslog(LOG_INFO, "Caught SIGTERM. Exiting."); 41 | remove(FIFO_PATH); 42 | exit(0); 43 | 44 | case SIGPIPE: 45 | syslog(LOG_INFO, "Reader exited; blocking."); 46 | break; 47 | 48 | default: 49 | syslog(LOG_INFO, "Caught unexpected signal: %d", sig); 50 | } 51 | } 52 | } 53 | 54 | int daemon_running() { 55 | int fd; 56 | char buf[16]; 57 | struct flock fl; 58 | fd = open(PIDFILE, O_RDWR|O_CREAT, LOCKMODE); 59 | if (fd < 0) 60 | fatal_err("cannot open pidfile."); 61 | fl.l_type = F_WRLCK; 62 | fl.l_start = 0; 63 | fl.l_whence = SEEK_SET; 64 | fl.l_len = 0; 65 | fl.l_pid = getpid(); 66 | if (fcntl(fd, F_SETLK, &fl) < 0) { 67 | if (errno == EACCES || errno == EAGAIN) { 68 | close(fd); 69 | return 1; 70 | } 71 | fatal_err("cannot lock pidfile."); 72 | } 73 | ftruncate(fd, 0); 74 | sprintf(buf, "%ld", (long) getpid()); 75 | write(fd, buf, strlen(buf)+1); 76 | return 0; 77 | } 78 | 79 | void daemonize() { 80 | int i, fd0, fd1, fd2; 81 | pid_t pid; 82 | struct rlimit rl; 83 | struct sigaction sa; 84 | umask(0); 85 | if (getrlimit(RLIMIT_NOFILE, &rl) < 0) 86 | init_fatal_err("Fatal: can't get file limit."); 87 | 88 | if ((pid = fork()) < 0) 89 | init_fatal_err("Fatal: can't fork."); 90 | else if (pid != 0) 91 | exit(0); 92 | setsid(); 93 | 94 | sa.sa_handler = SIG_IGN; 95 | sigemptyset(&sa.sa_mask); 96 | sa.sa_flags = 0; 97 | if (sigaction(SIGHUP, &sa, NULL) < 0) 98 | init_fatal_err("Fatal: can't ignore SIGHUP."); 99 | if ((pid = fork()) < 0) 100 | init_fatal_err("Fatal: can't fork.\n"); 101 | else if (pid != 0) 102 | exit(0); 103 | 104 | /* switch working directory to / so we're not preventing 105 | anything from unmounting */ 106 | if (chdir("/") < 0) 107 | init_fatal_err("Fatal: can't chdir to /."); 108 | 109 | if (rl.rlim_max == RLIM_INFINITY) 110 | rl.rlim_max = 1024; 111 | for (i=0; i < rl.rlim_max; ++i) 112 | close(i); 113 | 114 | /* so we can't spew into standard streams */ 115 | fd0 = open("/dev/null", O_RDWR); 116 | fd1 = dup(fd0); 117 | fd2 = dup(fd0); 118 | 119 | openlog(DAEMON_IDENT, LOG_CONS, LOG_DAEMON); 120 | syslog(LOG_INFO, "emokitd running; decrypted EEG data will be written to %s.", FIFO_PATH); 121 | 122 | } 123 | 124 | void dbg_stream(emokit_device *eeg) { 125 | int i; 126 | for (;;) { 127 | if (emokit_read_data(eeg) > 0) { 128 | emokit_get_next_frame(eeg); 129 | for (i=0; i < 32; ++i) { 130 | //printf("%d ", eeg->raw_frame[i]); 131 | } 132 | putchar('\n'); 133 | fflush(stdout); 134 | } 135 | } 136 | } 137 | 138 | void decrypt_loop(emokit_device *eeg) { 139 | int i; 140 | FILE *emokitd_fifo; 141 | emokitd_fifo = fopen(FIFO_PATH, "wb"); 142 | if (!emokitd_fifo) { 143 | fatal_err("cannot open FIFO for writing."); 144 | } 145 | for (;;) { 146 | if (emokit_read_data(eeg) > 0) { 147 | emokit_get_next_frame(eeg); 148 | unsigned char raw_frame[32]; 149 | emokit_get_raw_frame(eeg, raw_frame); 150 | fwrite(raw_frame, 1, EMOKIT_PKT_SIZE, emokitd_fifo); 151 | } 152 | } 153 | } 154 | 155 | int main(int argc, char **argv) { 156 | int i; 157 | unsigned char dev_type; 158 | pthread_t tid; 159 | struct sigaction sa; 160 | emokit_device *eeg; 161 | if (!DEBUG) { 162 | daemonize(); 163 | if (daemon_running()) { 164 | syslog(LOG_INFO, "Looks like emokitd is already running.\n"); 165 | exit(1); 166 | } 167 | } 168 | eeg = emokit_create(); 169 | if (emokit_open(eeg, EMOKIT_VID, EMOKIT_PID, 0) != 0) { 170 | fatal_err("cannot access device. Are you root?"); 171 | return 1; 172 | } 173 | 174 | if ((access(FIFO_PATH, W_OK) < 0) && mkfifo(FIFO_PATH, 0666) != 0) { 175 | fatal_err("cannot create FIFO."); 176 | } 177 | sa.sa_handler = SIG_DFL; 178 | sigemptyset(&sa.sa_mask); 179 | if (sigaction(SIGHUP, &sa, NULL) < 0) 180 | fatal_err("cannot restore SIGHUP."); 181 | sigfillset(&mask); 182 | if (pthread_sigmask(SIG_BLOCK, &mask, NULL) != 0) 183 | fatal_err("SIG_BLOCK error."); 184 | if (pthread_create(&tid, NULL, thr_signal_handler, 0) != 0) 185 | fatal_err("cannot create thread."); 186 | if (DEBUG) 187 | printf("Entering decrypt loop...\n"); 188 | decrypt_loop(eeg); 189 | return 0; 190 | } 191 | -------------------------------------------------------------------------------- /emokit/examples/emokitd/emokitd.h: -------------------------------------------------------------------------------- 1 | #include "sys/stat.h" 2 | 3 | #define DAEMON_IDENT "emokitd" 4 | #define PIDFILE "/var/run/emokitd.pid" 5 | #define LOCKMODE (S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH) 6 | #define FIFO_PATH "/dev/emokitd" 7 | #define EMOKIT_PKT_SIZE 32 8 | 9 | #ifndef DEBUG 10 | #define DEBUG 0 11 | #endif 12 | -------------------------------------------------------------------------------- /emokit/include/emokit/emokit.h: -------------------------------------------------------------------------------- 1 | /* Copyright (c) 2010, Daeken and Skadge 2 | * Copyright (c) 2011-2012, OpenYou Organization (http://openyou.org) 3 | * 4 | * Permission to use, copy, modify, and/or distribute this software for any 5 | * purpose with or without fee is hereby granted, provided that the above 6 | * copyright notice and this permission notice appear in all copies. 7 | * 8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 11 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 13 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 14 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 | */ 16 | 17 | #ifndef LIBEMOKIT_H_ 18 | #define LIBEMOKIT_H_ 19 | 20 | #define E_EMOKIT_DRIVER_ERROR -1 21 | #define E_EMOKIT_NOT_INITED -2 22 | #define E_EMOKIT_NOT_OPENED -3 23 | 24 | #include 25 | #if !defined(WIN32) 26 | #define EMOKIT_DECLSPEC 27 | #else 28 | #define EMOKIT_DECLSPEC __declspec(dllexport) 29 | #endif 30 | 31 | /// Vendor ID for all emotiv devices 32 | const static uint32_t EMOKIT_VID = 0x21a1; 33 | /// Product ID for all emotiv devices 34 | const static uint32_t EMOKIT_PID = 0x0001; 35 | 36 | /// Out endpoint for all emotiv devices 37 | const static uint32_t EMOKIT_OUT_ENDPT = 0x02; 38 | /// In endpoint for all emotiv devices 39 | const static uint32_t EMOKIT_IN_ENDPT = 0x82; 40 | 41 | struct emokit_contact_quality {//values > 4000 are good 42 | short F3, FC6, P7, T8, F7, F8, T7, P8, AF4, F4, AF3, O2, O1, FC5; 43 | }; 44 | 45 | struct emokit_frame { 46 | unsigned char counter; //loops from 0 to 128 (129 values) 47 | int F3, FC6, P7, T8, F7, F8, T7, P8, AF4, F4, AF3, O2, O1, FC5; //raw data values 48 | struct emokit_contact_quality cq; 49 | char gyroX, gyroY; 50 | unsigned char battery; //percentage of full charge, read on counter=128 51 | }; 52 | 53 | 54 | #ifdef __cplusplus 55 | extern "C" 56 | { 57 | #endif 58 | struct emokit_device; 59 | /** 60 | * Kills crypto context. Not meant for public calling, call 61 | * emokit_delete instead. 62 | * 63 | */ 64 | void emokit_deinit(struct emokit_device* s); 65 | 66 | /** 67 | * Create a new struct emokit_device structure and return a pointer to it. 68 | * Makes sure structure is initialized properly. To delete, call 69 | * emokit_delete(). 70 | * 71 | * 72 | * @return new struct emokit_device structure 73 | */ 74 | EMOKIT_DECLSPEC struct emokit_device* emokit_create(); 75 | 76 | /** 77 | * Return the number of devices currently connected to the system 78 | * 79 | * @param s Inited device structure 80 | * @param device_vid VID to look for, usually EMOKIT_VID constant 81 | * @param device_pid PID to look for, usually EMOKIT_PID constant 82 | * 83 | * @return Number of devices currently connected to system, or < 0 84 | * for error 85 | */ 86 | EMOKIT_DECLSPEC int emokit_get_count(struct emokit_device* s, 87 | int device_vid, 88 | int device_pid); 89 | 90 | /** 91 | * Open an inited device 92 | * 93 | * @param s Inited device structure 94 | * @param device_vid VID to look for, usually EMOKIT_VID constant 95 | * @param device_pid PID to look for, usually EMOKIT_PID constant 96 | * @param device_index Index of device to open on the bus (0 for first device 97 | * found) 98 | * 99 | * @return 0 if successful, < 0 for error 100 | */ 101 | EMOKIT_DECLSPEC int emokit_open(struct emokit_device* s, 102 | int device_vid, 103 | int device_pid, 104 | unsigned int device_index); 105 | 106 | /** 107 | * Close an opened device 108 | * 109 | * @param s Currently opened device 110 | * 111 | * @return 0 if successful, < 0 for error 112 | */ 113 | EMOKIT_DECLSPEC int emokit_close(struct emokit_device* s); 114 | 115 | /** 116 | * Delete an inited device 117 | * 118 | * @param dev Initied device strucure 119 | */ 120 | EMOKIT_DECLSPEC void emokit_delete(struct emokit_device* dev); 121 | 122 | /** 123 | * Read a single raw report from the device. This function will 124 | * block until a single report is read. We are guarenteed each 125 | * report will be a full message from the device, so we do not need 126 | * to maintain read state between reads. 127 | * 128 | * @param dev Opened device structure 129 | * 130 | * @return <0 for error, otherwise return the number of bytes read. 131 | */ 132 | EMOKIT_DECLSPEC int emokit_read_data(struct emokit_device* dev); 133 | 134 | /** 135 | * Read a single raw report from the device. 136 | * 137 | * @param dev Opened device structure 138 | * @param timeout Max wait time in ms 139 | * 140 | * @return <0 for error, otherwise return the number of bytes read. 141 | */ 142 | EMOKIT_DECLSPEC int emokit_read_data_timeout(struct emokit_device* dev, 143 | unsigned timeout); 144 | 145 | EMOKIT_DECLSPEC struct emokit_frame 146 | emokit_get_next_frame(struct emokit_device* dev); 147 | 148 | /** 149 | * Given a feature report from the device, extract the serial and 150 | * create the crypto key. Exposed because why not. Sets "key" field 151 | * in device struct. 152 | * 153 | * @param s Initied, opened device 154 | * @param dev_type EMOKIT_CONSUMER or EMOKIT_RESEARCH 155 | * 156 | * @return 0 if successful, < 0 for error 157 | */ 158 | EMOKIT_DECLSPEC void emokit_get_crypto_key(struct emokit_device* s, 159 | int dev_type); 160 | 161 | /** 162 | * Given an emokit_device and an unsigned char array of not 163 | * fewer than 32 bytes, load the most recent unencrypted data 164 | * frame into the array. Does not return a value. 165 | */ 166 | EMOKIT_DECLSPEC void emokit_get_raw_frame(struct emokit_device *dev, unsigned char *buf); 167 | 168 | #ifdef __cplusplus 169 | }; 170 | #endif 171 | #endif //LIBEMOKIT_H_ 172 | -------------------------------------------------------------------------------- /emokit/linux/epoc.rules: -------------------------------------------------------------------------------- 1 | #UDEV rule for the Emotiv EPOC headset 2 | # 3 | #Once installed into /etc/udev/rules.d, udev will recognize the headset and 4 | #create a /dev/eeg/encrypted device where you can access the headset encryted 5 | #stream. 6 | # 7 | #It will as well attempt to start a daemon in charge of decrypting the stream. 8 | #If the daemon successfully starts, you will find the data under /dev/eeg/raw 9 | 10 | ATTR{manufacturer}=="Emotiv Systems Pty Ltd", ATTRS{product}=="Receiver Dongle L01", NAME="eeg/epoc%2", SYMLINK+="epoc%n" 11 | 12 | #Consumer headset 13 | #SUBSYSTEM=="hidraw", ATTRS{idVendor}=="21a1", ATTRS{idProduct}=="0001", ATTRS{interface}=="Emotiv RAW DATA", NAME="eeg/encrypted%n", SYMLINK+="eeg/encrypted", MODE="0444", RUN +="decrypt_emotiv.sh consumer" 14 | 15 | #Research headset 16 | SUBSYSTEM=="hidraw", ATTRS{interface}=="Emotiv RAW DATA", NAME="eeg/encrypted%n", SYMLINK+="eeg/encrypted", MODE="0444", RUN +="decrypt_emotiv.sh research" 17 | 18 | -------------------------------------------------------------------------------- /emokit/python/MANIFEST.in: -------------------------------------------------------------------------------- 1 | include requirements.txt tests/* 2 | -------------------------------------------------------------------------------- /emokit/python/Makefile: -------------------------------------------------------------------------------- 1 | SHELL := /bin/bash 2 | 3 | test: 4 | nosetests-2.7 -s --verbosity=2 5 | 6 | clean: 7 | rm -fr build dist 8 | rm -fr *.egg-info 9 | find . -name *.pyc -exec rm {} \; 10 | find . -name *.swp -exec rm {} \; 11 | 12 | install: 13 | python2.7 setup.py install 14 | 15 | upload: clean 16 | python2.7 setup.py sdist upload 17 | 18 | -------------------------------------------------------------------------------- /emokit/python/dist/emokit-0.0.1-py2.7.egg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nikhiljay/brainwaves/42d96dccedf09504589fc9e14e3b470de7f5c0b2/emokit/python/dist/emokit-0.0.1-py2.7.egg -------------------------------------------------------------------------------- /emokit/python/emokit.egg-info/PKG-INFO: -------------------------------------------------------------------------------- 1 | Metadata-Version: 1.1 2 | Name: emokit 3 | Version: 0.0.1 4 | Summary: emotiv epoc eeg headset sdk 5 | Home-page: https://github.com/kanzure/emokit 6 | Author: Bryan Bishop 7 | Author-email: kanzure@gmail.com 8 | License: UNKNOWN 9 | Description: UNKNOWN 10 | Platform: any 11 | Classifier: Operating System :: OS Independent 12 | Classifier: Programming Language :: Python 13 | -------------------------------------------------------------------------------- /emokit/python/emokit.egg-info/SOURCES.txt: -------------------------------------------------------------------------------- 1 | MANIFEST.in 2 | requirements.txt 3 | setup.py 4 | emokit/__init__.py 5 | emokit/emotiv.py 6 | emokit.egg-info/PKG-INFO 7 | emokit.egg-info/SOURCES.txt 8 | emokit.egg-info/dependency_links.txt 9 | emokit.egg-info/not-zip-safe 10 | emokit.egg-info/requires.txt 11 | emokit.egg-info/top_level.txt 12 | tests/test_emokit.py -------------------------------------------------------------------------------- /emokit/python/emokit.egg-info/dependency_links.txt: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /emokit/python/emokit.egg-info/not-zip-safe: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /emokit/python/emokit.egg-info/requires.txt: -------------------------------------------------------------------------------- 1 | gevent 2 | pycrypto -------------------------------------------------------------------------------- /emokit/python/emokit.egg-info/top_level.txt: -------------------------------------------------------------------------------- 1 | emokit 2 | -------------------------------------------------------------------------------- /emokit/python/emokit/Makefile-manual: -------------------------------------------------------------------------------- 1 | ########################################### 2 | # Simple Makefile for HIDAPI test program 3 | # 4 | # Alan Ott 5 | # Signal 11 Software 6 | # 2010-07-03 7 | ########################################### 8 | 9 | all: hidtest 10 | 11 | CC=gcc 12 | CXX=g++ 13 | COBJS=hid.o 14 | CPPOBJS=../hidtest/hidtest.o 15 | OBJS=$(COBJS) $(CPPOBJS) 16 | CFLAGS+=-I../hidapi -Wall -g -c 17 | LIBS=-framework IOKit -framework CoreFoundation 18 | 19 | 20 | hidtest: $(OBJS) 21 | g++ -Wall -g $^ $(LIBS) -o hidtest 22 | 23 | $(COBJS): %.o: %.c 24 | $(CC) $(CFLAGS) $< -o $@ 25 | 26 | $(CPPOBJS): %.o: %.cpp 27 | $(CXX) $(CFLAGS) $< -o $@ 28 | 29 | clean: 30 | rm -f *.o hidtest $(CPPOBJS) 31 | 32 | .PHONY: clean 33 | -------------------------------------------------------------------------------- /emokit/python/emokit/Makefile.am: -------------------------------------------------------------------------------- 1 | lib_LTLIBRARIES = libhidapi.la 2 | libhidapi_la_SOURCES = hid.c 3 | libhidapi_la_LDFLAGS = $(LTLDFLAGS) 4 | AM_CPPFLAGS = -I$(top_srcdir)/hidapi/ 5 | 6 | hdrdir = $(includedir)/hidapi 7 | hdr_HEADERS = $(top_srcdir)/hidapi/hidapi.h 8 | 9 | EXTRA_DIST = Makefile-manual 10 | -------------------------------------------------------------------------------- /emokit/python/emokit/__init__.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | emokit - emotiv epoc reverse engineering 4 | ~~~~~~~~~~~~~~~ 5 | 6 | :copyright: (c) 2013 by ??? 7 | :license: ??? 8 | """ 9 | 10 | __title__ = "emokit" 11 | __version__ = "0.0.1" 12 | __build__ = 0x000001 13 | __author__ = "Bryan Bishop " 14 | __license__ = "???" 15 | __copyright__ = "Copyright 2013 Bryan Bishop" 16 | 17 | from . import emotiv 18 | -------------------------------------------------------------------------------- /emokit/python/emokit/cv.py: -------------------------------------------------------------------------------- 1 | /usr/local/Cellar/opencv/2.4.12/lib/python2.7/site-packages/cv.py -------------------------------------------------------------------------------- /emokit/python/emokit/cv2.so: -------------------------------------------------------------------------------- 1 | /usr/local/Cellar/opencv/2.4.12/lib/python2.7/site-packages/cv2.so -------------------------------------------------------------------------------- /emokit/python/emokit/data.txt: -------------------------------------------------------------------------------- 1 | {"Y": {"quality": 0, "value": -5}, "F3": {"quality": 0, "value": -92}, "F4": {"quality": 0, "value": 555}, "P7": {"quality": 0, "value": -1221}, "FC6": {"quality": 0, "value": 185}, "F7": {"quality": 0, "value": 150}, "F8": {"quality": 0, "value": -142}, "T7": {"quality": 0, "value": -66}, "P8": {"quality": 0, "value": 376}, "FC5": {"quality": 0, "value": 300}, "AF4": {"quality": 0, "value": -177}, "battery": {"value": 46}, "Unknown": {"quality": 0, "value": 37}, "T8": {"quality": 0, "value": 178}, "X": {"quality": 0, "value": 5}, "O2": {"quality": 0, "value": 25}, "O1": {"quality": 0, "value": -146}, "AF3": {"quality": 0, "value": 357}} -------------------------------------------------------------------------------- /emokit/python/emokit/hid.o: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nikhiljay/brainwaves/42d96dccedf09504589fc9e14e3b470de7f5c0b2/emokit/python/emokit/hid.o -------------------------------------------------------------------------------- /emokit/python/emokit/src/pip-delete-this-directory.txt: -------------------------------------------------------------------------------- 1 | This file is placed here by pip to indicate the source was put 2 | here by pip. 3 | 4 | Once this package is successfully installed this source code will be 5 | deleted (unless you remove this file). 6 | -------------------------------------------------------------------------------- /emokit/python/example.py: -------------------------------------------------------------------------------- 1 | # This is an example of popping a packet from the Emotiv class's packet queue 2 | # and printing the gyro x and y values to the console. 3 | 4 | from emokit.emotiv import Emotiv 5 | import platform 6 | if platform.system() == "Windows": 7 | import socket # Needed to prevent gevent crashing on Windows. (surfly / gevent issue #459) 8 | import gevent 9 | 10 | if __name__ == "__main__": 11 | headset = Emotiv() 12 | gevent.spawn(headset.setup) 13 | gevent.sleep(0) 14 | try: 15 | while True: 16 | packet = headset.dequeue() 17 | print packet.gyro_x, packet.gyro_y 18 | gevent.sleep(0) 19 | except KeyboardInterrupt: 20 | headset.close() 21 | finally: 22 | headset.close() 23 | -------------------------------------------------------------------------------- /emokit/python/mouse_control.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | # Example of using the gyro values to control mouse movement. 3 | import ctypes 4 | from ctypes import cdll 5 | 6 | import platform 7 | if platform.system() == "Windows": 8 | import socket # Needed to prevent gevent crashing on Windows. (surfly / gevent issue #459) 9 | import gevent 10 | 11 | from emokit.emotiv import Emotiv 12 | 13 | 14 | class Xlib: 15 | def __init__(self): 16 | self.xlib = cdll.LoadLibrary('libX11.so') 17 | 18 | display = self.xlib.XOpenDisplay(None) 19 | dflt_screen_num = self.xlib.XDefaultScreen(display) 20 | default_screen = self.xlib.XScreenOfDisplay(display, dflt_screen_num) 21 | 22 | self.width = self.xlib.XWidthOfScreen(default_screen) 23 | self.height = self.xlib.XHeightOfScreen(default_screen) 24 | self.xlib.XCloseDisplay(display) 25 | 26 | def move_mouse(self, x, y): 27 | display = self.xlib.XOpenDisplay(None) 28 | root = self.xlib.XDefaultRootWindow(display) 29 | self.xlib.XWarpPointer(display, None, root, 0, 0, 0, 0, x, y) 30 | self.xlib.XCloseDisplay(display) 31 | 32 | 33 | class WinMouse: 34 | def __init__(self): 35 | user32 = ctypes.windll.user32 36 | self.width = user32.GetSystemMetrics(0) 37 | self.height = user32.GetSystemMetrics(1) 38 | 39 | def click(self, x, y): 40 | ctypes.windll.user32.SetCursorPos(x, y) 41 | ctypes.windll.user32.mouse_event(2, 0, 0, 0, 0) # left down 42 | ctypes.windll.user32.mouse_event(4, 0, 0, 0, 0) # left up 43 | 44 | def move_mouse(self, x, y): 45 | ctypes.windll.user32.SetCursorPos(x, y) 46 | 47 | 48 | def main(): 49 | if not platform.system() == 'Windows': 50 | screen = Xlib() 51 | else: 52 | screen = WinMouse() 53 | width = screen.width 54 | height = screen.height 55 | 56 | cursor_x, cursor_y = width / 2, height / 2 57 | while True: 58 | updated = False 59 | packet = headset.dequeue() 60 | if abs(packet.gyro_x) > 1: 61 | cursor_x -= packet.gyro_x 62 | updated = True 63 | if abs(packet.gyro_y) > 1: 64 | cursor_y += packet.gyro_y 65 | updated = True 66 | cursor_x = max(0, min(cursor_x, width)) 67 | cursor_y = max(0, min(cursor_y, height)) 68 | if updated: 69 | screen.move_mouse(cursor_x, cursor_y) 70 | gevent.sleep(0) 71 | 72 | 73 | headset = None 74 | if __name__ == "__main__": 75 | try: 76 | headset = Emotiv() 77 | gevent.spawn(headset.setup) 78 | gevent.sleep(0) 79 | main() 80 | 81 | finally: 82 | if headset: 83 | headset.close() 84 | -------------------------------------------------------------------------------- /emokit/python/render.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | # Renders a window with graph values for each sensor and a box for gyro values. 3 | try: 4 | import psyco 5 | psyco.full() 6 | except ImportError: 7 | print 'No psyco. Expect poor performance. Not really...' 8 | 9 | import pygame 10 | import platform 11 | from pygame import FULLSCREEN 12 | if platform.system() == "Windows": 13 | import socket # Needed to prevent gevent crashing on Windows. (surfly / gevent issue #459) 14 | import gevent 15 | from emokit.emotiv import Emotiv 16 | 17 | quality_color = { 18 | "0": (0, 0, 0), 19 | "1": (255, 0, 0), 20 | "2": (255, 0, 0), 21 | "3": (255, 255, 0), 22 | "4": (255, 255, 0), 23 | "5": (0, 255, 0), 24 | "6": (0, 255, 0), 25 | "7": (0, 255, 0), 26 | } 27 | 28 | old_quality_color = { 29 | "0": (0, 0, 0), 30 | "1": (255, 0, 0), 31 | "2": (255, 255, 0), 32 | "3": (0, 255, 0), 33 | "4": (0, 255, 0), 34 | } 35 | 36 | 37 | class Grapher(object): 38 | """ 39 | Worker that draws a line for the sensor value. 40 | """ 41 | def __init__(self, screen, name, i): 42 | """ 43 | Initializes graph worker 44 | """ 45 | self.screen = screen 46 | self.name = name 47 | self.range = float(1 << 13) 48 | self.x_offset = 40 49 | self.y = i * gheight 50 | self.buffer = [] 51 | font = pygame.font.Font(None, 24) 52 | self.text = font.render(self.name, 1, (255, 0, 0)) 53 | self.text_pos = self.text.get_rect() 54 | self.text_pos.centery = self.y + gheight 55 | self.first_packet = True 56 | self.y_offset = 0 57 | 58 | def update(self, packet): 59 | """ 60 | Appends value and quality values to drawing buffer. 61 | """ 62 | if len(self.buffer) == 800 - self.x_offset: 63 | self.buffer = self.buffer[1:] 64 | self.buffer.append([packet.sensors[self.name]['value'], packet.sensors[self.name]['quality'], packet.old_model]) 65 | 66 | def calc_y(self, val): 67 | """ 68 | Calculates line height from value. 69 | """ 70 | return val - self.y_offset + gheight 71 | 72 | def draw(self): 73 | """ 74 | Draws a line from values stored in buffer. 75 | """ 76 | if len(self.buffer) == 0: 77 | return 78 | 79 | if self.first_packet: 80 | self.y_offset = self.buffer[0][0] 81 | self.first_packet = False 82 | pos = self.x_offset, self.calc_y(self.buffer[0][0]) + self.y 83 | for i, (value, quality, old_model) in enumerate(self.buffer): 84 | y = self.calc_y(value) + self.y 85 | if old_model: 86 | color = old_quality_color[str(quality)] 87 | else: 88 | color = quality_color[str(quality)] 89 | pygame.draw.line(self.screen, color, pos, (self.x_offset + i, y)) 90 | pos = (self.x_offset + i, y) 91 | self.screen.blit(self.text, self.text_pos) 92 | 93 | 94 | def main(): 95 | """ 96 | Creates pygame window and graph drawing workers for each sensor. 97 | """ 98 | global gheight 99 | pygame.init() 100 | screen = pygame.display.set_mode((800, 600)) 101 | graphers = [] 102 | recordings = [] 103 | recording = False 104 | record_packets = [] 105 | updated = False 106 | cursor_x, cursor_y = 400, 300 107 | for name in 'AF3 F7 F3 FC5 T7 P7 O1 O2 P8 T8 FC6 F4 F8 AF4'.split(' '): 108 | graphers.append(Grapher(screen, name, len(graphers))) 109 | fullscreen = False 110 | emotiv = Emotiv(display_output=True) 111 | gevent.spawn(emotiv.setup) 112 | gevent.sleep(0) 113 | while emotiv.running: 114 | for event in pygame.event.get(): 115 | if event.type == pygame.QUIT: 116 | emotiv.close() 117 | return 118 | if event.type == pygame.KEYDOWN: 119 | if event.key == pygame.K_ESCAPE: 120 | emotiv.close() 121 | return 122 | elif event.key == pygame.K_f: 123 | if fullscreen: 124 | screen = pygame.display.set_mode((800, 600)) 125 | fullscreen = False 126 | else: 127 | screen = pygame.display.set_mode((800, 600), FULLSCREEN, 16) 128 | fullscreen = True 129 | elif event.key == pygame.K_r: 130 | if not recording: 131 | record_packets = [] 132 | recording = True 133 | else: 134 | recording = False 135 | recordings.append(list(record_packets)) 136 | record_packets = None 137 | packets_in_queue = 0 138 | try: 139 | while packets_in_queue < 8: 140 | packet = emotiv.dequeue() 141 | if abs(packet.gyro_x) > 1: 142 | cursor_x = max(0, min(cursor_x, 800)) 143 | cursor_x -= packet.gyro_x 144 | if abs(packet.gyro_y) > 1: 145 | cursor_y += packet.gyro_y 146 | cursor_y = max(0, min(cursor_y, 600)) 147 | map(lambda x: x.update(packet), graphers) 148 | if recording: 149 | record_packets.append(packet) 150 | updated = True 151 | packets_in_queue += 1 152 | except Exception, ex: 153 | print ex 154 | 155 | if updated: 156 | screen.fill((75, 75, 75)) 157 | map(lambda x: x.draw(), graphers) 158 | pygame.draw.rect(screen, (255, 255, 255), (cursor_x - 5, cursor_y - 5, 10, 10), 0) 159 | pygame.display.flip() 160 | updated = False 161 | gevent.sleep(0) 162 | 163 | try: 164 | gheight = 580 / 14 165 | main() 166 | 167 | except Exception, e: 168 | print e 169 | -------------------------------------------------------------------------------- /emokit/python/requirements.txt: -------------------------------------------------------------------------------- 1 | gevent 2 | pycrypto 3 | -------------------------------------------------------------------------------- /emokit/python/setup.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | from setuptools import setup 3 | import os 4 | 5 | import emokit 6 | 7 | long_description = None 8 | 9 | packages = [ 10 | "emokit", 11 | ] 12 | 13 | requirements = open("requirements.txt", "r").read().split("\n") 14 | 15 | setup( 16 | name="emokit", 17 | version=emokit.__version__, 18 | url="https://github.com/kanzure/emokit", 19 | license="", 20 | author="Bryan Bishop", 21 | author_email="kanzure@gmail.com", 22 | maintainer="Bryan Bishop", 23 | maintainer_email="kanzure@gmail.com", 24 | description="emotiv epoc eeg headset sdk", 25 | long_description=long_description, 26 | packages=packages, 27 | install_requires=requirements, 28 | scripts=[], 29 | platforms="any", 30 | zip_safe=False, 31 | classifiers=[ 32 | "Operating System :: OS Independent", 33 | "Programming Language :: Python", 34 | ] 35 | ) 36 | -------------------------------------------------------------------------------- /emokit/python/tests/test_emokit.py: -------------------------------------------------------------------------------- 1 | # -*- encoding: utf-8 -*- 2 | from emokit.emotiv import Emotiv 3 | 4 | import unittest 5 | 6 | class TestEmotiv(unittest.TestCase): 7 | def test_emotiv(self): 8 | emotiv = Emotiv() 9 | 10 | -------------------------------------------------------------------------------- /emokit/src/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | ########################################## 2 | ## libemokit ### 3 | ########################################## 4 | 5 | # Create a library called "libemokit" 6 | ADD_LIBRARY (emokit emokit.c) 7 | target_link_libraries (emokit ${LIBS}) 8 | 9 | INSTALL (TARGETS emokit 10 | LIBRARY DESTINATION lib 11 | ARCHIVE DESTINATION lib 12 | ) 13 | 14 | IF(BUILD_SHARED_LIBS) 15 | INSTALL (FILES 16 | ${LIBEMOKIT_HEADERS} 17 | DESTINATION include/emokit 18 | ) 19 | ENDIF() 20 | 21 | -------------------------------------------------------------------------------- /scripts/brainwaves-script: -------------------------------------------------------------------------------- 1 | open /Users/Nikhil/Projects/Development/AAR/scripts/ngrok 2 | python /Users/Nikhil/Projects/Development/AAR/emokit/python/emokit/emotiv.py 3 | -------------------------------------------------------------------------------- /scripts/data.txt: -------------------------------------------------------------------------------- 1 | {"Y": {"quality": 0, "value": -6}, "F3": {"quality": 0, "value": -111}, "F4": {"quality": 0, "value": 576}, "P7": {"quality": 0, "value": -1272}, "FC6": {"quality": 0, "value": 177}, "F7": {"quality": 0, "value": 246}, "F8": {"quality": 0, "value": -154}, "T7": {"quality": 0, "value": -78}, "P8": {"quality": 0, "value": 384}, "FC5": {"quality": 0, "value": 294}, "Battery": {"value": 32}, "AF4": {"quality": 0, "value": -187}, "Unknown": {"quality": 0, "value": 30}, "T8": {"quality": 0, "value": 186}, "X": {"quality": 0, "value": 5}, "O2": {"quality": 0, "value": 2}, "O1": {"quality": 0, "value": -150}, "AF3": {"quality": 0, "value": 370}} -------------------------------------------------------------------------------- /scripts/ngrok: -------------------------------------------------------------------------------- 1 | cd 2 | ./ngrok http 8000 3 | --------------------------------------------------------------------------------