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