diff --git a/Swift Playground for Bluefruit.playgroundbook.zip b/Bluefruit/Swift Playground for Bluefruit.playgroundbook.zip similarity index 92% rename from Swift Playground for Bluefruit.playgroundbook.zip rename to Bluefruit/Swift Playground for Bluefruit.playgroundbook.zip index 06a5af8..54debf7 100644 Binary files a/Swift Playground for Bluefruit.playgroundbook.zip and b/Bluefruit/Swift Playground for Bluefruit.playgroundbook.zip differ diff --git a/Bluefruit/Swift Playground for Bluefruit.playgroundbook/Contents/Chapters/Chapter1.playgroundchapter/Manifest.plist b/Bluefruit/Swift Playground for Bluefruit.playgroundbook/Contents/Chapters/Chapter1.playgroundchapter/Manifest.plist new file mode 100755 index 0000000..65d1cc4 --- /dev/null +++ b/Bluefruit/Swift Playground for Bluefruit.playgroundbook/Contents/Chapters/Chapter1.playgroundchapter/Manifest.plist @@ -0,0 +1,14 @@ + + + + + Version + 1.0 + Name + Chapter 1 + Pages + + Page1.playgroundpage + + + diff --git a/Bluefruit/Swift Playground for Bluefruit.playgroundbook/Contents/Chapters/Chapter1.playgroundchapter/Pages/Page1.playgroundpage/Contents.swift b/Bluefruit/Swift Playground for Bluefruit.playgroundbook/Contents/Chapters/Chapter1.playgroundchapter/Pages/Page1.playgroundpage/Contents.swift new file mode 100755 index 0000000..06cb3a1 --- /dev/null +++ b/Bluefruit/Swift Playground for Bluefruit.playgroundbook/Contents/Chapters/Chapter1.playgroundchapter/Pages/Page1.playgroundpage/Contents.swift @@ -0,0 +1,109 @@ +/*:#localized(key: "FirstProseBlock") + **Goal:** Learn how to use basic movement functions. + + It’s time to race! Start your engines! + + + Use your Swift programming skills to control the Robot Rover with **basic motion** function calls like `moveForward()`, `turnRight()`, `turnLeft()`, and `moveBack()`. + + + + + */ +//#-code-completion(everything, hide) +//#-code-completion(identifier, show, moveForward(), turnLeft(), moveBack(), turnRight(), wait(), dance()) +//#-hidden-code +import Foundation +import PlaygroundSupport + +setup() + + +//var rcCommand: RCCommand = RCCommand() +//var commandManager: CommandManager = CommandManager() + +//func testFw(_ time:) { +// rcCommand.duration = time +//} + +//func moveForward(_ item: Int) { +// let page = PlaygroundPage.current +// if let proxy = page.liveView as? PlaygroundRemoteLiveViewProxy { +// let message = PlaygroundValue.integer(item) +// // let message2: PlaygroundValue = .string(CommandType.COMMAND_MOVE_FORWARD.rawValue) +// +// proxy.send(message) +// commandManager.moveForward() +// } +//} + +//func moveBack(_ item: Int) { +// let page = PlaygroundPage.current +// if let proxy = page.liveView as? PlaygroundRemoteLiveViewProxy { +// let message = PlaygroundValue.integer(item) +// // let message2: PlaygroundValue = .string(CommandType.COMMAND_MOVE_BACKWARD.rawValue) +// +// proxy.send(message) +// commandManager.moveBack() +// } +//} + + +//func turnLeft(_ item: Int) { +// let page = PlaygroundPage.current +// if let proxy = page.liveView as? PlaygroundRemoteLiveViewProxy { +// let message = PlaygroundValue.integer(item) +// //let message2: PlaygroundValue = .string(CommandType.COMMAND_TURN_LEFT.rawValue) +// +// proxy.send(message) +// commandManager.turnLeft() +// } +//} +// +// +//func turnRight(_ item: Int) { +// let page = PlaygroundPage.current +// if let proxy = page.liveView as? PlaygroundRemoteLiveViewProxy { +// let message = PlaygroundValue.integer(item) +// //let message2: PlaygroundValue = .string(CommandType.COMMAND_TURN_RIGHT.rawValue) +// +// proxy.send(message) +// commandManager.turnRight() +// } +//} + +//func testFw(_ item: Int) { +// let page = PlaygroundPage.current +// if let proxy = page.liveView as? PlaygroundRemoteLiveViewProxy { +// let message: PlaygroundValue = .integer(item) +// proxy.send(message) +// } +//} + + + + + + +//#-end-hidden-code +//#-editable-code +moveForward() +//#-end-editable-code +//#-hidden-code + +/* + turnRight() + moveForward() + turnLeft() + moveForward() + turnLeft() + moveForward() + moveForward() + turnRight() + moveForward() + turnRight() + moveForward() + turnLeft() + pause() + */ +//#-end-hidden-code diff --git a/Bluefruit/Swift Playground for Bluefruit.playgroundbook/Contents/Chapters/Chapter1.playgroundchapter/Pages/Page1.playgroundpage/LiveView.swift b/Bluefruit/Swift Playground for Bluefruit.playgroundbook/Contents/Chapters/Chapter1.playgroundchapter/Pages/Page1.playgroundpage/LiveView.swift new file mode 100644 index 0000000..ca47f15 --- /dev/null +++ b/Bluefruit/Swift Playground for Bluefruit.playgroundbook/Contents/Chapters/Chapter1.playgroundchapter/Pages/Page1.playgroundpage/LiveView.swift @@ -0,0 +1,11 @@ +// Created by Trevor Beaton on 12/14/17. +// Copyright © 2017 Vanguard Logic LLC. All rights reserved. + +import UIKit +import Foundation +import PlaygroundSupport +import PlaygroundBluetooth + + +let rcViewController: RCViewController = RCViewController(1) +PlaygroundPage.current.liveView = rcViewController diff --git a/Bluefruit/Swift Playground for Bluefruit.playgroundbook/Contents/Chapters/Chapter1.playgroundchapter/Pages/Page1.playgroundpage/Manifest.plist b/Bluefruit/Swift Playground for Bluefruit.playgroundbook/Contents/Chapters/Chapter1.playgroundchapter/Pages/Page1.playgroundpage/Manifest.plist new file mode 100755 index 0000000..a969d7b --- /dev/null +++ b/Bluefruit/Swift Playground for Bluefruit.playgroundbook/Contents/Chapters/Chapter1.playgroundchapter/Pages/Page1.playgroundpage/Manifest.plist @@ -0,0 +1,14 @@ + + + + + Name + Page 1 + LiveViewMode + VisibleByDefault + LiveViewEdgeToEdge + + PlaygroundLoggingMode + Off + + diff --git a/Bluefruit/Swift Playground for Bluefruit.playgroundbook/Contents/Chapters/Chapter1.playgroundchapter/Pages/Page1.playgroundpage/PrivateResources/Hints.plist b/Bluefruit/Swift Playground for Bluefruit.playgroundbook/Contents/Chapters/Chapter1.playgroundchapter/Pages/Page1.playgroundpage/PrivateResources/Hints.plist new file mode 100755 index 0000000..ff7ae9f --- /dev/null +++ b/Bluefruit/Swift Playground for Bluefruit.playgroundbook/Contents/Chapters/Chapter1.playgroundchapter/Pages/Page1.playgroundpage/PrivateResources/Hints.plist @@ -0,0 +1,8 @@ + + + + + Hints + + + diff --git a/Bluefruit/Swift Playground for Bluefruit.playgroundbook/Contents/Chapters/Chapter1.playgroundchapter/Pages/Page1.playgroundpage/PublicResources/.gitkeep b/Bluefruit/Swift Playground for Bluefruit.playgroundbook/Contents/Chapters/Chapter1.playgroundchapter/Pages/Page1.playgroundpage/PublicResources/.gitkeep new file mode 100755 index 0000000..e69de29 diff --git a/Bluefruit/Swift Playground for Bluefruit.playgroundbook/Contents/Chapters/Chapter1.playgroundchapter/Pages/Page1.playgroundpage/Sources/.gitkeep b/Bluefruit/Swift Playground for Bluefruit.playgroundbook/Contents/Chapters/Chapter1.playgroundchapter/Pages/Page1.playgroundpage/Sources/.gitkeep new file mode 100755 index 0000000..e69de29 diff --git a/Bluefruit/Swift Playground for Bluefruit.playgroundbook/Contents/Chapters/Chapter1.playgroundchapter/Pages/Page1.playgroundpage/Sources/CommandList.swift b/Bluefruit/Swift Playground for Bluefruit.playgroundbook/Contents/Chapters/Chapter1.playgroundchapter/Pages/Page1.playgroundpage/Sources/CommandList.swift new file mode 100644 index 0000000..52ce6f5 --- /dev/null +++ b/Bluefruit/Swift Playground for Bluefruit.playgroundbook/Contents/Chapters/Chapter1.playgroundchapter/Pages/Page1.playgroundpage/Sources/CommandList.swift @@ -0,0 +1,90 @@ +// +// CommandList.swift +// +// Created by Trevor Beaton on 12/14/17. +// Copyright © 2017 Vanguard Logic LLC. All rights reserved. + +import Foundation +import PlaygroundSupport + +public func moveForward(){ + commandManager.moveForward() +} + +public func moveBack(){ + commandManager.moveBack() +} + +public func turnRight(){ + commandManager.turnRight() +} + +public func turnLeft(){ + commandManager.turnLeft() +} + +public func wait() { + commandManager.pause() +} + +//public func wheelie(){ +// commandManager.moveBack() +// commandManager.moveForward() +//} + +public func dance(){ + commandManager.turnLeft() + commandManager.turnLeft() + commandManager.turnRight() + commandManager.turnRight() + commandManager.turnLeft() + commandManager.turnLeft() + commandManager.turnRight() + commandManager.turnRight() + commandManager.pause() + commandManager.moveBack() + commandManager.moveForward() + commandManager.turnRight() + commandManager.turnRight() +} + +/* + create a function reference that takes the duration time and sends it to the command manager function that will be sent to the RCCommand.Duration + */ + +public func moveForward(_ seconds: Int) { + let page = PlaygroundPage.current + if let proxy = page.liveView as? PlaygroundRemoteLiveViewProxy { + let message = PlaygroundValue.integer(seconds) + proxy.send(message) + commandManager.moveForward() + } +} + +public func moveBack(_ seconds: Int) { + let page = PlaygroundPage.current + if let proxy = page.liveView as? PlaygroundRemoteLiveViewProxy { + let message = PlaygroundValue.integer(seconds) + proxy.send(message) + commandManager.moveBack() + } +} + +public func turnLeft(_ seconds: Int) { + let page = PlaygroundPage.current + if let proxy = page.liveView as? PlaygroundRemoteLiveViewProxy { + let message = PlaygroundValue.integer(seconds) + proxy.send(message) + commandManager.turnLeft() + } +} + + +public func turnRight(_ seconds: Int) { + let page = PlaygroundPage.current + if let proxy = page.liveView as? PlaygroundRemoteLiveViewProxy { + let message = PlaygroundValue.integer(seconds) + proxy.send(message) + commandManager.turnRight() + } +} diff --git a/Bluefruit/Swift Playground for Bluefruit.playgroundbook/Contents/Chapters/Chapter1.playgroundchapter/Pages/Page1.playgroundpage/Sources/Setup.swift b/Bluefruit/Swift Playground for Bluefruit.playgroundbook/Contents/Chapters/Chapter1.playgroundchapter/Pages/Page1.playgroundpage/Sources/Setup.swift new file mode 100644 index 0000000..e9b1580 --- /dev/null +++ b/Bluefruit/Swift Playground for Bluefruit.playgroundbook/Contents/Chapters/Chapter1.playgroundchapter/Pages/Page1.playgroundpage/Sources/Setup.swift @@ -0,0 +1,52 @@ +//Newer +// Created by Trevor Beaton on 12/14/17. +// Copyright © 2017 Vanguard Logic LLC. All rights reserved. +import Foundation +import PlaygroundSupport +import PlaygroundBluetooth + + +var delegate: UserProcessDelegate? + +let rcBluetooth: RCBluetooth = RCBluetooth() +let commandManager: CommandManager = CommandManager() + +public func setup(){ + printLog(newString: #function) + let page = PlaygroundPage.current + page.needsIndefiniteExecution = true + let proxy = page.liveView as? PlaygroundRemoteLiveViewProxy + delegate = UserProcessDelegate(pauseHandler: commandManager) + delegate?.onAssessment = assessment + proxy?.delegate = delegate +} + + + +public func assessment(_ playgroundValue:PlaygroundValue)->Bool{ + // Assessment + var correctSolution:[CommandType] = [ CommandType.COMMAND_MOVE_FORWARD ] + + var commands:[PlaygroundValue] = [PlaygroundValue]() + + if case let .array(values) = playgroundValue { + commands = values + } + + let result:Bool = RCCommand.solutionChecker(commands, correctSolution) + + var failureHints = [NSLocalizedString("Fail Hint.Test.", comment: "")] + + //Update assessment status + PlaygroundPage.current.assessmentStatus = .pass(message: NSLocalizedString("### Pass! \n Now that’s what I call a victory dance!\n\n[**Next Page**](@next)", comment: "")) + + if(result){ + printLog(newString: "PASS!") + PlaygroundPage.current.assessmentStatus = .pass(message: NSLocalizedString("### Pass Message. \n\n[**Next Page**](@next)", comment: "")) + } + else{ + printLog(newString: "Fail") + PlaygroundPage.current.assessmentStatus = .fail(hints: failureHints, solution: nil) + } + return result +} diff --git a/Bluefruit/Swift Playground for Bluefruit.playgroundbook/Contents/Manifest.plist b/Bluefruit/Swift Playground for Bluefruit.playgroundbook/Contents/Manifest.plist new file mode 100755 index 0000000..06109a8 --- /dev/null +++ b/Bluefruit/Swift Playground for Bluefruit.playgroundbook/Contents/Manifest.plist @@ -0,0 +1,26 @@ + + + + + SwiftVersion + 3.0 + ImageReference + icon.png + Version + 3.0 + ContentVersion + 1.0 + Name + Empty + ContentIdentifier + com.example.adafruitswiftplayground + DeploymentTarget + ios10.0 + DevelopmentRegion + en + Chapters + + Chapter1.playgroundchapter + + + diff --git a/Bluefruit/Swift Playground for Bluefruit.playgroundbook/Contents/PrivateResources/Images/adafruitAvatarPlaceholder.png b/Bluefruit/Swift Playground for Bluefruit.playgroundbook/Contents/PrivateResources/Images/adafruitAvatarPlaceholder.png new file mode 100644 index 0000000..bcd0cb5 Binary files /dev/null and b/Bluefruit/Swift Playground for Bluefruit.playgroundbook/Contents/PrivateResources/Images/adafruitAvatarPlaceholder.png differ diff --git a/Bluefruit/Swift Playground for Bluefruit.playgroundbook/Contents/PrivateResources/Images/adafruit_logo_small copy.png b/Bluefruit/Swift Playground for Bluefruit.playgroundbook/Contents/PrivateResources/Images/adafruit_logo_small copy.png new file mode 100644 index 0000000..6bd3743 Binary files /dev/null and b/Bluefruit/Swift Playground for Bluefruit.playgroundbook/Contents/PrivateResources/Images/adafruit_logo_small copy.png differ diff --git a/Bluefruit/Swift Playground for Bluefruit.playgroundbook/Contents/PrivateResources/icon.png b/Bluefruit/Swift Playground for Bluefruit.playgroundbook/Contents/PrivateResources/icon.png new file mode 100644 index 0000000..7431147 Binary files /dev/null and b/Bluefruit/Swift Playground for Bluefruit.playgroundbook/Contents/PrivateResources/icon.png differ diff --git a/Bluefruit/Swift Playground for Bluefruit.playgroundbook/Contents/PublicResources/.gitkeep b/Bluefruit/Swift Playground for Bluefruit.playgroundbook/Contents/PublicResources/.gitkeep new file mode 100755 index 0000000..e69de29 diff --git a/Bluefruit/Swift Playground for Bluefruit.playgroundbook/Contents/Sources/.gitkeep b/Bluefruit/Swift Playground for Bluefruit.playgroundbook/Contents/Sources/.gitkeep new file mode 100755 index 0000000..e69de29 diff --git a/Bluefruit/Swift Playground for Bluefruit.playgroundbook/Contents/Sources/CommandManager.swift b/Bluefruit/Swift Playground for Bluefruit.playgroundbook/Contents/Sources/CommandManager.swift new file mode 100644 index 0000000..3ab3749 --- /dev/null +++ b/Bluefruit/Swift Playground for Bluefruit.playgroundbook/Contents/Sources/CommandManager.swift @@ -0,0 +1,102 @@ +// +// CommandManager.swift +// +// +// Created by Trevor Beaton on 12/14/17. +// Copyright © 2017 Vanguard Logic LLC. All rights reserved. + +import Foundation +import PlaygroundSupport + +public enum CommandType: String { + + case COMMAND_MOVE_FORWARD = "command_moveForward" + case COMMAND_MOVE_BACKWARD = "command_moveBackward" + case COMMAND_TURN_RIGHT = "command_turnRight" + case COMMAND_TURN_LEFT = "command_turnLeft" + case COMMAND_PAUSE = "command_pause" + case COMMAND_EXIT_PROGRAM = "ExitProgram" + +} + +public protocol CommandPauseDelegate { + var isReadyForMoreCommands: Bool { get set } + var returnValue: Bool { get set } + +} + +extension CommandPauseDelegate { + /// Waits until `isReadyForMoreCommands` is set to true. + func wait() { + repeat { + RunLoop.main.run(mode: .defaultRunLoopMode, before: Date(timeIntervalSinceNow: 0.1)) + } while !isReadyForMoreCommands + } +} + +public class CommandManager: CommandPauseDelegate { + + public var isReadyForMoreCommands = true + public var returnValue = false + var command: PlaygroundValue = .string("") + var userInt: Int? + + public init(){ + } + + public func sendCommand(_ commandData:PlaygroundValue) { + let page = PlaygroundPage.current + if let proxy = page.liveView as? PlaygroundRemoteLiveViewProxy { + proxy.send(commandData) + } + // Spin the runloop until the LiveView process has completed the current command. + isReadyForMoreCommands = false + wait() + } + + + + public func moveForward(){ + command = .string(CommandType.COMMAND_MOVE_FORWARD.rawValue) + sendCommand(command) + printLog(newString: #function) + } + + public func moveBack(){ + command = .string(CommandType.COMMAND_MOVE_BACKWARD.rawValue) + sendCommand(command) + printLog(newString: #function) + } + + public func turnRight(){ + command = .string(CommandType.COMMAND_TURN_RIGHT.rawValue) + sendCommand(command) + printLog(newString: #function) + } + + public func turnLeft(){ + command = .string(CommandType.COMMAND_TURN_LEFT.rawValue) + sendCommand(command) + printLog(newString: #function) + } + + public func exitProgram(){ + command = .string(CommandType.COMMAND_EXIT_PROGRAM.rawValue) + sendCommand(command) + } + + public func pause(){ + command = .string(CommandType.COMMAND_PAUSE.rawValue) + sendCommand(command) + } + + public func testForward(){ + command = .string(CommandType.COMMAND_MOVE_FORWARD.rawValue) + sendCommand(command) + printLog(newString: #function) + } + + public func intTaker(){ + printLog(newString: "Hello") + } +} diff --git a/Bluefruit/Swift Playground for Bluefruit.playgroundbook/Contents/Sources/Constants.swift b/Bluefruit/Swift Playground for Bluefruit.playgroundbook/Contents/Sources/Constants.swift new file mode 100644 index 0000000..d46d8a5 --- /dev/null +++ b/Bluefruit/Swift Playground for Bluefruit.playgroundbook/Contents/Sources/Constants.swift @@ -0,0 +1,64 @@ +// Created by Trevor Beaton on 12/14/17. +// Copyright © 2017 Vanguard Logic LLC. All rights reserved. + + + +import UIKit +import CoreBluetooth +import PlaygroundSupport +import Foundation + + + +let kBLEService_UUID = "6e400001-b5a3-f393-e0a9-e50e24dcca9e" +let kBLE_Characteristic_uuid_Tx = "6e400002-b5a3-f393-e0a9-e50e24dcca9e" +let kBLE_Characteristic_uuid_Rx = "6e400003-b5a3-f393-e0a9-e50e24dcca9e" + +let BLEService_UUID = CBUUID(string: kBLEService_UUID) + +let BLE_Characteristic_uuid_Tx = CBUUID(string: kBLE_Characteristic_uuid_Tx)//(Property = Write without response) + +let BLE_Characteristic_uuid_Rx = CBUUID(string: kBLE_Characteristic_uuid_Rx)// (Property = Read/Notify) + + + +public class Constants: NSObject { + + public static let COMMAND_FINISHED = "CommandFinishedtestS" + + public static let PROGRAM_FINISHED = "ProgramFinished" + + + public static func commandTextToLocalizedText(_ text:String)->String{ + if(text == ""){ + return "" + } + var type:CommandType = CommandType(rawValue: text)! + return self.commandTypeToLocalizedText(type) + } + + public static func commandTypeToLocalizedText(_ type:CommandType)->String{ + var text:String = "" + switch(type) { + + case .COMMAND_MOVE_FORWARD: + text = NSLocalizedString("I'm moving forward!", comment: "") + case .COMMAND_MOVE_BACKWARD: + text = NSLocalizedString("Backing up!", comment: "") + case .COMMAND_TURN_RIGHT: + text = NSLocalizedString("And a quick turn to the right!", comment: "") + case .COMMAND_TURN_LEFT: + text = NSLocalizedString("And a quick turn to the left!", comment: "") + + default: + break + } + return text + } + + + + + + +} diff --git a/Bluefruit/Swift Playground for Bluefruit.playgroundbook/Contents/Sources/RCBluetooth.swift b/Bluefruit/Swift Playground for Bluefruit.playgroundbook/Contents/Sources/RCBluetooth.swift new file mode 100644 index 0000000..c1d9cf0 --- /dev/null +++ b/Bluefruit/Swift Playground for Bluefruit.playgroundbook/Contents/Sources/RCBluetooth.swift @@ -0,0 +1,275 @@ +// +// RCBluetooth.swift +// +// Created by Trevor Beaton on 12/14/17. +// Copyright © 2017 Vanguard Logic LLC. All rights reserved. +// + +import Foundation +import CoreBluetooth +import PlaygroundSupport +import PlaygroundBluetooth + + +//Global variables and print funtion for debugging +public var printString = "" +public var bleStatus: String? +public var bleStatus2: String? +public func printLog(newString: String) { + let appendString = "\n" + printString = newString + appendString + NotificationCenter.default.post(name:NSNotification.Name(rawValue: "Print"), object: nil) +} + +public class RCBluetooth: NSObject, PlaygroundBluetoothCentralManagerDelegate, CBPeripheralDelegate { + + + // Mark:- Data + + + var timer = Timer() + var duration: Int = 2000 + var txCharacteristic : CBCharacteristic? + var rxCharacteristic : CBCharacteristic? + var characteristicASCIIValue = NSString() + + //Public variables + public var onDataWritten:(()->Void)? + public var isConnected: Bool = false + public var onCharacteristicsUpdated:((Data)->Void)? + public var centralManager: PlaygroundBluetoothCentralManager? + public var onCharacteristicsDiscovered:((CBPeripheral)->Void)? + + //Private variables + private var blePeripheral: CBPeripheral? + private let data = NSMutableData() + + //Motion String Commands + var forwardString = "!B516" + var stopString = "!B507" + var backString = "!B615" + var backStopString = "!B606" + var rightString = "!B813" + var rightStop = "!B804" + var leftString = "!B714" + var leftStop = "!B705" + let txCharMax: Int = 20 + + public override init() { + super.init() + //Creates a central manager that supports communicating with Bluetooth peripherals + centralManager = PlaygroundBluetoothCentralManager(services: [BLEService_UUID], queue: .global()) + centralManager!.delegate = self + } + + + //:- Methods for Connectivity + + + //Tells the delegate that the state of the central manager has changed. + public func centralManagerStateDidChange(_ centralManager: PlaygroundBluetoothCentralManager) { + if centralManager.state == .poweredOn { + isConnected = true + printLog(newString: "Bluetooth is Enabled.") + }else { + printLog(newString: "Bluetooth is Disabled. Turn On Bluetooth in Control Panel.") + } + } + + // Tells the delegate that a peripheral has been discovered during scanning. + public func centralManager(_ centralManager: PlaygroundBluetoothCentralManager, didDiscover peripheral: CBPeripheral, withAdvertisementData advertisementData: [String : Any]?, rssi: Double) { + } + + // Tells the delegate that the central manager is about to attempt to establish a connection with a peripheral. + public func centralManager(_ centralManager: PlaygroundBluetoothCentralManager, willConnectTo peripheral: CBPeripheral) { + } + + // Tells the delegate that the central manager established a connection with a peripheral. + public func centralManager(_ centralManager: PlaygroundBluetoothCentralManager, didConnectTo peripheral: CBPeripheral) { + peripheral.delegate = self + // Make sure we get the discovery callbacks + peripheral.discoverServices([BLEService_UUID]) + blePeripheral = peripheral + } + + // Tells the delegate that the central manager failed to establish a connection with a peripheral. + public func centralManager(_ centralManager: PlaygroundBluetoothCentralManager, didFailToConnectTo peripheral: CBPeripheral, error: Error?) { + } + + // Tells the delegate that the central manager disconnected from a peripheral. + public func centralManager(_ centralManager: PlaygroundBluetoothCentralManager, didDisconnectFrom peripheral: CBPeripheral, error: Error?) { + blePeripheral = nil + } + + // Invoked when you discover the peripheral’s available services. + public func peripheral(_ peripheral: CBPeripheral, didDiscoverServices error: Error?) { + guard error == nil else { + print("Error discovering services: \(error!.localizedDescription)") + return + } + guard let services = peripheral.services else { + return + } + for service in services { + // Find the characteristic we want in services + peripheral.discoverCharacteristics([BLE_Characteristic_uuid_Tx, BLE_Characteristic_uuid_Rx], for: service) + } + } + + // Invoked when you discover the characteristics of a specified service. + public func peripheral(_ peripheral: CBPeripheral, didDiscoverCharacteristicsFor service: CBService, error: Error?) { + if ((error) != nil) { + print("Error discovering services: \(error!.localizedDescription)") + return + } + guard let characteristics = service.characteristics else { + return + } + + for characteristic in characteristics { + //looks for the right characteristic + + if characteristic.uuid.isEqual(BLE_Characteristic_uuid_Tx) { + txCharacteristic = characteristic + isConnected = true + onCharacteristicsDiscovered?(peripheral) + } + if characteristic.uuid.isEqual(BLE_Characteristic_uuid_Rx) { + peripheral.setNotifyValue(true, for: characteristic) + } + peripheral.discoverDescriptors(for: characteristic) + } + } + + // Invoked when you write data to a characteristic descriptor’s value. + public func peripheral(_ peripheral: CBPeripheral, didWriteValueFor characteristic: CBCharacteristic, error: Error?){ + guard error == nil else { + return + } + //onDataWritten?() + } + + // Callback on data arrival via notification on the characteristic + public func peripheral(_ peripheral: CBPeripheral, didUpdateValueFor characteristic: CBCharacteristic, error: Error?) { + guard error == nil else { + printLog(newString: "Error discovering services: \(error!.localizedDescription)") + return + } + if characteristic.uuid.isEqual(BLE_Characteristic_uuid_Rx) { + onCharacteristicsUpdated?(characteristic.value!) + } + } + + // The peripheral checks whether our subscribe/unsubscribe happened or not + public func peripheral(_ peripheral: CBPeripheral, didUpdateNotificationStateFor characteristic: CBCharacteristic, error: Error?) { + guard error == nil else { + // myPrint("Error changing notification state: \(error!.localizedDescription)") + return + } + if (characteristic.isNotifying) { + print("Notification began on \(characteristic)") + } else { + print("Notification stopped on (\(characteristic)) Disconnecting") + } + } + + // Sends our motion commands and duration time to bluetooth device using a write characteristic. + public func sendRcData(_ data: Data, _ duration: Int){ + blePeripheral!.writeValue(data, for: txCharacteristic!, type: CBCharacteristicWriteType.withResponse) + DispatchQueue.main.asyncAfter(deadline: .now() + .milliseconds(duration) ) { + self.onDataWritten?() + self.stopForward() + } + } + + // Write function + public func writeValue22(data: String){ + let data = (data as NSString).data(using: String.Encoding.utf8.rawValue) + if let blePeripheral = blePeripheral{ + if let txCharacteristic = txCharacteristic { + blePeripheral.writeValue(data!, for: txCharacteristic, type: CBCharacteristicWriteType.withResponse) + } + } + } + + func stringToData(string: String) { + let data = string.data(using: String.Encoding.utf8,allowLossyConversion: true) + sendDataWithCrc(data!) + } + + func sendDataWithCrc(_ data : Data) { + + let len = data.count + var dataBytes = [UInt8](repeating: 0, count: len) + var crc: UInt8 = 0 + (data as NSData).getBytes(&dataBytes, length: len) + + for i in dataBytes { //add all bytes + crc = crc &+ i + } + crc = ~crc //invert + + var dataWithChecksum = NSData(data: data) as Data + dataWithChecksum.append(&crc, count: 1) + sendCommand = "\(dataWithChecksum)" + } + + + // Mark:- Motion Functions + + + public func moveForward(){ + printLog(newString: "") + writeValue22(data: forwardString) + } + + public func stopForward(){ + // printLog(newString: "") + writeValue22(data: stopString) + } + + public func moveBack(){ + printLog(newString: "") + writeValue22(data: backString) + } + + public func stopBack(){ + // printLog(newString: "") + writeValue22(data: backStopString) + } + + public func turnRight(){ + printLog(newString: "") + writeValue22(data: rightString) + } + + public func stopRight(){ + // printLog(newString: "") + writeValue22(data: rightStop) + } + + public func turnLeft(){ + printLog(newString: "") + writeValue22(data: leftString) + } + + public func stopLeft(){ + // printLog(newString: "") + writeValue22(data: leftStop) + } + + func sendTouchEvent(_ tag: Int, isPressed: Bool) { + let message = "!B\(tag)\(isPressed ? "1" : "0")" + if let data = message.data(using: String.Encoding.utf8) { + sendDataWithCrc(data) + } + } +} + +extension RCBluetooth : ControllerPadViewControllerDelegate { + func onSendControllerPadButtonStatus(tag: Int, isPressed: Bool) { + sendTouchEvent(tag, isPressed: isPressed) + } +} + + diff --git a/Bluefruit/Swift Playground for Bluefruit.playgroundbook/Contents/Sources/RCCommand.swift b/Bluefruit/Swift Playground for Bluefruit.playgroundbook/Contents/Sources/RCCommand.swift new file mode 100644 index 0000000..0ed2480 --- /dev/null +++ b/Bluefruit/Swift Playground for Bluefruit.playgroundbook/Contents/Sources/RCCommand.swift @@ -0,0 +1,116 @@ +// +// RcCommand.swift +// +// +// Created by Trevor Beaton on 9/5/17. +// Copyright © 2017 Vanguard Logic LLC. All rights reserved. + + +import Foundation +import PlaygroundSupport + + +public var durationTimer: Int? + +public class RCCommand: NSObject { + + //:- Variables + + public var duration: Int = 750 + public var sensorType:String? + public var commandArray : [String] = [] + let rcBluetooth: RCBluetooth = RCBluetooth() + let commandManager: CommandManager = CommandManager() + + //:- Motion String Commands + + + let MOVE_BACKWARD : [Int8] = [ 0x21, 0x42, 0x36, 0x31, 0x35 ] //!B615 + let MOVE_FORWARD : [Int8] = [ 0x21, 0x42, 0x35, 0x31, 0x36 ] //!B516 + let TURN_RIGHT : [Int8] = [ 0x21, 0x42, 0x37, 0x31, 0x34 ] //!B714 + let TURN_LEFT : [Int8] = [ 0x21, 0x42, 0x38, 0x31, 0x33 ] //!B813 + let PAUSE : [Int8] = [ 0x21, 0x42, 0x35, 0x30, 0x37 ] //!B507 + + //:- Functions + + public func sendRobotDuration(_ command: PlaygroundValue){ + var testString = "\(command)" + let result = testString.trimmingCharacters(in: CharacterSet(charactersIn: "01234567890.").inverted) + duration = Int(result)! + printLog(newString: "Result: \(result)") + } + + public func durationReset(){ + printLog(newString: "Duration Has Been Reset to 300 milliseconds.") + duration = 750 + } + + public func sendRobotCommand(_ rcBluetooth: RCBluetooth, _ command: PlaygroundValue){ + switch command { + case let .string(text): + var fourBytes : [Int8] = [] + sensorType = nil + switch(text) { + case CommandType.COMMAND_PAUSE.rawValue: + fourBytes = PAUSE + // duration = 1 + case CommandType.COMMAND_MOVE_FORWARD.rawValue: + fourBytes = MOVE_FORWARD + // duration = 800 + printLog(newString: "Forward Duration: \(duration)") + break + case CommandType.COMMAND_MOVE_BACKWARD.rawValue: + fourBytes = MOVE_BACKWARD + // duration = 800 + printLog(newString: "Backward Duration: \(duration)") + break + case CommandType.COMMAND_TURN_RIGHT.rawValue: + fourBytes = TURN_LEFT + // duration = 600 + printLog(newString: "Right Duration: \(duration)") + break + case CommandType.COMMAND_TURN_LEFT.rawValue: + fourBytes = TURN_RIGHT + // duration = 600 + printLog(newString: "Left Duration: \(duration)") + default: + break + } + if sensorType == nil { + let data : Data = NSData(bytes: fourBytes, length: fourBytes.count*4) as Data + rcBluetooth.sendRcData(data, duration) + } + else{ + printLog(newString: "Data was not sent.") + } + break + default: + break + } + } + + func delay(_ delay:Double, closure:@escaping ()->()) { + DispatchQueue.main.asyncAfter( + deadline: DispatchTime.now() + Double(Int64(delay * Double(NSEC_PER_SEC))) / Double(NSEC_PER_SEC), execute: closure) + } + + public static func solutionChecker(_ commands:[PlaygroundValue], _ correctSolution:[CommandType])->Bool{ // Don't pass in robot connect command into this + var result:Bool = false + if commands.count == correctSolution.count{ + for index in 0...(commands.count-1) { + let command:PlaygroundValue = commands[index] + if case let .string(text) = command { + if !text.isEqual(correctSolution[index].rawValue){ + break + } + } + if index==(commands.count-1){ + result = true + } + } + } + return result + } + +} + diff --git a/Bluefruit/Swift Playground for Bluefruit.playgroundbook/Contents/Sources/RCView.swift b/Bluefruit/Swift Playground for Bluefruit.playgroundbook/Contents/Sources/RCView.swift new file mode 100644 index 0000000..c2d9486 --- /dev/null +++ b/Bluefruit/Swift Playground for Bluefruit.playgroundbook/Contents/Sources/RCView.swift @@ -0,0 +1,73 @@ +// +// RCView.swift +// +// +// Created by Trevor Beaton on 8/23/17. +// Copyright © 2017 Vanguard Logic LLC. All rights reserved. + + +import UIKit +import Foundation +import CoreBluetooth + + +public class RobotView:UIView{ + + var scrollView:UIScrollView! + var buttons = [UIButton]() + let label = UILabel(frame: CGRect(x: 0, y: 0, width: 50, height: 50)) + let icon = UIImageView(frame: CGRect(x: 0, y: 0, width: 50, height: 50)) + + var robotName:String = "" + + override init (frame : CGRect) { + super.init(frame : frame) + setupView() + } + + required public init?(coder aDecoder: NSCoder) { + super.init(coder: aDecoder) + } + + + func setupView(){ + icon.image = #imageLiteral(resourceName: "robotAvatar.png") + icon.translatesAutoresizingMaskIntoConstraints = false + self.addSubview(icon) + + label.numberOfLines = 0 + label.text = NSLocalizedString("Robots\nAvailable", comment: "") + label.textAlignment = NSTextAlignment.left; + label.textColor = #colorLiteral(red: 1, green: 1, blue: 1, alpha: 1) + label.font = UIFont.boldSystemFont(ofSize: 12) + label.translatesAutoresizingMaskIntoConstraints = false + self.addSubview(label) + + scrollView = UIScrollView(frame: CGRect(x: 0, y: 0, width: 200, height: 50)) + scrollView.backgroundColor = #colorLiteral(red: 0.9688462615, green: 0.9830557704, blue: 1, alpha: 0) + scrollView.contentSize = CGSize(width:200, height:50) + scrollView.translatesAutoresizingMaskIntoConstraints = false + self.addSubview(scrollView) + + } + + + + public func addDiscoveredRobot(_ name:String){ + print("addDiscoveredRobot: \(name)") + let button = UIButton(frame: CGRect(x:self.buttons.count*100 , y: 0, width: 150, height: 50)) + // button.backgroundColor = UIColor(patternImage: #imageLiteral(resourceName: "robotNameBg.png")) // # imageLiteral(resourceName: "robotNameBg.png") + button.setTitle(name, for: UIControlState.normal) + button.setTitleColor(#colorLiteral(red: 1, green: 1, blue: 1, alpha: 1), for: UIControlState.normal) + button.titleLabel!.font = UIFont.boldSystemFont(ofSize: 15) + button.titleLabel!.textAlignment = .left + button.titleLabel!.lineBreakMode = .byWordWrapping + button.titleLabel!.numberOfLines = 2 + scrollView.addSubview(button) + self.buttons.append(button) + } + + + + +} diff --git a/Bluefruit/Swift Playground for Bluefruit.playgroundbook/Contents/Sources/RCViewController.swift b/Bluefruit/Swift Playground for Bluefruit.playgroundbook/Contents/Sources/RCViewController.swift new file mode 100644 index 0000000..cffcd74 --- /dev/null +++ b/Bluefruit/Swift Playground for Bluefruit.playgroundbook/Contents/Sources/RCViewController.swift @@ -0,0 +1,523 @@ +// +// RCViewController.swift +// +// Copyright © 2017 Vanguard Logic LLC. All rights reserved. +// Created by Trevor Beaton on 8/22/17. +// +// + +import Foundation +import UIKit +import WebKit +import CoreBluetooth +import PlaygroundSupport +import PlaygroundBluetooth + +protocol ControllerPadViewControllerDelegate: class { + func onSendControllerPadButtonStatus(tag: Int, isPressed: Bool) +} + +var sendCommand : String? + +public class RCViewController: UIViewController, UITextViewDelegate { + //Data + //Page ID + var page:Int = 1 + //Data + var bleView: PlaygroundBluetoothConnectionView! + let bleViewDelegate = ConnectionViewDelegate() + var btViewConstraints = [NSLayoutConstraint]() + var isLandscape:Bool = true + var isPortraitMode:Bool = true + var rcBluetooth: RCBluetooth = RCBluetooth() + var rcCommand: RCCommand = RCCommand() + var commandsForAssessment:[PlaygroundValue] = [PlaygroundValue]() + private let buttonPrefix = "!B" + + + //Button Setup + public var commentText:UITextView! + var forwardButton : UIButton! + var backButton: UIButton! + var leftButton: UIButton! + var rightButton: UIButton! + var blePeripheral: CBPeripheral! + + // Data + weak var delegate: ControllerPadViewControllerDelegate? + + func updateTextView() { + let newLine = "\n" + var newText = commentText.text! + newText += printString + commentText.text = newText + } + + public required init(coder aDecoder: NSCoder) { + super.init(coder: aDecoder)! + } + + public override init(nibName nibNameOrNil: String?, bundle nibBundleOrNil: Bundle?) { + super.init(nibName: nibNameOrNil, bundle: nibBundleOrNil) + } + + public convenience init(_ page:Int = 1) { + self.init(nibName: nil, bundle: nil) + self.page = page + } + + public override func viewDidLoad() { + super.viewDidLoad() + + rcBluetooth.onDataWritten = onCommandCompleted + + + + UISetup() + + self.commentText.delegate = self + + NotificationCenter.default.addObserver(self, selector: #selector(updateTextView),name:NSNotification.Name(rawValue: "Print"), object: nil) + } + + public override func viewDidAppear(_ animated: Bool) { + super.viewDidAppear(animated) + } + + public override func viewDidLayoutSubviews() { + super.viewDidLayoutSubviews() + + } + + public override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator){ + super.viewWillTransition(to: size, with: coordinator) + // printLog(newString: "\(size)") + if(size.width>size.height){ + setupPortraitView(size) + } + else{ + setupLandscapeView(size) + } + } + + fileprivate func sendTouchEvent(_ tag: Int, isPressed: Bool) { + if let delegate = delegate { + delegate.onSendControllerPadButtonStatus(tag: tag, isPressed: isPressed) + } + } + + // MARK: - Actions + + public func scrollToBottom() { + let stringLength:Int = self.commentText.text.count + self.commentText.scrollRangeToVisible(NSMakeRange(stringLength-1, 0)) + } + + func onTouchDownForward(_ sender: UIButton) { + sendTouchEvent(sender.tag, isPressed: true) + let isPressed = true + rcBluetooth.moveForward() + scrollToBottom() + } + + func onTouchUpForward(_ sender: UIButton) { + let isPressed = false + sendTouchEvent(sender.tag, isPressed: true) + rcBluetooth.stopForward() + } + + func onTouchDownBack(_ sender: UIButton) { + sendTouchEvent(sender.tag, isPressed: true) + let isPressed = true + rcBluetooth.moveBack() + scrollToBottom() + } + + + func onTouchUpBack(_ sender: UIButton) { + sendTouchEvent(sender.tag, isPressed: true) + let isPressed = false + rcBluetooth.stopBack() + //scrollToBottom() + } + + + func onTouchDownRight(_ sender: UIButton) { + sendTouchEvent(sender.tag, isPressed: true) + let isPressed = true + rcBluetooth.turnRight() + scrollToBottom() + } + + + func onTouchUpRight(_ sender: UIButton) { + let isPressed = false + rcBluetooth.stopRight() + // scrollToBottom() + } + + + func onTouchDownLeft(_ sender: UIButton) { + sendTouchEvent(sender.tag, isPressed: true) + let isPressed = true + rcBluetooth.turnLeft() + scrollToBottom() + } + + + func onTouchUpLeft(_ sender: UIButton) { + let isPressed = false + rcBluetooth.stopLeft() + // scrollToBottom() + } + + func addCommandToAssessmentArray(_ command:PlaygroundValue){ + // printLog(newString: " addCommandToAssessmentArray: Phase #1 - Function is called") + + if(self.commandsForAssessment.count <= 30){ + self.commandsForAssessment.append(command) + //printLog(newString: " addCommandToAssessmentArray: Phase #2") + } + // printLog(newString: " addCommandToAssessmentArray: Phase #3") + } + + func processCommand(_ command:PlaygroundValue){ + // printLog(newString: #function) + rcCommand.sendRobotCommand(rcBluetooth, command) + } + + func processCommandForDuration(_ item:PlaygroundValue){ + // printLog(newString: #function) + rcCommand.sendRobotDuration(item) + } + + + func onCommandCompleted(){ + // printLog(newString: "Command Completed") + self.sendMessage(.string(Constants.COMMAND_FINISHED)) + } + + func onCommandCompleted2(){ + commentText.text = "Test" + } + + func UISetup() { + + + isLandscape = (self.view.frame.width > self.view.frame.height) + + //Connecting Bluetooth View + bleView = PlaygroundBluetoothConnectionView(centralManager: rcBluetooth.centralManager!) + bleView.delegate = bleViewDelegate + bleView.dataSource = bleViewDelegate + DispatchQueue.main.asyncAfter(deadline: .now() + .milliseconds(1000)) { + self.rcBluetooth.centralManager!.connectToLastConnectedPeripheral() + } + self.view.addSubview(bleView) + + + // Setup debug log + commentText = UITextView(frame: CGRect(x: self.view.frame.width*5/100, y: self.view.frame.height*68/100, width: self.view.frame.width*89/200, height: self.view.frame.height*13/100)) + commentText.isEditable = false + commentText.backgroundColor = #colorLiteral(red: 0.2549019754, green: 0.2745098174, blue: 0.3019607961, alpha: 1) + commentText.textColor = #colorLiteral(red: 0.9254902005, green: 0.2352941185, blue: 0.1019607857, alpha: 1) + commentText.font = UIFont.init(name: "Avenir", size: 15) + commentText.textAlignment = .left + commentText.textContainer.lineBreakMode = .byWordWrapping + commentText.layer.borderWidth = 0 + commentText.layer.cornerRadius = 18 + + view.addSubview(commentText) + + + forwardButton = UIButton(frame: CGRect(x: 320, y: 70, width: 83, height: 60)) + forwardButton.setTitle("Forward", for: .normal) + forwardButton.setTitleColor(UIColor.white, for: .normal) + forwardButton.backgroundColor = #colorLiteral(red: 0.1764705926, green: 0.4980392158, blue: 0.7568627596, alpha: 1) + + // Rounded button + + forwardButton.layer.borderWidth = 0 + forwardButton.layer.cornerRadius = 18 + forwardButton.tag = 5 + + + + forwardButton.addTarget(self, action: #selector(onTouchDownForward(_:)), for: .touchDown) + + forwardButton.addTarget(self, action: #selector(onTouchUpForward(_:)), for: .touchUpInside) + + forwardButton.addTarget(self, action: #selector(onTouchUpForward(_:)), for: .touchDragExit) + + forwardButton.addTarget(self, action: #selector(onTouchUpForward(_:)), for: .touchCancel) + + + view.addSubview(forwardButton) + + + backButton = UIButton(frame: CGRect(x: 320, y: 210, width: 83, height: 60)) + backButton.setTitle("Back", for: .normal) + backButton.setTitleColor(UIColor.white, for: .normal) + backButton.backgroundColor = #colorLiteral(red: 0.1764705926, green: 0.4980392158, blue: 0.7568627596, alpha: 1) + + // Rounded button + backButton.layer.borderWidth = 0 + backButton.layer.cornerRadius = 18 + backButton.tag = 6 + + + backButton.addTarget(self, action: #selector(onTouchDownBack(_:)), for: .touchDown) + + backButton.addTarget(self, action: #selector(onTouchUpBack(_:)), for: .touchUpInside) + + backButton.addTarget(self, action: #selector(onTouchUpBack(_:)), for: .touchDragExit) + + backButton.addTarget(self, action: #selector(onTouchUpBack(_:)), for: .touchCancel) + view.addSubview(backButton) +// +// + + leftButton = UIButton(frame: CGRect(x: 270, y: 140, width: 83, height: 60)) + leftButton.setTitle("Left", for: .normal) + leftButton.setTitleColor(UIColor.white, for: .normal) + leftButton.backgroundColor = #colorLiteral(red: 0.1764705926, green: 0.4980392158, blue: 0.7568627596, alpha: 1) + leftButton.tag = 7 + // Rounded button + leftButton.layer.borderWidth = 0 + leftButton.layer.cornerRadius = 18 + leftButton.addTarget(self, action: #selector(onTouchDownLeft(_:)), for: .touchDown) + + leftButton.addTarget(self, action: #selector(onTouchUpLeft(_:)), for: .touchUpInside) + + leftButton.addTarget(self, action: #selector(onTouchUpLeft(_:)), for: .touchDragExit) + + leftButton.addTarget(self, action: #selector(onTouchUpLeft(_:)), for: .touchCancel) + view.addSubview(leftButton) + + + + rightButton = UIButton(frame: CGRect(x: 375, y: 140, width: 83, height: 60)) + rightButton.setTitle("Right", for: .normal) + rightButton.setTitleColor(UIColor.white, for: .normal) + rightButton.backgroundColor = #colorLiteral(red: 0.1764705926, green: 0.4980392158, blue: 0.7568627596, alpha: 1) + // Rounded button + rightButton.layer.borderWidth = 0 + rightButton.layer.cornerRadius = 18 + rightButton.tag = 8 + rightButton.addTarget(self, action: #selector(onTouchDownRight(_:)), for: .touchDown) + + rightButton.addTarget(self, action: #selector(onTouchUpRight(_:)), for: .touchUpInside) + + rightButton.addTarget(self, action: #selector(onTouchUpRight(_:)), for: .touchDragExit) + + rightButton.addTarget(self, action: #selector(onTouchUpRight(_:)), for: .touchCancel) + + + view.addSubview(rightButton) + + + if(isLandscape){ + setupLandscapeView(CGSize(width: self.view.frame.width/2, height: self.view.frame.height)) + } + else{ + setupPortraitView(CGSize(width: self.view.frame.width, height: self.view.frame.height/2)) + } + + } + + //- LANDSCAPE ORIENTATION + func setupLandscapeView(_ size:CGSize){ + isLandscape = true + + NSLayoutConstraint.deactivate(btViewConstraints) + btViewConstraints.removeAll() + btViewConstraints.append(bleView.topAnchor.constraint(equalTo: self.view.topAnchor, constant: 20)) + btViewConstraints.append(bleView.leadingAnchor.constraint(equalTo: self.view.leadingAnchor, constant: 20)) + NSLayoutConstraint.activate(btViewConstraints) + + //- Comment Log mark + scrollToBottom() + + commentText.frame = CGRect(x: 12, y: 390, width: 490, height: 300) + commentText.font = UIFont.init(name: "Avenir Next", size: 17) + + // scrollToBottom() + //-Button Frame Update For Landscape Mode + + forwardButton.frame = CGRect(x: 320, y: 70, width: 83, height: 60) + backButton.frame = CGRect(x: 320, y: 210, width: 83, height: 60) + leftButton.frame = CGRect(x: 270, y: 140, width: 83, height: 60) + rightButton.frame = CGRect(x: 375, y: 140, width: 83, height: 60) + } + + func setupPortraitView(_ size:CGSize){ + isLandscape = false + + NSLayoutConstraint.deactivate(btViewConstraints) + btViewConstraints.removeAll() + btViewConstraints.append(bleView.topAnchor.constraint(equalTo: self.view.topAnchor, constant: 75)) + btViewConstraints.append(bleView.leadingAnchor.constraint(equalTo: self.view.leadingAnchor, constant: 20)) + NSLayoutConstraint.activate(btViewConstraints) + + + scrollToBottom() + //- Comment Log + + commentText.frame = CGRect(x: 190, y: 300, width: 400, height: 140) + commentText.font = UIFont.init(name: "Avenir Next", size: 17) + + + // scrollToBottom() + //- Button Frame Update For Portrait Mode + + forwardButton.frame = CGRect(x: 570, y: 85, width: 83, height: 60) + backButton.frame = CGRect(x: 570, y: 215, width: 83, height: 60) + leftButton.frame = CGRect(x: 520, y: 150, width: 83, height: 60) + rightButton.frame = CGRect(x: 620, y: 150, width: 83, height: 60) + } + + + func exitProgram(){ + // All commands executed + let message: PlaygroundValue = .array(commandsForAssessment) + sendMessage(message) + commandsForAssessment.removeAll() + } + + class ConnectionViewDelegate: PlaygroundBluetoothConnectionViewDelegate, PlaygroundBluetoothConnectionViewDataSource { + + //PlaygroundBluetoothConnectionViewDataSource + public func connectionView(_ connectionView: PlaygroundBluetoothConnectionView, itemForPeripheral peripheral: CBPeripheral, withAdvertisementData advertisementData: [String : Any]?) -> PlaygroundBluetoothConnectionView.Item { + // Displays UI elements for connectivity + let name = peripheral.name ?? NSLocalizedString("Unknown Device", comment: "") + let icon = UIImage(imageLiteralResourceName:"Images/adafruit_logo_small copy.png") + let issueIcon = icon + return PlaygroundBluetoothConnectionView.Item(name: name, icon: icon, issueIcon: issueIcon, firmwareStatus: nil, batteryLevel: nil) + } + + // MARK: PlaygroundBluetoothConnectionView Delegate + public func connectionView(_ connectionView: PlaygroundBluetoothConnectionView, shouldDisplayDiscovered peripheral: CBPeripheral, withAdvertisementData advertisementData: [String : Any]?, rssi: Double) -> Bool { + // Filter out peripheral items (optional) + return true + } + + public func connectionView(_ connectionView: PlaygroundBluetoothConnectionView, titleFor state: PlaygroundBluetoothConnectionView.State) -> String { + // Provide a localized title for the given state of the connection view. + switch state { + case .noConnection: + return NSLocalizedString("Connect RC", comment: "") + case .connecting: + return NSLocalizedString("Connecting to RC", comment: "") + case .searchingForPeripherals: + return NSLocalizedString("Searching for RC", comment: "") + case .selectingPeripherals: + return NSLocalizedString("Select your RC", comment: "") + case .connectedPeripheralFirmwareOutOfDate: + return NSLocalizedString("Connect to a Different RC", comment: "") + } + } + + public func connectionView(_ connectionView: PlaygroundBluetoothConnectionView, firmwareUpdateInstructionsFor peripheral: CBPeripheral) -> String { + // Provide firmware update instructions. + return "Firmware update instructions here." + } + + func connectionView(_ connectionView: PlaygroundBluetoothConnectionView, + willDisconnectFrom peripheral: CBPeripheral) { + } + + func connectionView(_ connectionView: PlaygroundBluetoothConnectionView, + shouldConnectTo peripheral: CBPeripheral, + withAdvertisementData advertisementData: [String: Any]?, + rssi: Double) -> Bool { + return true + } + } +} + + +extension RCViewController: PlaygroundLiveViewMessageHandler { + + public func liveViewMessageConnectionOpened(){ + // printLog(newString: " ") + + } + + public func liveViewMessageConnectionClosed() { + commandsForAssessment.removeAll() + //PlaygroundPage.current.finishExecution() + } + + //Recieve message from Constant.swift + public func receive(_ message: PlaygroundValue) { + printLog(newString: #function) + + if case let .string(command) = message { + if command.isEqual(CommandType.COMMAND_EXIT_PROGRAM.rawValue){ + exitProgram() + } + + if rcBluetooth.isConnected { + // printLog(newString: "Bluetooth is Online.") + addCommandToAssessmentArray(message) + processCommand(message) + + } + + else{ // Connection not ready + printLog(newString: "Connect To RC Before Sending Commands.") + } + } + + else if case let .dictionary(dict) = message { // Connect to robot + printLog(newString: "Send message; Command String attempt made") + processCommand(message) + addCommandToAssessmentArray(message) + } + + else if case let .boolean(result) = message { // Program Results + // programStateImage.stopAnimating() + //isShowingResult = true +// if result{ +// myPrint("Receive result from Constants.swift: feedback_success") +// setCommandAnimationAsync(CommandType.FEEDBACK_SUCCESS) +// if robotConnection.isConnected { +// robotCommand.sendRobotCommand(robotConnection, PlaygroundValue.string(CommandType.COMMAND_SOUND_AWESOME.rawValue)) +// } +// } +// else{ +// myPrint("Receive result from Constants.swift: feedback_fail") +// setCommandAnimationAsync(CommandType.FEEDBACK_FAIL) +// if robotConnection.isConnected { +// robotCommand.sendRobotCommand(robotConnection, PlaygroundValue.string(CommandType.COMMAND_SOUND_WHA.rawValue)) +// } +// } + sendMessage(.string(Constants.PROGRAM_FINISHED)) + } + + else if case let item = message { + + if rcBluetooth.isConnected { + printLog(newString: "Integer Sent: \(message)") + addCommandToAssessmentArray(message) + processCommandForDuration(message) + // printLog(newString: "Array count \(commandsForAssessment.count)") + // printLog(newString: "First in the arrray is... \(commandsForAssessment[0])") + + } else{ // Connection not ready + printLog(newString: "Send message; (PROGRAM_FINISHED) attempt made") + sendMessage(.string(Constants.PROGRAM_FINISHED)) + } + + } + +} + + public func sendMessage(_ message: PlaygroundValue) { + // printLog(newString: "") + rcCommand.durationReset() + send(message) + } +} + + diff --git a/Bluefruit/Swift Playground for Bluefruit.playgroundbook/Contents/Sources/UserProcessDelegate.swift b/Bluefruit/Swift Playground for Bluefruit.playgroundbook/Contents/Sources/UserProcessDelegate.swift new file mode 100644 index 0000000..c09a8b1 --- /dev/null +++ b/Bluefruit/Swift Playground for Bluefruit.playgroundbook/Contents/Sources/UserProcessDelegate.swift @@ -0,0 +1,70 @@ +// +// UserProcessDelegate.swift +// +// +// Created by Trevor Beaton on 9/20/17. +// Copyright © 2017 Vanguard Logic LLC. All rights reserved. + + +import Foundation +import PlaygroundSupport + +public class UserProcessDelegate: PlaygroundRemoteLiveViewProxyDelegate { + + public var pauseHandler: CommandPauseDelegate? + + public init(pauseHandler: CommandPauseDelegate?) { + self.pauseHandler = pauseHandler + } + + public var onAssessment:((PlaygroundValue)->Bool)? + + public init() { + + } + + //On live view connection closed + public func remoteLiveViewProxyConnectionClosed(_ remoteLiveViewProxy: PlaygroundRemoteLiveViewProxy) { + // Kill user process if LiveView process closed. + //PlaygroundPage.current.finishExecution() + } + + //Receive message from live view + public func remoteLiveViewProxy(_ remoteLiveViewProxy: PlaygroundRemoteLiveViewProxy, received message: PlaygroundValue) { + + if case let .string(text) = message { + if text.isEqual(Constants.COMMAND_FINISHED){ + // Indicate that the handler is ready for more commands. + pauseHandler?.isReadyForMoreCommands = true + // printLog(newString: "UserProcess-remoteLiveViewProxy-TEST") + } + } + + if case let item = message { + + pauseHandler?.isReadyForMoreCommands = true + // printLog(newString: "UserProcess-remoteLiveViewProxy-TEST") + } + + + + // Update Hints and Assessments + if case let .array(commands) = message { + let result:Bool = (onAssessment?(message))! + //Send Result to live view + let resultValue: PlaygroundValue = .boolean(result) + remoteLiveViewProxy.send(resultValue) + } + // Kill user process if LiveView process closed. + if case let .string(text) = message { + if text.isEqual(Constants.PROGRAM_FINISHED){ + PlaygroundPage.current.finishExecution() + } + } + } +} + + + + + diff --git a/Bluefruit/Swift Playground for Bluefruit.playgroundbook/Edits/KeyValueStore.plist b/Bluefruit/Swift Playground for Bluefruit.playgroundbook/Edits/KeyValueStore.plist new file mode 100644 index 0000000..0e6221a Binary files /dev/null and b/Bluefruit/Swift Playground for Bluefruit.playgroundbook/Edits/KeyValueStore.plist differ diff --git a/Bluefruit/Swift Playground for Bluefruit.playgroundbook/Edits/UserEdits.diffpack/Chapters/Chapter1.playgroundchapter/Pages/Page1.playgroundpage/Contents.swift.delta b/Bluefruit/Swift Playground for Bluefruit.playgroundbook/Edits/UserEdits.diffpack/Chapters/Chapter1.playgroundchapter/Pages/Page1.playgroundpage/Contents.swift.delta new file mode 100644 index 0000000..2541afc --- /dev/null +++ b/Bluefruit/Swift Playground for Bluefruit.playgroundbook/Edits/UserEdits.diffpack/Chapters/Chapter1.playgroundchapter/Pages/Page1.playgroundpage/Contents.swift.delta @@ -0,0 +1,21 @@ + + + + + Diff + + + ModifiedContent + 3 + ModifiedRange + {1274, 1} + OriginalContent + + OriginalRange + {1274, 0} + + + File + Chapters/Chapter1.playgroundchapter/Pages/Page1.playgroundpage/Contents.swift + + diff --git a/Bluefruit/Swift Playground for Bluefruit.playgroundbook/Edits/UserEdits.diffpack/Manifest.plist b/Bluefruit/Swift Playground for Bluefruit.playgroundbook/Edits/UserEdits.diffpack/Manifest.plist new file mode 100644 index 0000000..e6b699c --- /dev/null +++ b/Bluefruit/Swift Playground for Bluefruit.playgroundbook/Edits/UserEdits.diffpack/Manifest.plist @@ -0,0 +1,34 @@ + + + + + BaseVersion + 1.0 + DiffPackType + UserEdit + DocumentType + PlaygroundBook + Name + com.razeware.empty + UpdateVersion + 1.0 + Updates + + Added + + Modified + + + Diff + Chapters/Chapter1.playgroundchapter/Pages/Page1.playgroundpage/Contents.swift.delta + File + Chapters/Chapter1.playgroundchapter/Pages/Page1.playgroundpage/Contents.swift + + + Removed + + Replaced + + + + diff --git a/Bluefruit/banner.png b/Bluefruit/banner.png new file mode 100644 index 0000000..5553529 Binary files /dev/null and b/Bluefruit/banner.png differ diff --git a/Bluefruit/preview-1.png b/Bluefruit/preview-1.png new file mode 100644 index 0000000..8ef514a Binary files /dev/null and b/Bluefruit/preview-1.png differ diff --git a/Bluefruit/thumbnail.png b/Bluefruit/thumbnail.png new file mode 100644 index 0000000..e379d5e Binary files /dev/null and b/Bluefruit/thumbnail.png differ diff --git a/feed.json b/feed.json new file mode 100644 index 0000000..c096a6f --- /dev/null +++ b/feed.json @@ -0,0 +1,41 @@ +{ + "documents": [ + { + "previewImageURLs": [], + "bannerImageURL": "Bluefruit/banner.png", + "thumbnailURL": "Bluefruit/thumbnail.png", + "subtitle": "Learn Swift with Adafruit", + "description": "Learn Swift with Adafruit", + "publishedDate": "2017-05-29T12:00:00+00:00", + "url": "Bluefruit/Swift-Playground-for-Bluefruit.playgroundbook.zip", + "additionalInformation": [ + { + "name": "Publisher:", + "value": "Adafruit Industries" + }, + { + "name": "Version:", + "value": "1.0" + }, + { + "type": "date", + "name": "Released:", + "value": "2017-05-29T12:00:00+00:00" + }, + { + "name": "Languages:", + "value": "English" + } + ], + "title": "Adafruit Bluefruit", + "contentVersion": "1.0", + "lastUpdatedDate": "2017-05-29T12:00:00+00:00", + "contentIdentifier": "com.adafruit.swiftplaygrounds.bluefruit" + } + ], + "publisherName": "Adafruit Industries", + "title": "Adafruit", + "formatVersion": "1.0", + "feedIdentifier": "com.adafruit.swiftplaygrounds", + "contactURL": "support.adafruit.com" +} \ No newline at end of file