Now that we have completely tested PRoC and PSoC4200M firmware the next step is to build an iOS App called Example 10.  The Xcode project is available in the Xcode directory in the project directory at github.com/iotexpert/cy8ckit-021/

Ill try to build this App to be as simple as possible.   Here is what the (single) screen looks like in three different state (nothing pressed, button0 pressed, led0 on):

IMG_0027     IMG_0028    IMG_0029

This App is built up with four files

  1. ViewController.swift: an object which controls the screen (button clicks)
  2. BluetoothNeighborhood.swift: an object which controls the Bluetooth in the phone and represents the CY8CKIT021 board (the Model)
  3. globals.swift: Defines the NSNotifications that can be sent
  4. Main.storyboard: The screen layout

The code will do the following:

  1. When the ViewController (VC) starts it will instantiate a BluetoothNeighborhood (BN) object
  2. VC: Tell the BN to start the bluetooth central in the phone
  3. BN: Scan for BLE Peripherals that are advertising the CY8CKIT-021 Service UUID
  4. BN: When it hears the peripheral with the correct UUID then connect
  5. BN: Read the state of the button0 and led0 then send an NSNotification
  6. BN: Turn on the notify for button0 (to cause the PRoC to send an NSNotification when there are changes)
  7. VC: update the screen when it gets the NSNotification from (5)
  8. VC: If the LED0 switch on the screen is switched then tell the BN to write to the PRoC
  9. BN: If the button0 is changed then send an NSNotification to the VC
  10. VC: If there is an NSNotification (9) of a button0 change then update the screen
  11. VC: If the bootloader button is pressed tell the BN to write the bootloader characteristic
  12. BN: If there is a disconnect event then send an NSNotification to the VC to disable the GUI elements and start scanning again (step 3)

ViewController.swift

The viewDidLoad method runs when the Apps starts and loads the first screen.  This method

  1. Initializes the BluetoothNeighborhood object
  2. Tell it to start the bluetooth scanning
  3. Disables the UI buttons
  4. Then registers with the NSNotificationCenter that it wants to hear the 4 possible messages that the model can send
    1. Connect: enable the buttons
    2. Disconnect: disable the buttons
    3. UpdateLED: reflect the current state of the LED on the screen
    4. UpdateButton: reflect the current state of the button on the screen

 

//
//  ViewController.swift
//  Example10
//
// Project: Example10
// Kit: CY8CKIT-021 Sheild
// Baseboard: CY8CKit-44 PSoC4M
//
//  This file contains the viewcontroller for the single view application.
//  Basically when it loads you startup and connect to the bleboard
//  then display the state of things... or let the user flip the switch
//
 
import UIKit
 
class ViewController: UIViewController {
 
var bleLand : BlueToothNeighborhood!
 
override func viewDidLoad() {
super.viewDidLoad()
 
// bleLand-BlueToothNeighborhood is the model.  It is capable of finding
// a CY8CKIT021 and connecting to it. It can also read/write etc
bleLand = BlueToothNeighborhood()
bleLand.startUpCentralManager()
 
// start with the switch disabled.  it will turn on once there is a connection
led0switch.userInteractionEnabled = false
bootLoaderButton.userInteractionEnabled = false
 
 
// The global structure CY8CKITNotifications defines the different notificateions
// that can come from the bleLand model.  Basically a connection/disconnection or
// and update of the Led0 or Button0 State
 
// If you get a complete connection then turn on the buttons to start working
NSNotificationCenter.defaultCenter().addObserverForName(CY8CKIT021Notifications.ConnectionComplete, object: nil, queue: NSOperationQueue.mainQueue()) { _ in
self.led0switch.userInteractionEnabled = true
self.bootLoaderButton.userInteractionEnabled = true
}
 
// if you get disconnected then turn off the buttons
NSNotificationCenter.defaultCenter().addObserverForName(CY8CKIT021Notifications.DisconnectedDevice, object: nil, queue: NSOperationQueue.mainQueue()) { _ in
self.led0switch.userInteractionEnabled = false
self.bootLoaderButton.userInteractionEnabled = false
}
 
// The we got feedback from the model about the state of the button0
NSNotificationCenter.defaultCenter().addObserverForName(CY8CKIT021Notifications.UpdatedButton0, object: nil, queue: NSOperationQueue.mainQueue()) { _ in self.button0.selected = self.bleLand.button0State }
 
// The we got feedback from the model about the state of the led0
NSNotificationCenter.defaultCenter().addObserverForName(CY8CKIT021Notifications.UpdateLed0, object: nil, queue: NSOperationQueue.mainQueue()) { _ in self.updateLed0() }
 
}

The GUI part of the code just acts when the button/switch is pressed to send messages to the model.  These methods are linked to the GUI elements on the main.storyboard

