Pre loader

How to update values as realtime chart from device connected by bluetooth (Swift)

Welcome to the SciChart Forums!

  • Please read our Question Asking Guidelines for how to format a good question
  • Some reputation is required to post answers. Get up-voted to avoid the spam filter!
  • We welcome community answers and upvotes. Every Q&A improves SciChart for everyone

WPF Forums | JavaScript Forums | Android Forums | iOS Forums

0
0

I have just learned how to use sci-chart framework with tutorials.
And I tried to add values from bluetooth as realtime chart as shown in tutorials.
I have finished receiving data from a Bluetooth connection.
However, using scichart to represent this data in real time is hard to solve by looking at the tutorial alone.
Does anyone have any idea how to use real-time tutorials to teach you how to represent your own data, not the example sine graph?

The code below is what I tried and is wrong.

import UIKit
import CoreBluetooth
import SciChart

let maestroServiceCBUUID = CBUUID(string:”495sdfd3-FE7D-4AE5-8FA9-9FAFD205E455″)
let maestroBrainDataCBUUID = CBUUID(string: “4953sdf3-1E4D-4BD9-BA61-23C647249616”)
class HRMViewController: UIViewController {
var sciChartSurface: SCIChartSurface?

var lineDataSeries: SCIXyDataSeries!
var scatterDataSeries: SCIXyDataSeries!

var lineRenderableSeries: SCIFastLineRenderableSeries!
var scatterRenderableSeries: SCIXyScatterRenderableSeries!

var timer: Timer?
var phase = 0.0
var i = 0

@IBOutlet weak var brainRateLabel: UILabel!

var centralManager: CBCentralManager!
var maestroPeripheral:CBPeripheral!
override func viewDidLoad() {
super.viewDidLoad()

sciChartSurface = SCIChartSurface(frame: self.view.bounds)
sciChartSurface?.autoresizingMask = [.flexibleHeight, .flexibleWidth]
sciChartSurface?.translatesAutoresizingMaskIntoConstraints = true

self.view.addSubview(sciChartSurface!)


let xAxis = SCINumericAxis()
xAxis.growBy = SCIDoubleRange(min: SCIGeneric(0.1), max: SCIGeneric(0.1))
sciChartSurface?.xAxes.add(xAxis)

let yAxis = SCINumericAxis()
yAxis.growBy = SCIDoubleRange(min: SCIGeneric(0.1), max: SCIGeneric(0.1))
sciChartSurface?.yAxes.add(yAxis)

createRenderableSeries()
addModifiers()


centralManager = CBCentralManager(delegate: self , queue: nil)

// Make the digits monospaces to avoid shifting when the numbers change

}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)

if nil == timer{
  timer = Timer.scheduledTimer(withTimeInterval: 0.01, repeats: true, block: updatingDataPoints)
}

}

override func viewWillDisappear(_ animated: Bool) {
super.viewWillDisappear(animated)

if nil != timer{
  timer?.invalidate()
  timer = nil
}

}

func updatingDataPoints(timer:Timer){

i += 1

lineDataSeries.appendX(SCIGeneric(i), y: SCIGeneric(cos(Double(i)*0.1 + phase)))
scatterDataSeries.appendX(SCIGeneric(i), y: SCIGeneric(cos(Double(i)*0.1 + phase)))

phase += 0.01

sciChartSurface?.zoomExtents()
sciChartSurface?.invalidateElement()

}

func createDataSeries(_brainwave2:Double){
// Init line data series
lineDataSeries = SCIXyDataSeries(xType: .double, yType: .double)
lineDataSeries.fifoCapacity = 500
lineDataSeries.seriesName = “line series”

// Init scatter data series

// scatterDataSeries = SCIXyDataSeries(xType: .double, yType: .double)
// scatterDataSeries.fifoCapacity = 500
// scatterDataSeries.seriesName = “scatter series”

for i in 0...500{
  lineDataSeries.appendX(SCIGeneric(i), y: SCIGeneric(_brainwave2))

// scatterDataSeries.appendX(SCIGeneric(i), y: SCIGeneric(cos(Double(i)*0.1)))
}

i = Int(lineDataSeries.count())

}

func createRenderableSeries(){
lineRenderableSeries = SCIFastLineRenderableSeries()
lineRenderableSeries.dataSeries = lineDataSeries

scatterRenderableSeries = SCIXyScatterRenderableSeries()
scatterRenderableSeries.dataSeries = scatterDataSeries

sciChartSurface?.renderableSeries.add(lineRenderableSeries)
sciChartSurface?.renderableSeries.add(scatterRenderableSeries)

}

func addModifiers(){
let xAxisDragmodifier = SCIXAxisDragModifier()
xAxisDragmodifier.dragMode = .pan
xAxisDragmodifier.clipModeX = .none

let yAxisDragmodifier = SCIYAxisDragModifier()
yAxisDragmodifier.dragMode = .pan

let extendZoomModifier = SCIZoomExtentsModifier()
let pinchZoomModifier = SCIPinchZoomModifier()

let rolloverModifier = SCIRolloverModifier()
let legend = SCILegendModifier()

let groupModifier = SCIChartModifierCollection(childModifiers: [xAxisDragmodifier, yAxisDragmodifier, pinchZoomModifier, extendZoomModifier, legend, rolloverModifier])

sciChartSurface?.chartModifiers = groupModifier

}

func brainwaveReceived(_ brainWave:Double){
let brainWave = brainWave * 3.3 / 65536
brainRateLabel.text = String(brainWave)
print(“brainwave: (brainWave)”)
}

}

