Adafruit Subscription
This commit is contained in:
parent
00eb36497c
commit
c3b5ab6465
30 changed files with 1643 additions and 0 deletions
Binary file not shown.
|
|
@ -0,0 +1,14 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>Version</key>
|
||||
<string>1.0</string>
|
||||
<key>Name</key>
|
||||
<string>Chapter 1</string>
|
||||
<key>Pages</key>
|
||||
<array>
|
||||
<string>Page1.playgroundpage</string>
|
||||
</array>
|
||||
</dict>
|
||||
</plist>
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -0,0 +1,14 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>Name</key>
|
||||
<string>Page 1</string>
|
||||
<key>LiveViewMode</key>
|
||||
<string>VisibleByDefault</string>
|
||||
<key>LiveViewEdgeToEdge</key>
|
||||
<true/>
|
||||
<key>PlaygroundLoggingMode</key>
|
||||
<string>Off</string>
|
||||
</dict>
|
||||
</plist>
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>Hints</key>
|
||||
<array/>
|
||||
</dict>
|
||||
</plist>
|
||||
|
|
@ -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()
|
||||
}
|
||||
}
|
||||
|
|
@ -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
|
||||
}
|
||||
|
|
@ -0,0 +1,26 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>SwiftVersion</key>
|
||||
<string>3.0</string>
|
||||
<key>ImageReference</key>
|
||||
<string>icon.png</string>
|
||||
<key>Version</key>
|
||||
<string>3.0</string>
|
||||
<key>ContentVersion</key>
|
||||
<string>1.0</string>
|
||||
<key>Name</key>
|
||||
<string>Empty</string>
|
||||
<key>ContentIdentifier</key>
|
||||
<string>com.example.adafruitswiftplayground</string>
|
||||
<key>DeploymentTarget</key>
|
||||
<string>ios10.0</string>
|
||||
<key>DevelopmentRegion</key>
|
||||
<string>en</string>
|
||||
<key>Chapters</key>
|
||||
<array>
|
||||
<string>Chapter1.playgroundchapter</string>
|
||||
</array>
|
||||
</dict>
|
||||
</plist>
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 19 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 16 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 66 KiB |
|
|
@ -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")
|
||||
}
|
||||
}
|
||||
|
|
@ -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
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
|
@ -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: "<Forward>")
|
||||
writeValue22(data: forwardString)
|
||||
}
|
||||
|
||||
public func stopForward(){
|
||||
// printLog(newString: "<Forward Stopped>")
|
||||
writeValue22(data: stopString)
|
||||
}
|
||||
|
||||
public func moveBack(){
|
||||
printLog(newString: "<Back>")
|
||||
writeValue22(data: backString)
|
||||
}
|
||||
|
||||
public func stopBack(){
|
||||
// printLog(newString: "<Back Stopped>")
|
||||
writeValue22(data: backStopString)
|
||||
}
|
||||
|
||||
public func turnRight(){
|
||||
printLog(newString: "<Turning Right>")
|
||||
writeValue22(data: rightString)
|
||||
}
|
||||
|
||||
public func stopRight(){
|
||||
// printLog(newString: "<Right Stopped>")
|
||||
writeValue22(data: rightStop)
|
||||
}
|
||||
|
||||
public func turnLeft(){
|
||||
printLog(newString: "<Turning Left>")
|
||||
writeValue22(data: leftString)
|
||||
}
|
||||
|
||||
public func stopLeft(){
|
||||
// printLog(newString: "<Left Stopped>")
|
||||
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)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -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
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
|
@ -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)
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
|
@ -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: "<Live View Message Connection Made> ")
|
||||
|
||||
}
|
||||
|
||||
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: "<Send message to Contants.swift>")
|
||||
rcCommand.durationReset()
|
||||
send(message)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -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()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
Binary file not shown.
|
|
@ -0,0 +1,21 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>Diff</key>
|
||||
<array>
|
||||
<dict>
|
||||
<key>ModifiedContent</key>
|
||||
<string>3</string>
|
||||
<key>ModifiedRange</key>
|
||||
<string>{1274, 1}</string>
|
||||
<key>OriginalContent</key>
|
||||
<string></string>
|
||||
<key>OriginalRange</key>
|
||||
<string>{1274, 0}</string>
|
||||
</dict>
|
||||
</array>
|
||||
<key>File</key>
|
||||
<string>Chapters/Chapter1.playgroundchapter/Pages/Page1.playgroundpage/Contents.swift</string>
|
||||
</dict>
|
||||
</plist>
|
||||
|
|
@ -0,0 +1,34 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>BaseVersion</key>
|
||||
<string>1.0</string>
|
||||
<key>DiffPackType</key>
|
||||
<string>UserEdit</string>
|
||||
<key>DocumentType</key>
|
||||
<string>PlaygroundBook</string>
|
||||
<key>Name</key>
|
||||
<string>com.razeware.empty</string>
|
||||
<key>UpdateVersion</key>
|
||||
<string>1.0</string>
|
||||
<key>Updates</key>
|
||||
<dict>
|
||||
<key>Added</key>
|
||||
<array/>
|
||||
<key>Modified</key>
|
||||
<array>
|
||||
<dict>
|
||||
<key>Diff</key>
|
||||
<string>Chapters/Chapter1.playgroundchapter/Pages/Page1.playgroundpage/Contents.swift.delta</string>
|
||||
<key>File</key>
|
||||
<string>Chapters/Chapter1.playgroundchapter/Pages/Page1.playgroundpage/Contents.swift</string>
|
||||
</dict>
|
||||
</array>
|
||||
<key>Removed</key>
|
||||
<array/>
|
||||
<key>Replaced</key>
|
||||
<array/>
|
||||
</dict>
|
||||
</dict>
|
||||
</plist>
|
||||
BIN
Bluefruit/banner.png
Normal file
BIN
Bluefruit/banner.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 110 KiB |
BIN
Bluefruit/preview-1.png
Normal file
BIN
Bluefruit/preview-1.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 786 KiB |
BIN
Bluefruit/thumbnail.png
Normal file
BIN
Bluefruit/thumbnail.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 32 KiB |
41
feed.json
Normal file
41
feed.json
Normal file
|
|
@ -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"
|
||||
}
|
||||
Loading…
Reference in a new issue