    // This function grabs the current button0 state from the model and sets the button
// to indicate it is either being pressed or not
func updateButton0()
{
self.button0.selected = self.bleLand.button0State
}
 
// This functiong rabs the current led0 state from the model and then flips the 
// switch the right way
func updateLed0()
{
led0switch.on = bleLand.led0State
}
 
@IBOutlet weak var button0: UIButton!
@IBOutlet weak var led0switch: UISwitch!
 
// When the user flips the switch you need to write the updated value to the model
@IBAction func led0SwitchAction(sender: UISwitch) {
 
bleLand.writeLed0Characteristic(sender.on)
}
 
// If the user presses the bootload button then send the bootload command
// this will cause and immediate BLE disconnect... etc
@IBOutlet weak var bootLoaderButton: UIButton!
@IBAction func startBootLoader(sender: AnyObject) {
bleLand.startBootloader()
}

BluetoothNeighborhood

This file contains all of the code that interacts with the CY8CKIT021 board.  The first block of code defines a structure with a list of the UUIDs that we need to search for.  These are defined in the Bluetooth Component Customizer from the PRoC firmware.

// BlueToothNeighborhood.swift
//
// Project: Example10
// Kit: CY8CKIT-021 Sheild
// Baseboard: CY8CKit-44 PSoC4M
//
// This file contains the model for the CY8CKIT021 board with 1 LED0 and 1 Button 0
//
 
import CoreBluetooth
 
 
// This structure conatains the UUIDS for the services and characteristics on the board
// it MUST match what you defined in the creator BLE Configuration Wizard
private struct BLEParameters {
static let CY8CKIT021Service = CBUUID(string: "00000000-0000-1000-8000-00805F9B3400")
static let bootloadCharactersticUUID = CBUUID(string:"00000000-0000-1000-8000-00805F9B3401")
static let ledCharactersticUUID = CBUUID(string:"00000000-0000-1000-8000-00805F9B3402")
static let buttonCharactersticUUID = CBUUID(string:"00000000-0000-1000-8000-00805F9B3404")
 
}

The next block of code

// The model for the board
// The BlueToothNeighborhood has BOTH the board model and the Bluetooth model.  This
// makes the code slightly simpler to explain but is a bit weird architectururally
class BlueToothNeighborhood: NSObject, CBCentralManagerDelegate, CBPeripheralDelegate  {
 
private var centralManager : CBCentralManager!
private var CY8CKIT021Board : CBPeripheral?
private var CY8CKIT021Service : CBService!
private var led0Characteristic : CBCharacteristic!
private var button0Characteristic : CBCharacteristic!
private var bootloadCharacteristic : CBCharacteristic!
 
// This function is called by the main view controller to get things going
func startUpCentralManager() {
centralManager = CBCentralManager(delegate: self, queue: nil)
}
 
// This is the bluetooth delegate function
@objc func centralManagerDidUpdateState(central: CBCentralManager) {
switch (central.state) {
case .PoweredOff: break
case .PoweredOn:
print("Bluetooth is on - Starting scan")
// start scanning for a device that we can talk to
centralManager.scanForPeripheralsWithServices([BLEParameters.CY8CKIT021Service], options: [CBCentralManagerScanOptionAllowDuplicatesKey:false])
 
case .Resetting: break
case .Unauthorized: break
case .Unknown:break
case .Unsupported:break
}
}
 
// This delegate function is called by the bluetooth when it finds a device
// that matches our UUID that we told it when we started the scan
func centralManager(central: CBCentralManager, didDiscoverPeripheral peripheral: CBPeripheral, advertisementData: [String : AnyObject], RSSI: NSNumber)
{
// if you already are connected to a device ignore this one
if CY8CKIT021Board == nil {
print("Found a new Periphal advertising CY8CKIT021 Service")
CY8CKIT021Board = peripheral
centralManager.stopScan()
centralManager.connectPeripheral(CY8CKIT021Board!, options: nil)
}
}
 
// This delegate is called when a device connection is complete
func centralManager(central: CBCentralManager, didConnectPeripheral peripheral: CBPeripheral) {
print("Connection complete \(CY8CKIT021Board) \(peripheral)")
CY8CKIT021Board!.delegate = self
CY8CKIT021Board!.discoverServices(nil)
}
 
// This delegate is called after the service discovery is complete
func peripheral(peripheral: CBPeripheral, didDiscoverServices error: NSError?) {
print("discovered services")
for service in peripheral.services! {
print("Found service \(service)")
if service.UUID == BLEParameters.CY8CKIT021Service {
CY8CKIT021Service = service // as! CBService
}
}
CY8CKIT021Board!.discoverCharacteristics(nil, forService: CY8CKIT021Service)
}
 
 
// This delegate is called when the characteristic discovery is complete
func peripheral(peripheral: CBPeripheral, didDiscoverCharacteristicsForService service: CBService, error: NSError?) {
for characteristic in service.characteristics!
{
 
print("Found characteristic \(characteristic)")
switch characteristic.UUID {
case BLEParameters.buttonCharactersticUUID: button0Characteristic = characteristic
case BLEParameters.ledCharactersticUUID: led0Characteristic = characteristic
case BLEParameters.bootloadCharactersticUUID: bootloadCharacteristic = characteristic
default: break
}
}
 
// You have a complete connection... so find out the current state of the LED0
// and Button.. then notify the viewcontroller that things are rolling
 
// read the led0 characteristic to find out its current state
CY8CKIT021Board?.readValueForCharacteristic(led0Characteristic)
 
// read the button0 characteristic to find out its current state
CY8CKIT021Board?.readValueForCharacteristic(button0Characteristic)
 
CY8CKIT021Board!.setNotifyValue(true, forCharacteristic: button0Characteristic)
NSNotificationCenter.defaultCenter().postNotificationName(CY8CKIT021Notifications.ConnectionComplete, object: nil)
}
 
// disconnected device - start scanning again
func centralManager(central: CBCentralManager, didDisconnectPeripheral peripheral: CBPeripheral, error: NSError?) {
print("Disconnected \(peripheral)")
CY8CKIT021Board = nil
NSNotificationCenter.defaultCenter().postNotificationName(CY8CKIT021Notifications.DisconnectedDevice, object: nil)
centralManager.scanForPeripheralsWithServices([BLEParameters.CY8CKIT021Service], options: [CBCentralManagerScanOptionAllowDuplicatesKey:false])
 
}

The last block of code is responsible for interacting with the board

// start the bootloader...this will cause an immediate disconnect by the board
func startBootloader()
{
var val: UInt8 = 1 // it doesnt matter the value... any write will cause the bootloader to start
let ns = NSData(bytes: &val, length: sizeof(UInt8))
CY8CKIT021Board!.writeValue(ns, forCharacteristic: bootloadCharacteristic, type: CBCharacteristicWriteType.WithResponse)
}
 
 
// a helper function to write the the device
func writeLed0Characteristic(state: Bool)
{
var val : Int8
if(state)
{
val = 1
}
else
{
val = 0
}
let ns = NSData(bytes: &val, length: sizeof(Int8))
CY8CKIT021Board!.writeValue(ns, forCharacteristic: led0Characteristic, type: CBCharacteristicWriteType.WithResponse)
}
 
// this is the model of the board
var button0State : Bool = false 
var led0State : Bool = false // assume that it is off
 
// This delegate function is called when an updated value is received from the Bluetooth Stack
func peripheral(peripheral: CBPeripheral, didUpdateValueForCharacteristic characteristic: CBCharacteristic, error: NSError?) {
if characteristic == button0Characteristic {
var out: UInt8 = 0
characteristic.value!.getBytes(&out, length:sizeof(UInt8))
if(out == 0)
{
button0State = false
}
else
{
button0State = true
}
NSNotificationCenter.defaultCenter().postNotificationName(CY8CKIT021Notifications.UpdatedButton0, object: nil)
}
 
if characteristic == led0Characteristic {
var out: NSInteger = 0
characteristic.value!.getBytes(&out, length:sizeof(UInt8))
if(out == 0)
{
led0State = false
}
else
{
led0State = true
}
NSNotificationCenter.defaultCenter().postNotificationName(CY8CKIT021Notifications.UpdateLed0, object: nil)
}
}

In the next post Ill show you how to build the Android App.

index description
CY8CKIT-021: A Simple FM/PSoC + BLE Demonstration Board Introduction to CY8CKIT021
CY8CKIT-021: The first four example projects Use the LEDs Buzzer 7-Segment display and the Potentiometer
CY8CKIT-021: The next three example projects Use theThermistor and two Capsense Examples
CY8CKIT-021: Bootloading the PRoC How to put firmware into the PRoC
CY8CKIT-021: The BLEIOT Component A custom component to communicate with the PRoC/PSoC
CY8CKIT-021: Using the BLEIOT Component A full example of the tho MCUs talking
CY8CKIT-021: The PRoC BLE Firmware How to make PRoC Firmware and use it with the BLEIOT Component
CY8CKIT-021: Example 10 - the new IOS App How to build and IOS App to talk to the development kit

Recommended Posts

No comment yet, add your voice below!


Add a Comment

Your email address will not be published. Required fields are marked *