extension HRMViewController: CBCentralManagerDelegate {
func centralManagerDidUpdateState(_ central: CBCentralManager) {
switch central.state {

case .unknown:
  print("central.state is . unknown")
case .resetting:
  print("central.state is . resetting")
case .unsupported:
  print("central.state is . unsupported")
case .unauthorized:
  print("central.state is . unauthorized")
case .poweredOff:
  print("central.state is . poweredOff")
case .poweredOn:
  print("central.state is . poweredOn")
  centralManager.scanForPeripherals(withServices:nil)
}

}

func centralManager(_ central: CBCentralManager, didDiscover peripheral: CBPeripheral, advertisementData: [String : Any], rssi RSSI: NSNumber) {
print(peripheral)
if peripheral.name == “MAESTRO1” {
// maestroPeripheral = peripheral
centralManager.stopScan()
maestroPeripheral = peripheral
maestroPeripheral.delegate = self
central.connect(maestroPeripheral)
}

}
func centralManager(_ central: CBCentralManager, didConnect peripheral: CBPeripheral) {
print(“Connected!”)
maestroPeripheral.discoverServices([maestroServiceCBUUID])
}
}

extension HRMViewController:CBPeripheralDelegate{
func peripheral(_ peripheral: CBPeripheral, didDiscoverServices error: Error?) {
guard let services = peripheral.services else {return}
for service in services {
print(service)
peripheral.discoverCharacteristics(nil, for: service)
}
}
func peripheral(_ peripheral: CBPeripheral, didDiscoverCharacteristicsFor service: CBService, error: Error?) {
guard let characteristics = service.characteristics else {return}

for characteristic in characteristics {
  print(characteristic)
  if characteristic.properties.contains(.read){
    print("\(characteristic.uuid): properties contain .read")
  }
  if characteristic.properties.contains(.notify){
    print("\(characteristic.uuid): properties contain .notify")
    peripheral.setNotifyValue(true , for: characteristic)
  }
}

}

func peripheral(_ peripheral: CBPeripheral, didUpdateValueFor characteristic: CBCharacteristic,
error: Error?) {
switch characteristic.uuid {
case maestroBrainDataCBUUID:
let wave = Double(brainData(from: characteristic))*3.3/65536
createDataSeries(_brainwave2:wave)

  default:
  print("Unhandled Characteristic UUID: \(characteristic.uuid)")
}

}
private func brainData(from characteristic: CBCharacteristic) -> Int {
guard let characteristicData = characteristic.value else { return -1 }
let byteArray = UInt8

let firstBitValue = byteArray[0] & 0x01
if firstBitValue == 0 {
  // Heart Rate Value Format is in the 2nd byte
  return Int(byteArray[1])
} else {
  // Heart Rate Value Format is in the 2nd and 3rd bytes
  return (Int(byteArray[1]) << 8) + Int(byteArray[2])
}

}

}

Version
11.3
  • You must to post comments
0
0

Hi JaeHwan,

The code sample above – we can’t run that and have a look so its hard to see what is wrong when someone pastes so much code into the forums.

All I can suggest to you, is from the tutorial (which you’ve seen here), you need to use a technique like this to append data into the DataSeries.

func updatingDataPoints(timer:Timer){

    let i = lineDataSeries.count()

    lineDataSeries.appendX(SCIGeneric(i), y: SCIGeneric(sin(Double(i)*0.1 + phase)))
    scatterDataSeries.appendX(SCIGeneric(i), y: SCIGeneric(cos(Double(i)*0.1 + phase)))

    phase += 0.01

    sciChartSurface?.zoomExtents()
}

SCIXyDataSeries.appendX function allows you to append an X,Y value to the data series. The chart will automatically redraw but it will not zoom to fit unless you call SCIChartSurface.zoomExtents() or you set SCIAxisBase.autoRange.

let me know if this helps

Best regards
Andrew

  • You must to post comments
0
0

First of all ,

Thank you for answer about my question.

But , i still can’t solve this problem.

What i want to make likes as below (y value : cos or sin(Double(i)) -> wave)

Wave is from bluetooth data

But if i tried to that , there were some error.

How to apply to wave in another function to y value in scichart? (refer to tutorials)

It might be just normal customizing chart.. But i’m not sure how to solve it ..TT

Thank you

func updatingDataPoints(timer:Timer){

    i += 1

    lineDataSeries.appendX(SCIGeneric(i), y: SCIGeneric(wave)))

    phase += 0.01

    sciChartSurface?.zoomExtents()
    sciChartSurface?.invalidateElement()
 }


 func createDataSeries(){
    lineDataSeries = SCIXyDataSeries(xType: .double, yType: .double)
    lineDataSeries.fifoCapacity = 500
    lineDataSeries.seriesName = "line series"


    for i in 0...500{
      lineDataSeries.appendX(SCIGeneric(i), y: SCIGeneric(wave))
    }

    i = Int(lineDataSeries.count())
  }



 func peripheral(_ peripheral: CBPeripheral, didUpdateValueFor characteristic: CBCharacteristic,
                  error: Error?) {
    switch characteristic.uuid {
      case maestroBrainDataCBUUID:
        let wave = Double(brainData(from: characteristic))*3.3/65536

      default:
      print("Unhandled Characteristic UUID: \(characteristic.uuid)")
    }

  }
  • You must to post comments
Showing 2 results
Your Answer

Please first to submit.

Try SciChart Today

Start a trial and discover why we are the choice
of demanding developers worldwide

Start TrialCase Studies