-
Notifications
You must be signed in to change notification settings - Fork 172
macos: initial support for scanning/connecting/write characteristics/notifications #7
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from all commits
Commits
Show all changes
12 commits
Select commit
Hold shift + click to select a range
105d50a
macos: starting point for adding macOS support
deadprogram 2791776
macos: able to retrieve some of the info when scanning
deadprogram 7a1e1f6
all: use Addresser interface to handle fact that macOS uses UUID inst…
deadprogram 35de6ef
windows: use Addresser interface for the MAC address for a peripheral
deadprogram a5ff736
docs: show that we can now scan on macOS
deadprogram 7cc099d
macos: completed initial implementation
deadprogram 0a7f003
macos: able to discover services and characteristics for a device
deadprogram be4168e
gap: switch to use MACAddress struct when possible for shared impleme…
deadprogram b5b4c68
macos: remove unneeded functions to export internal implementaions.
deadprogram f789e84
macos: added characteristic notifications
deadprogram c245754
gap: correct use of Address on Linux platform
deadprogram b80b918
docs: better explanation of peripheral UUID on macOS
deadprogram File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,124 @@ | ||
package bluetooth | ||
|
||
import ( | ||
"errors" | ||
"time" | ||
|
||
"github.com/JuulLabs-OSS/cbgo" | ||
) | ||
|
||
// Adapter is a connection to BLE devices. | ||
type Adapter struct { | ||
cmd *centralManagerDelegate | ||
pmd *peripheralManagerDelegate | ||
|
||
cm cbgo.CentralManager | ||
pm cbgo.PeripheralManager | ||
|
||
peripheralFoundHandler func(*Adapter, ScanResult) | ||
scanChan chan error | ||
poweredChan chan error | ||
connectChan chan cbgo.Peripheral | ||
} | ||
|
||
// DefaultAdapter is the default adapter on the system. | ||
// | ||
// Make sure to call Enable() before using it to initialize the adapter. | ||
var DefaultAdapter = &Adapter{ | ||
cm: cbgo.NewCentralManager(nil), | ||
pm: cbgo.NewPeripheralManager(nil), | ||
connectChan: make(chan cbgo.Peripheral), | ||
} | ||
|
||
// Enable configures the BLE stack. It must be called before any | ||
// Bluetooth-related calls (unless otherwise indicated). | ||
func (a *Adapter) Enable() error { | ||
if a.poweredChan != nil { | ||
return errors.New("already calling Enable function") | ||
} | ||
|
||
// wait until powered | ||
a.poweredChan = make(chan error) | ||
|
||
a.cmd = ¢ralManagerDelegate{a: a} | ||
a.cm.SetDelegate(a.cmd) | ||
select { | ||
case <-a.poweredChan: | ||
case <-time.NewTimer(10 * time.Second).C: | ||
return errors.New("timeout enabling CentralManager") | ||
} | ||
a.poweredChan = nil | ||
|
||
// wait until powered? | ||
a.pmd = &peripheralManagerDelegate{a: a} | ||
a.pm.SetDelegate(a.pmd) | ||
|
||
return nil | ||
} | ||
|
||
// CentralManager delegate functions | ||
|
||
type centralManagerDelegate struct { | ||
cbgo.CentralManagerDelegateBase | ||
|
||
a *Adapter | ||
} | ||
|
||
// CentralManagerDidUpdateState when central manager state updated. | ||
func (cmd *centralManagerDelegate) CentralManagerDidUpdateState(cmgr cbgo.CentralManager) { | ||
// powered on? | ||
if cmgr.State() == cbgo.ManagerStatePoweredOn { | ||
close(cmd.a.poweredChan) | ||
} | ||
|
||
// TODO: handle other state changes. | ||
} | ||
|
||
// DidDiscoverPeripheral when peripheral is discovered. | ||
func (cmd *centralManagerDelegate) DidDiscoverPeripheral(cmgr cbgo.CentralManager, prph cbgo.Peripheral, | ||
advFields cbgo.AdvFields, rssi int) { | ||
if cmd.a.peripheralFoundHandler != nil { | ||
sr := makeScanResult(prph, advFields, rssi) | ||
cmd.a.peripheralFoundHandler(cmd.a, sr) | ||
} | ||
} | ||
|
||
// DidConnectPeripheral when peripheral is connected. | ||
func (cmd *centralManagerDelegate) DidConnectPeripheral(cmgr cbgo.CentralManager, prph cbgo.Peripheral) { | ||
// Unblock now that we're connected. | ||
cmd.a.connectChan <- prph | ||
} | ||
|
||
// makeScanResult creates a ScanResult when peripheral is found. | ||
func makeScanResult(prph cbgo.Peripheral, advFields cbgo.AdvFields, rssi int) ScanResult { | ||
uuid, _ := ParseUUID(prph.Identifier().String()) | ||
|
||
var serviceUUIDs []UUID | ||
for _, u := range advFields.ServiceUUIDs { | ||
parsedUUID, _ := ParseUUID(u.String()) | ||
serviceUUIDs = append(serviceUUIDs, parsedUUID) | ||
} | ||
|
||
// Peripheral UUID is randomized on macOS, which means to | ||
// different centrals it will appear to have a different UUID. | ||
return ScanResult{ | ||
RSSI: int16(rssi), | ||
Address: Address{ | ||
UUID: uuid, | ||
}, | ||
AdvertisementPayload: &advertisementFields{ | ||
AdvertisementFields{ | ||
LocalName: advFields.LocalName, | ||
ServiceUUIDs: serviceUUIDs, | ||
}, | ||
}, | ||
} | ||
} | ||
|
||
// PeripheralManager delegate functions | ||
|
||
type peripheralManagerDelegate struct { | ||
cbgo.PeripheralManagerDelegateBase | ||
|
||
a *Adapter | ||
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.