/ app / packages / ble_peripheral / darwin / Classes / BleExtensions.swift
BleExtensions.swift
  1  //
  2  //  BleExtensions.swift
  3  //  ble_peripheral
  4  //
  5  //  Created by Rohit Sangwan on 29/07/23.
  6  //
  7  
  8  #if os(iOS)
  9      import Flutter
 10  #elseif os(macOS)
 11      import FlutterMacOS
 12  #else
 13      #error("Unsupported platform.")
 14  #endif
 15  import CoreBluetooth
 16  import Foundation
 17  
 18  enum CustomError: Error {
 19      case notFound(String)
 20  }
 21  
 22  /// local list of characteristic
 23  var characteristicsList = [CBMutableCharacteristic]()
 24  var servicesList = [CBMutableService]()
 25  
 26  extension BleService {
 27      func toCBService() -> CBMutableService {
 28          let service = CBMutableService(
 29              type: CBUUID(string: uuid),
 30              primary: primary
 31          )
 32          let chars = characteristics.compactMap { bleChar in
 33              bleChar.toCBChar()
 34          }
 35          if !chars.isEmpty {
 36              service.characteristics = chars
 37          }
 38          // Add local reference of this service
 39          servicesList.removeAll { $0.uuid.uuidString.lowercased() == service.uuid.uuidString.lowercased() }
 40          servicesList.append(service)
 41          return service
 42      }
 43  }
 44  
 45  extension BleDescriptor {
 46      func toCBMutableDescriptor() -> CBMutableDescriptor {
 47          return CBMutableDescriptor(
 48              type: CBUUID(string: uuid),
 49              value: value?.toData()
 50          )
 51      }
 52  }
 53  
 54  extension BleCharacteristic {
 55      func toCBChar() -> CBMutableCharacteristic {
 56          let properties: [CBCharacteristicProperties] = self.properties.compactMap { int64 in
 57              int64.toCBCharacteristicProperties()
 58          }
 59          let permissions: [CBAttributePermissions] = self.permissions.compactMap { int64 in
 60              int64.toCBAttributePermissions()
 61          }
 62  
 63          let combinedProperties = properties.reduce(CBCharacteristicProperties()) { $0.union($1) }
 64          let combinedPermissions = permissions.reduce(CBAttributePermissions()) { $0.union($1) }
 65  
 66          let char = CBMutableCharacteristic(
 67              type: CBUUID(string: uuid),
 68              properties: combinedProperties,
 69              value: value?.toData(),
 70              permissions: combinedPermissions
 71          )
 72          char.descriptors = descriptors?.compactMap { desc in
 73              desc.toCBMutableDescriptor()
 74          }
 75          // Add local reference of this characteristic
 76          characteristicsList.removeAll { $0.uuid.uuidString.lowercased() == char.uuid.uuidString.lowercased() }
 77          characteristicsList.append(char)
 78          return char
 79      }
 80  }
 81  
 82  extension String {
 83      func findCharacteristic() -> CBMutableCharacteristic? {
 84          return characteristicsList.first { ch in
 85              ch.uuid.uuidString == self
 86          }
 87      }
 88  
 89      func findService() -> CBMutableService? {
 90          return servicesList.first { ch in
 91              ch.uuid.uuidString == self
 92          }
 93      }
 94  }
 95  
 96  extension Int64 {
 97      func toCBCharacteristicProperties() -> CBCharacteristicProperties? {
 98          switch self {
 99          case 0:
100              return CBCharacteristicProperties.broadcast
101          case 1:
102              return CBCharacteristicProperties.read
103          case 2:
104              return CBCharacteristicProperties.writeWithoutResponse
105          case 3:
106              return CBCharacteristicProperties.write
107          case 4:
108              return CBCharacteristicProperties.notify
109          case 5:
110              return CBCharacteristicProperties.indicate
111          case 6:
112              return CBCharacteristicProperties.authenticatedSignedWrites
113          case 7:
114              return CBCharacteristicProperties.extendedProperties
115          case 8:
116              return CBCharacteristicProperties.notifyEncryptionRequired
117          case 9:
118              return CBCharacteristicProperties.indicateEncryptionRequired
119          default:
120              return nil
121          }
122      }
123  
124      func toCBAttributePermissions() -> CBAttributePermissions? {
125          switch self {
126          case 0:
127              return CBAttributePermissions.readable
128          case 1:
129              return CBAttributePermissions.writeable
130          case 2:
131              return CBAttributePermissions.readEncryptionRequired
132          case 3:
133              return CBAttributePermissions.writeEncryptionRequired
134          default:
135              return nil
136          }
137      }
138  
139      func toCBATTErrorCode() -> CBATTError.Code {
140          switch self {
141          case 0:
142              return CBATTError.success
143          case 1:
144              return CBATTError.invalidHandle
145          case 2:
146              return CBATTError.readNotPermitted
147          case 3:
148              return CBATTError.writeNotPermitted
149          case 4:
150              return CBATTError.invalidPdu
151          case 5:
152              return CBATTError.insufficientAuthentication
153          case 6:
154              return CBATTError.requestNotSupported
155          case 7:
156              return CBATTError.invalidOffset
157          case 8:
158              return CBATTError.insufficientAuthorization
159          case 9:
160              return CBATTError.prepareQueueFull
161          case 10:
162              return CBATTError.attributeNotFound
163          case 11:
164              return CBATTError.attributeNotLong
165          case 12:
166              return CBATTError.insufficientEncryptionKeySize
167          case 13:
168              return CBATTError.invalidAttributeValueLength
169          case 14:
170              return CBATTError.unlikelyError
171          case 15:
172              return CBATTError.insufficientEncryption
173          case 16:
174              return CBATTError.unsupportedGroupType
175          case 17:
176              return CBATTError.insufficientResources
177          default:
178              return CBATTError.success
179          }
180      }
181  }
182  
183  extension FlutterStandardTypedData {
184      func toData() -> Data {
185          return Data(data)
186      }
187  }
188  
189  extension Data {
190      func toInt64() -> [Int64] {
191          return map { Int64(Int($0)) }
192      }
193  
194      func toFlutterBytes() -> FlutterStandardTypedData {
195          return FlutterStandardTypedData(bytes: self)
196      }
197  }
198  
199  extension [Int64?] {
200      func toData() -> Data {
201          let finalArray = self.compactMap { data in
202              data
203          }
204          return Data(bytes: finalArray, count: finalArray.count)
205      }
206  }