I am quite new to iOS programming and also to bluetooth protocol.
I have found a sample code written in swift and trying to modify it to work with my own bluetooth module. The module I have is DBM01 from dorji.
The service I need to use is FFF0 and the characteristics is FFF1 for sending a ASCII value.
When I use the LightBlue app on my macbook and connect to the board I have designed, which has the DBM01 module on it, I can send the char value of "1" and I get the expected response (Turning on a LED) and when I send value of "0" it turns the LED off.
Now with the code I have, I can connect to the DBM01 module. I can print its name. However, I cannot disconnect from it with the following function. I am also not sure if this is for disconnecting from the device or it is called automatically when the device is disconnected. Regardless, it does not work either way.
func centralManager(central: CBCentralManager,
didDisconnectPeripheral peripheral: CBPeripheral,
error: NSError?)
My main problem is I really didn't understand how I specify the service and the characteristics that I am interested in and connect to specific device that has them.
I am also unable to send a message. When I try I got the predefined error, since the following condition did't hold
if writeCharacteristic != nil
Below is my full code.
Appreciate if you can point out where I am doing wrong and how I can achieve connecting to specific device with specific service and characteristics information and sending data.
//
// ViewController.swift
// bleSwift
//
import UIKit
import CoreBluetooth
class ViewController: UIViewController, CBCentralManagerDelegate, CBPeripheralDelegate {
var centralManager: CBCentralManager!
var peripheral: CBPeripheral!
var writeCharacteristic: CBCharacteristic!
var service: CBService!
var characteristic: CBCharacteristic!
var bluetoothAvailable = false
let message = "1"
#IBOutlet weak var deviceName: UILabel!
#IBOutlet weak var ServiceName: UILabel!
#IBOutlet weak var CharacteristicsName: UILabel!
func centralManagerDidUpdateState(central: CBCentralManager)
{
print("Checking state")
switch (central.state)
{
case .PoweredOff:
print("CoreBluetooth BLE hardware is powered off")
case .PoweredOn:
print("CoreBluetooth BLE hardware is powered on and ready")
bluetoothAvailable = true;
case .Resetting:
print("CoreBluetooth BLE hardware is resetting")
case .Unauthorized:
print("CoreBluetooth BLE state is unauthorized")
case .Unknown:
print("CoreBluetooth BLE state is unknown");
case .Unsupported:
print("CoreBluetooth BLE hardware is unsupported on this platform");
}
if bluetoothAvailable == true
{
discoverDevices()
}
}
func centralManager(central: CBCentralManager, didDiscoverPeripheral peripheral: CBPeripheral, advertisementData: [String : AnyObject], RSSI: NSNumber)
{
// Stop scanning
self.centralManager.stopScan()
print("Stopped Scanning")
// Set as the peripheral to use and establish connection
//self.peripheral = peripheral
//self.peripheral.delegate = self
//self.centralManager.connectPeripheral(peripheral, options: nil)
peripheral.discoverServices([CBUUID(string: "FFF0")])
print("CONNECTED!!")
print(peripheral.name)
deviceName.text = peripheral.name
}
func discoverDevices() {
print("Discovering devices")
centralManager.scanForPeripheralsWithServices(nil, options: nil)
}
#IBAction func disconnectDevice(sender: AnyObject) {
func centralManager(central: CBCentralManager,
didDisconnectPeripheral peripheral: CBPeripheral,
error: NSError?)
{
print("CONNECTION WAS DISCONNECTED")
deviceName.text = "Disconnected"
}
}
#IBAction func Scan(sender: AnyObject)
{
print("Scan")
centralManager = CBCentralManager(delegate: self, queue: nil)
}
#IBAction func Send(sender: AnyObject)
{
let data = message.dataUsingEncoding(NSUTF8StringEncoding)
if writeCharacteristic != nil
{
print("Sent")
peripheral!.writeValue(data!, forCharacteristic: writeCharacteristic, type: CBCharacteristicWriteType.WithoutResponse)
}
else
{
print("Couldn't Send")
}
}
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}
In order to send data to your ble peripheral, you should:
Start scanning.
In your ble central manager delegate you'll recieve didDiscoverPeripheral callback with discovered peripheral. Set yourself as its delegate and connect to it: centralManager.connectPeripheral(...)
Receive didConnectPeripheral in delegate. Now call discoverServices for this peripheral.
Recieve didDiscoverServices in your delegate. Finaly, call discoverCharacteristics for your service.
You'll recieve characteristic in didDiscoverCharacteristic delegate method. After that, you'll be able to send data to exact characteristic of your peripheral.
To disconnect peripheral, call method centralManager.cancelPeripheralConnection(...)
Related
I created a new app with swiftUI and trying to use coreBluetooth library to connect Raspberry Pi 4. I searched all the google and I stuck at connecting Raspberry Pi 4. I can find all the devices (peripherals) but I'm not able to connect them.
Here is the code;
class BLEManager: NSObject, ObservableObject, CBCentralManagerDelegate {
var myCentral: CBCentralManager!
#Published var isSwitchedOn = false
#Published var peripherals = [Peripheral]()
override init() {
super.init()
myCentral = CBCentralManager(delegate: self, queue: nil)
myCentral.delegate = self
}
func centralManagerDidUpdateState(_ central: CBCentralManager) {
if central.state == .poweredOn {
isSwitchedOn = true
}
else {
isSwitchedOn = false
}
}
func centralManager(_ central: CBCentralManager, didDiscover peripheral: CBPeripheral, advertisementData: [String : Any], rssi RSSI: NSNumber) {
var peripheralName: String!
if let name = advertisementData[CBAdvertisementDataLocalNameKey] as? String {
peripheralName = name
}
else {
peripheralName = "Unknown"
}
if peripheral.identifier.uuidString == "6D915395-3E79-0072-22A3-009DDC331F7C" {
myCentral.stopScan()
myCentral.connect(peripheral, options: nil)
print("okokokokok")
}
let newPeripheral = Peripheral(id: peripherals.count, name: peripheralName, rssi: RSSI.intValue)
print(newPeripheral)
peripherals.append(newPeripheral)
}
func centralManager(central: CBCentralManager!,didConnectPeripheral peripheral: CBPeripheral!)
{
peripheral.discoverServices(nil)
print("Connected")
print(peripheral.name!)
print(peripheral.services!)
}
}
Deleted some of code parts bc of stackoverfow
Your problem for the connection was not holding a reference to the CBPeripheral object to which you want to connect. So you've solved it by referencing to it in your BLEManager class.
Now how can you send and get data to / from your Raspberry? Well you must implement the CBPeripheralDelegate in your BLEManager class.
After the central manager finishes discovering the available services it will call didDiscoverServices method of CBPeripheralDelegate; where you need to invoke discoverCharacteristics for the discovered service.
Again, when characteristics has been discovered for the given service with the discoverCharacteristics(_:for:) method which you invoked in the didDiscoverServices callback, you can set the notify value if you want to know about characteristic updates.
After the characteristics has been discovered you can send values by using writeValue method of CBPeripheral instance to which you've referenced it when connected.
When you send data from the Raspberry for a certain charachteristic, the didUpdateValueFor method of CBPeripheralDelegate will get called. In this callback; you can obtain the received data from the CBCharacteristic.value property. Note that the value property is optional, hence you need to handle it with care.
I'm actually in informatics school and I have some trouble with the connection between my own self signed app coded in Swift(Xcode 11.3 and for IOS 13.2 device) and a BLE module SH-HC-08 plugged on an Arduino. (UUID : FE60E626-C58C-69F5-324F-43C7C409A93D)
I'm totally new into swift language and self-learning this way of thinking in this language.
I'm using CoreBluetooth to detect if the Bluetooth on my iPhone is On or off.
I can't actually check if my peripheral is detected, and can't send any information by my app.
(don't understand how to configure the methods in CoreBluetooth)
I downloaded apps caled LightBlue and BluetoothLE on app store. The first one give me fews information about my Bluetooth device and the second one allow me to sends Ascii Strings to my Arduino by my Bluetooth module.
LightBlue information 1:
LightBlue information 2:
BluetoothLE app:
As I said before, i already :
Import CoreBluetooth
Add CBCentralManagerDelegate & CBPeripheralDelegate to my class ViewController
instantiate CBCentralManager and CBPeripheral
setup the centralManagerDidUpdateState function
CoreBluetooth code:
import UIKit
import CoreBluetooth
var texteEnvoyer:String?
var test = false
class ViewController: UIViewController, CBCentralManagerDelegate, CBPeripheralDelegate {
var manager:CBCentralManager!
var module : CBPeripheral!
#IBOutlet weak var labelConnection: UILabel!
#IBOutlet weak var switchConnection: UISwitch!
#IBOutlet weak var labelTextField: UITextField!
#IBOutlet weak var labelTest: UILabel!
override func viewDidLoad() {
super.viewDidLoad()
refresh()
manager = CBCentralManager(delegate: self, queue: nil)
}
func centralManagerDidUpdateState(_ central: CBCentralManager)
{
if(central.state == .poweredOff)
{
let alertController = UIAlertController(title: "Bluetooth", message: "Le bluetooth est déconnecté, veuillez l'activer et vous connecter au module.", preferredStyle: UIAlertController.Style.alert)
alertController.addAction(UIAlertAction(title: "OK", style: UIAlertAction.Style.default, handler: nil))
present(alertController, animated: true, completion: nil)
test = false
}
if(central.state == .poweredOn)
{
test = true
}
refresh()
}
I tried to play with the others methods like didDiscoverPeripheral or didConnected but I don't understand what i do and can't find any help to send information (preferred in String) by a self made application with bluetooth.
I tried that to discover my module but I don't have any "print" in my logs and don't know if my request was done or not... if I do it well or not too.
func centralManager(_ central: CBCentralManager, didDiscover peripheral: CBPeripheral, advertisementData: [String : Any], rssi RSSI: NSNumber) {
print("Name: \(peripheral.name)")
self.module = peripheral
self.module.delegate = self
if(peripheral.name == "SG-HC-08"){
manager.stopScan()
manager.connect(self.module, options: nil)
print(peripheral.name)
}
}
Someone have any experience with that or any help to give it will help me so much.
Thanks
Jikko,
I would be careful with using Global Variables.
Your global variables are the two declared outside of your class scope.
var texteEnvoyer:String?
var test = false
These can sometimes cause issues with your program such as memory leaks and retention. Im not saying that this is the case for you. But if you continue to develop and publish applications this may be something to rethink. Im sure for your purposes now this is totally fine.
To your point of "nothing in the console form the peripheral" we can try adding in some print statements to help us debug what is actually happening.
For starters:
func centralManagerDidUpdateState(_ central: CBCentralManager){
//.....
print("ENTERED THE FUNCTION")
if(peripheral.name == "SG-HC-08"){
manager.stopScan()
manager.connect(self.module, options: nil)
print("REACHED HERE")
}
}
IF in the console you see "REACHED HERE" then we know the code was called and executed. However this does not mean a successful connection.
If we do not see the print statement "ENTERED THE FUNCTION" , or "REACHED HERE" then that means there is a basic error. The function was never called or executed.
I would first create a function like so:
func startScan(){
if let central = manager {
central.scanForPeripheralsWithServices(nil, options: nil)
print("started Scanning")
}
}
And then in viewDidLoad()
call the start scan
override func viewDidLoad(){
super.viewDidLoad(animated)
startScan()
}
And then once you have discovered a peripheral use the didDiscoverPeripheral method (which will be called first)
func centralManager(_ central: CBCentralManager!, didDiscoverPeripheral peripheral: CBPeripheral!, advertisementData: [NSObject : AnyObject]!, RSSI: NSNumber!) {
print("DISCOVERED PERIPHERAL", peripheral)
// manager.connectPeripheral(peripheral, options: nil)
}
You can then connect to it once discovered.
Hope this helps
EDIT ----
try adding in these two lines to your function.
peripheral.delegate = self
peripheral.discoverServices(nil)
like so
func centralManager(_ central: CBCentralManager!, didDiscoverPeripheral peripheral: CBPeripheral!, advertisementData: [NSObject : AnyObject]!, RSSI: NSNumber!) {
print("DISCOVERED PERIPHERAL", peripheral)
// manager.connectPeripheral(peripheral, options: nil)
}
I forgot to add in the underscore "_" to the function parameters
func centralManager(_ central: ....) {}
--------------------^
Please find some informations on how delegation (1) and BLE (2) work.
1) When you instantiate your CBCentralObject manager, you pass your view controller (self) as the delegate of the central manager which means that some Bluetooth events handled by your central manager will be forwarded to your view controller.
In your case, it seems that you didn't implement the centralManager(_ central: CBCentralManager, didDiscover peripheral: CBPeripheral, advertisementData: [String : Any], rssi RSSI: NSNumber) method which is called every time a new peripheral is discovered.
Once you get the discovered peripheral, you can continue the process with the other delegates methods
2) If you want to communicate with a BLE device you have several steps to follow:
discover the device
connect to it
discover services and
characteristics
Then you can write data on any characteristic you want, or subscribe to listen to data emitted by your BLE device.
I am trying to make a Bluetooth scanning and connect app using SwiftUI. I am having issues refreshing the list view in SwiftUI as the Bluetooth scanning starts and I get some peripheral names with RSSI values. Any guidance would be useful. The code is as follows:
Firstly I have a SwiftUI view with a list and the text in HorizontalView within that. I will be using ForEach() later on but for now I just kept it simple with one text.
import SwiftUI
struct ContentView: View {
var body: some View {
List{
// ForEach: Loop here to list all BLE Devices in "devices" array
// Monitor "devices" array for changes. As changes happen, Render the Body again.
HStack{
Text("Device-1")
.onTapGesture {
// To Do: Call Connect BLE Device
print("Device-1 Connected.")
}
}
}.navigationBarTitle("BLE Devices")
.onAppear(perform: connectBLEDevice)
}
private func connectBLEDevice(){
let ble = BLEConnection()
// Start Scanning for BLE Devices
ble.startCentralManager()
}
}
// UIHosting Controller
var child = UIHostingController(rootView: ContentView())
For scanning and connecting to the Bluetooth device, this is the code that I use:
import Foundation
import UIKit
import CoreBluetooth
open class BLEConnection: NSObject, CBPeripheralDelegate, CBCentralManagerDelegate {
// Properties
private var centralManager: CBCentralManager! = nil
private var peripheral: CBPeripheral!
public static let bleServiceUUID = CBUUID.init(string: "XXXX")
public static let bleCharacteristicUUID = CBUUID.init(string: "XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXXX")
// Array to contain names of BLE devices to connect to.
// Accessable by ContentView for Rendering the SwiftUI Body on change in this array.
var scannedBLEDevices: [String] = []
func startCentralManager() {
self.centralManager = CBCentralManager(delegate: self, queue: nil)
print("Central Manager State: \(self.centralManager.state)")
DispatchQueue.main.asyncAfter(deadline: .now() + 1) {
self.centralManagerDidUpdateState(self.centralManager)
}
}
// Handles BT Turning On/Off
public func centralManagerDidUpdateState(_ central: CBCentralManager) {
switch (central.state) {
case .unsupported:
print("BLE is Unsupported")
break
case .unauthorized:
print("BLE is Unauthorized")
break
case .unknown:
print("BLE is Unknown")
break
case .resetting:
print("BLE is Resetting")
break
case .poweredOff:
print("BLE is Powered Off")
break
case .poweredOn:
print("Central scanning for", BLEConnection.bleServiceUUID);
self.centralManager.scanForPeripherals(withServices: [BLEConnection.bleServiceUUID],options: [CBCentralManagerScanOptionAllowDuplicatesKey : true])
break
}
if(central.state != CBManagerState.poweredOn)
{
// In a real app, you'd deal with all the states correctly
return;
}
}
// Handles the result of the scan
public func centralManager(_ central: CBCentralManager, didDiscover peripheral: CBPeripheral, advertisementData: [String : Any], rssi RSSI: NSNumber) {
print("Peripheral Name: \(String(describing: peripheral.name)) RSSI: \(String(RSSI.doubleValue))")
// We've found it so stop scan
self.centralManager.stopScan()
// Copy the peripheral instance
self.peripheral = peripheral
self.scannedBLEDevices.append(peripheral.name!)
self.peripheral.delegate = self
// Connect!
self.centralManager.connect(self.peripheral, options: nil)
}
// The handler if we do connect successfully
public func centralManager(_ central: CBCentralManager, didConnect peripheral: CBPeripheral) {
if peripheral == self.peripheral {
print("Connected to your BLE Board")
peripheral.discoverServices([BLEConnection.bleServiceUUID])
}
}
// Handles discovery event
public func peripheral(_ peripheral: CBPeripheral, didDiscoverServices error: Error?) {
if let services = peripheral.services {
for service in services {
if service.uuid == BLEConnection.bleServiceUUID {
print("BLE Service found")
//Now kick off discovery of characteristics
peripheral.discoverCharacteristics([BLEConnection.bleCharacteristicUUID], for: service)
return
}
}
}
}
// Handling discovery of characteristics
public func peripheral(_ peripheral: CBPeripheral, didDiscoverCharacteristicsFor service: CBService, error: Error?) {
if let characteristics = service.characteristics {
for characteristic in characteristics {
if characteristic.uuid == BLEConnection.bleServiceUUID {
print("BLE service characteristic found")
} else {
print("Characteristic not found.")
}
}
}
}
}
The task here is to scan for peripherals and show them as they come and go from the range in the SwiftUI List.
Thanks.
You have no state here and no way to update that state. I would probably make BLEConnection an ObservableObject and then #Publish the array of devices:
open class BLEConnection: ..., ObservableObject {
#Publish var scannedBLEDevices: [Device] = [] // keep as [String] for initial debugging if you want
}
then, in your ContentView, subscribe to those changes:
struct ContentView: View {
#ObservedObject var bleConnection = BLEConnection()
var body: some View {
// if still `[String]` then \.self will work, otherwise make `Device` `Identifiable`
List(bleConnection.devices, id: \.self) { device in
Text(verbatim: device)
}
}
}
Now, when your connection adds/removes devices to scannedBLEDevices, it will automatically update in your ContentView.
Im new to programming in swift, & I need help with working with bluetooth.
Im working on a project that involves sending a string to a computer via bluetooth, and Im able to enter the receiving device's MAC address beforehand so it has that to know where to send it.
My only problem at this stage is connecting to said device, & sending the data. I tried looking up tutorials, but they were either for Android (Which I already got working, I need one for iOS now), or they were about how to connect via service UUID (what?).
Heres the code I have so far:
import UIKit
import CoreBluetooth
class transmitter: UIViewController, CBCentralManagerDelegate, CBPeripheralDelegate {
var manager:CBCentralManager!
var peripheral:CBPeripheral!
let SCRATCH_UUID = UUID.init(uuidString: "00001101-0000-1000-8000-00805F9B34FB")
let SERVICE_UUID = CBUUID(string: "00001101-0000-1000-8000-00805F9B34FB")
override func viewDidLoad() {
super.viewDidLoad()
// Define manager
manager = CBCentralManager(delegate: self, queue: nil)
print(globals.data)
// Do any additional setup after loading the view.
}
#IBOutlet weak var console: UILabel!
// Check if teh bluetooth is enabled
func centralManagerDidUpdateState(_ central: CBCentralManager) {
if central.state == CBManagerState.poweredOn {
central.scanForPeripherals(withServices:nil, options: nil)
print (central.isScanning)
console.text = String(describing: central.retrievePeripherals(withIdentifiers: [SCRATCH_UUID!]))
} else {
//print("Bluetooth not available.")
let alert = UIAlertController(title: "Bluetooth unavalible", message: "Bluetooth is unavalibe for this device. Is it even turned on?", preferredStyle: UIAlertControllerStyle.alert)
alert.addAction(UIAlertAction(title: "Ok", style: UIAlertActionStyle.default, handler: nil))
self.present(alert, animated: true, completion: nil)
}
}
// Pair with device....
// TODO: Change to be based on MAC Address instead of name...?
private func centralManager(central: CBCentralManager, didDiscoverPeripheral peripheral: CBPeripheral, advertisementData: [String : AnyObject], RSSI: NSNumber) {
let device = (advertisementData as NSDictionary).object(forKey: CBAdvertisementDataLocalNameKey) as? NSString
// console.text = peripheral.name
/*
if device?.contains(globals.macAddress) == true {
self.manager.stopScan()
self.peripheral = peripheral
self.peripheral.delegate = self
manager.connect(peripheral, options: nil)
}
*/
}
//
// The rest is copied from a tutorial
//
// Once you are connected to a device, you can get a list of services on that device.
func centralManager(central: CBCentralManager, didConnectPeripheral peripheral: CBPeripheral) {
peripheral.discoverServices(nil)
}
// Once you get a list of the services offered by the device, you will want to get a list of the characteristics. You can get crazy here, or limit listing of characteristics to just a specific service. If you go crazy watch for threading issues.
private func peripheral(peripheral: CBPeripheral,didDiscoverServices error: NSError?) {
for service in peripheral.services! {
let thisService = service as CBService
if service.uuid == SERVICE_UUID {
peripheral.discoverCharacteristics(nil, for: thisService)
}
}
}
// There are different ways to approach getting data from the BLE device. One approach would be to read changes incrementally. Another approach, the approach I used in my application, would be to have the BLE device notify you whenever a characteristic value has changed.
private func peripheral(peripheral: CBPeripheral, didDiscoverCharacteristicsForService service: CBService, error: NSError?) {
for characteristic in service.characteristics! {
let thisCharacteristic = characteristic as CBCharacteristic
if thisCharacteristic.uuid == SERVICE_UUID {
self.peripheral.setNotifyValue(true, for: thisCharacteristic)
}
}
}
// This is an optional step, but hey, let us be good programmers and clean up after ourselves. Also a good place to start scanning all over again.
private func centralManager(central: CBCentralManager, didDisconnectPeripheral peripheral: CBPeripheral, error: NSError?) {
central.scanForPeripherals(withServices: nil, options: nil)
}
}
What I was trying to do at this stage was:
Check to make sure bluetooth is enabled (Works)
List devices available, as I was not able to connect via MAC address (Fails)
What would be nice though is that if I didn't have to do step 2, & just connect via the provided MAC address instead of scanning for devices, which didn't show any.
Help?
Ok, so it seems that SPP is not supported. Crap :/
Ill look into what both John Doe & Paulw11 suggested
Thanks!
I'm trying to listen to all Bluetooth connect/disconnect events. Even though the delegate's centralManagerDidUpdateState function is called, nothing happens when I connect or disconnect Bluetooth devices.
I'm confused as to what's going wrong. I initialize the Central Manager/delegate like this:
var btDelegate: CBCentralManagerDelegate = BluetoothDelegate()
var btManager = CBCentralManager(delegate: btDelegate, queue: nil)
BluetoothDelegate is defined like so:
import Foundation
import CoreBluetooth
class BluetoothDelegate : NSObject, CBCentralManagerDelegate {
func centralManager(central: CBCentralManager!, didConnectPeripheral peripheral: CBPeripheral!) {
println("connect") //this line is not called
}
func centralManager(central: CBCentralManager!, didDisconnectPeripheral peripheral: CBPeripheral!, error: NSError!) {
println("disconnect") //this line is not called
}
func centralManagerDidUpdateState(central: CBCentralManager!) {
println("state update") //this line is called
}
}
Note: I can continuously receive more state update events such as when I toggle Bluetooth, even though connect and disconnect are not called.
From your code it looks like you haven't started scanning for peripherals. Once you have confirmed that your central is in powered on state from centralManagerDidUpdateState method you should start scanning for your peripherals.
(The bluetooth devices you connected from bluetooth settings panel are irrelevant. You can't have access to them. (as far as I know) Incase you want to scan and find out your device on your own below code will help)
func centralManagerDidUpdateState(central: CBCentralManager!) {
switch (central.state) {
case CBCentralManagerState.PoweredOff:
break
case CBCentralManagerState.PoweredOn:
startScan() // start scanning once the bluetooth is On
break
default:
break
}
}
And your startScan method will be (You can provide service UUID, use nil if you want all )
func startScan(){
if let central = btManager {
central.scanForPeripheralsWithServices(nil, options: nil)
println("started Scanning")
}
}
After that whenever you discover a peripheral didDiscoverPeripheral method will be called first.
func centralManager(central: CBCentralManager!, didDiscoverPeripheral peripheral: CBPeripheral!, advertisementData: [NSObject : AnyObject]!, RSSI: NSNumber!) {
println(peripheral)
// btManager.connectPeripheral(peripheral, options: nil)
}
From there you collect the peripheral and then invoke connectPeripheral method of CBCentralManager. If the connection is successful didConnectPeripheral method will be called.
You should go through this documentation for complete details