Skip to content

Commit

Permalink
Add characteristic
Browse files Browse the repository at this point in the history
  • Loading branch information
colemancda committed Nov 20, 2024
1 parent 71c8c56 commit e9a88e4
Show file tree
Hide file tree
Showing 5 changed files with 118 additions and 38 deletions.
19 changes: 13 additions & 6 deletions Sources/NimBLE/GAP.swift
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,13 @@ public extension NimBLE {
/// NimBLE GAP interface.
public struct GAP {

internal struct Context {

var advertisment = LowEnergyAdvertisingData()

var scanResponse = LowEnergyAdvertisingData()
}

internal let context: UnsafeMutablePointer<NimBLE.Context>

/// Indicates whether an advertisement procedure is currently in progress.
Expand Down Expand Up @@ -47,25 +54,25 @@ public struct GAP {
}

public var advertisementData: LowEnergyAdvertisingData {
context.pointee.advertisment
context.pointee.gap.advertisment
}

/// Configures the data to include in subsequent advertisements.
public func setAdvertisement(_ data: LowEnergyAdvertisingData) throws(NimBLEError) {
context.pointee.advertisment = data
try context.pointee.advertisment.withUnsafePointer {
context.pointee.gap.advertisment = data
try context.pointee.gap.advertisment.withUnsafePointer {
ble_gap_adv_set_data($0, Int32(data.length))
}.throwsError()
}

public var scanResponse: LowEnergyAdvertisingData {
context.pointee.scanResponse
context.pointee.gap.scanResponse
}

/// Configures the data to include in subsequent scan responses.
public func setScanResponse(_ data: LowEnergyAdvertisingData) throws(NimBLEError) {
context.pointee.scanResponse = data
try context.pointee.scanResponse.withUnsafePointer {
context.pointee.gap.scanResponse = data
try context.pointee.gap.scanResponse.withUnsafePointer {
ble_gap_adv_rsp_set_data($0, Int32(data.length))
}.throwsError()
}
Expand Down
90 changes: 72 additions & 18 deletions Sources/NimBLE/GATTServer.swift
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@

import Bluetooth
import BluetoothGATT
//import GATT
import GATT
import CNimBLE

public extension NimBLE {
Expand All @@ -18,24 +18,45 @@ public extension NimBLE {
/// NimBLE GATT Server interface.
public struct GATTServer {

nonisolated(unsafe) private static var services = [ble_gatt_svc_def]()

nonisolated(unsafe) private static var buffers = [[UInt8]]()
internal struct Context {

var services = [ble_gatt_svc_def]()

var characteristics = [ble_gatt_chr_def]()

var buffers = [[UInt8]]()

/// Callback to handle GATT read requests.
var willRead: ((GATTReadRequest<Central, [UInt8]>) -> ATTError?)?

/// Callback to handle GATT write requests.
var willWrite: ((GATTWriteRequest<Central, [UInt8]>) -> ATTError?)?

/// Callback to handle post-write actions for GATT write requests.
var didWrite: ((GATTWriteConfirmation<Central, [UInt8]>) -> ())?
}

// MARK: - Properties

internal let context: UnsafeMutablePointer<NimBLE.Context>

/*
/// Callback to handle GATT read requests.
public var willRead: ((GATTReadRequest<Central>) -> ATTError?)?
public var willRead: ((GATTReadRequest<Central, [UInt8]>) -> ATTError?)? {
get { context.pointee.gattServer.willRead }
set { context.pointee.gattServer.willRead = newValue }
}

/// Callback to handle GATT write requests.
public var willWrite: ((GATTWriteRequest<Central>) -> ATTError?)?
public var willWrite: ((GATTWriteRequest<Central, [UInt8]>) -> ATTError?)? {
get { context.pointee.gattServer.willWrite }
set { context.pointee.gattServer.willWrite = newValue }
}

/// Callback to handle post-write actions for GATT write requests.
public var didWrite: ((GATTWriteConfirmation<Central>) -> ())?
*/
public var didWrite: ((GATTWriteConfirmation<Central, [UInt8]>) -> ())? {
get { context.pointee.gattServer.didWrite }
set { context.pointee.gattServer.didWrite = newValue }
}

// MARK: - Methods

Expand All @@ -47,9 +68,10 @@ public struct GATTServer {
public func add(services: [GATTAttribute<[UInt8]>.Service]) throws(NimBLEError) {
var cServices = [ble_gatt_svc_def].init(repeating: .init(), count: services.count + 1)
var buffers = [[UInt8]]()
// TODO: Free memory
for (serviceIndex, service) in services.enumerated() {
// set type
cServices[serviceIndex].type = service.isPrimary ? UInt8(BLE_GATT_SVC_TYPE_PRIMARY) : UInt8(BLE_GATT_SVC_TYPE_SECONDARY)
// set uuid
let serviceUUID = ble_uuid_any_t(service.uuid)
withUnsafeBytes(of: serviceUUID) {
let buffer = [UInt8]($0)
Expand All @@ -59,15 +81,34 @@ public struct GATTServer {
}
}
assert(ble_uuid_any_t(cServices[serviceIndex].uuid) == serviceUUID)
//assert(serviceUUID.dataLength == service.uuid.dataLength)
}
try withExtendedLifetime(buffers) { _ throws(NimBLEError) -> () in
try ble_gatts_count_cfg(cServices).throwsError()
try ble_gatts_add_svcs(cServices).throwsError()
assert(serviceUUID.dataLength == service.uuid.dataLength)
// add characteristics
var cCharacteristics = [ble_gatt_chr_def].init(repeating: .init(), count: service.characteristics.count + 1)
for (characteristicIndex, characteristic) in service.characteristics.enumerated() {
// set callback
cCharacteristics[characteristicIndex].access_cb = _ble_gatt_access
// set UUID
let characteristicUUID = ble_uuid_any_t(characteristic.uuid)
withUnsafeBytes(of: characteristicUUID) {
let buffer = [UInt8]($0)
buffers.append(buffer)
buffer.withUnsafeBytes {
cCharacteristics[characteristicIndex].uuid = .init(OpaquePointer($0.baseAddress))
}
}
}
cCharacteristics.withUnsafeBufferPointer {
cServices[serviceIndex].characteristics = $0.baseAddress
}
self.context.pointee.gattServer.characteristics = cCharacteristics
}
//try ble_gatts_start().throwsError()
Self.services = cServices
Self.buffers = buffers
// queue service registration
try ble_gatts_count_cfg(cServices).throwsError()
try ble_gatts_add_svcs(cServices).throwsError()
// store buffers
cServices.removeLast() // nil terminator
self.context.pointee.gattServer.services = cServices
self.context.pointee.gattServer.buffers = buffers
}

/// Removes the service with the specified handle.
Expand All @@ -78,9 +119,22 @@ public struct GATTServer {
/// Clears the local GATT database.
public func removeAllServices() {
ble_gatts_reset()
self.context.pointee.gattServer.buffers.removeAll()
self.context.pointee.gattServer.services.removeAll()
}

public func dump() {
ble_gatts_show_local()
}
}

// typedef int ble_gatt_access_fn(uint16_t conn_handle, uint16_t attr_handle, struct ble_gatt_access_ctxt *ctxt, void *arg);
internal func _ble_gatt_access(
conn_handle: UInt16,
attr_handle: UInt16,
accessContext: UnsafeMutablePointer<ble_gatt_access_ctxt>?,
context: UnsafeMutableRawPointer?
) -> CInt {

return 0
}
19 changes: 10 additions & 9 deletions Sources/NimBLE/NimBLE.swift
Original file line number Diff line number Diff line change
Expand Up @@ -37,23 +37,24 @@ public struct NimBLE: ~Copyable {
nimble_port_run()
}

public func run(while body: () -> (Bool)) {
let time = ble_npl_time_t(BLE_NPL_TIME_FOREVER)
let dflt = nimble_port_get_dflt_eventq()
while body() {
let event = ble_npl_eventq_get(dflt, time)
ble_npl_event_run(event)
}
}
}

internal extension NimBLE {

struct Context {

var advertisment = LowEnergyAdvertisingData()

var scanResponse = LowEnergyAdvertisingData()
var gap = GAP.Context()

/// Callback to handle GATT read requests.
//public var willRead: ((GATTReadRequest<Central>) -> ATTError?)?
var gattServer = GATTServer.Context()

/// Callback to handle GATT write requests.
//public var willWrite: ((GATTWriteRequest<Central>) -> ATTError?)?

/// Callback to handle post-write actions for GATT write requests.
//public var didWrite: ((GATTWriteConfirmation<Central>) -> ())?
}
}
12 changes: 10 additions & 2 deletions Sources/NimBLEDemo/NimBLEDemo.swift
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,16 @@ struct NimBLEDemo {
uuid: .bit16(0x180A),
isPrimary: true,
characteristics: [

]
.init(
uuid: .manufacturerNameString,
value: Array("Test Inc.".utf8),
permissions: [.read],
properties: [.read],
descriptors: [
.init(GATTUserDescription(rawValue: "Manufacturer Name String"), permissions: .read)
]
)
]
)
try server.add(services: [service])
try server.start()
Expand Down
16 changes: 13 additions & 3 deletions Tests/NimBLETests/GATTServerTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
// Created by Alsey Coleman Miller on 11/9/24.
//

import Foundation
import Testing
import Bluetooth
import BluetoothGATT
Expand All @@ -21,11 +22,20 @@ struct GATTServerTests {
let service = GATTAttribute<[UInt8]>.Service(
uuid: .bit16(0x180A),
isPrimary: true,
characteristics: []
characteristics: [
.init(
uuid: .manufacturerNameString,
value: Array("Test Inc.".utf8),
permissions: [.read],
properties: [.read],
descriptors: [
.init(GATTUserDescription(rawValue: "Manufacturer Name String"), permissions: .read)
]
)
]
)
try server.add(services: [service])
try ble_gatts_start().throwsError()
try server.start()
server.dump()
try ble_gatts_reset().throwsError()
}
}

0 comments on commit e9a88e4

Please sign in to comment.