Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
62 changes: 52 additions & 10 deletions pkg/bluetooth/bluetooth.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,9 +37,16 @@ type Ble struct {
messageInput chan *message.Message
messageOutput chan *message.Message

stopLoop chan bool
device *gatt.Device
central *gatt.Central
stopLoop chan bool
reconnected chan bool
device *gatt.Device
central *gatt.Central

// connGen counts central connections; servingGen is the one the
// message loop was started for. They differ only after a real reconnect.
genMtx sync.Mutex
connGen uint64
servingGen uint64

cmdNotifier gatt.Notifier
cmdNotifierMtx sync.Mutex
Expand Down Expand Up @@ -71,6 +78,7 @@ func New(adapterID string, podId []byte) (*Ble, error) {
cmdOutput: make(chan Packet, 5),
messageInput: make(chan *message.Message, 5),
messageOutput: make(chan *message.Message, 2),
reconnected: make(chan bool, 1),
device: &d,
}

Expand All @@ -79,6 +87,15 @@ func New(adapterID string, podId []byte) (*Ble, error) {
fmt.Println("pkg bluetooth; ** New connection from: ", c.ID())
b.StopMessageLoop()
b.central = &c
b.genMtx.Lock()
b.connGen++
b.genMtx.Unlock()
// Wake any in-flight CommandLoop so it can tear down and
// re-establish a session on this new connection.
select {
case b.reconnected <- true:
default:
}
}),
gatt.CentralDisconnected(func(c gatt.Central) {
log.Tracef("pkg bluetooth; ** disconnect: %s", c.ID())
Expand Down Expand Up @@ -273,16 +290,34 @@ func (b *Ble) ReadMessage() (*message.Message, error) {
return message, nil
}

func (b *Ble) ReadMessageWithTimeout(d time.Duration) (*message.Message, bool) {
select {
case message := <-b.messageInput:
return message, false
case <-time.After(d):
log.Debugf("ReadMessage timeout")
return nil, true
func (b *Ble) ReadMessageWithTimeout(d time.Duration) (*message.Message, bool, bool) {
deadline := time.After(d)
for {
select {
case message := <-b.messageInput:
return message, false, false
case <-b.reconnected:
if b.servingCurrentConnection() {
// Latched while this very connection was being set up
// (pairing retries connect several times). Not a reconnect.
log.Tracef("pkg bluetooth; ignoring stale connect signal")
continue
}
log.Debugf("ReadMessage interrupted by a new connection")
return nil, false, true
case <-deadline:
log.Debugf("ReadMessage timeout")
return nil, true, false
}
}
}

func (b *Ble) servingCurrentConnection() bool {
b.genMtx.Lock()
defer b.genMtx.Unlock()
return b.connGen == b.servingGen
}

func (b *Ble) ShutdownConnection() {
(*b.central).Close()
}
Expand Down Expand Up @@ -312,6 +347,13 @@ func (b *Ble) StartMessageLoop() {
if b.stopLoop != nil {
log.Fatalf("pkg bluetooth; Messaging loop is already running")
}
b.genMtx.Lock()
b.servingGen = b.connGen
b.genMtx.Unlock()
select {
case <-b.reconnected:
default:
}
b.stopLoop = make(chan bool)
go b.loop(b.stopLoop)
}
Expand Down
13 changes: 12 additions & 1 deletion pkg/pod/pod.go
Original file line number Diff line number Diff line change
Expand Up @@ -214,7 +214,18 @@ func (p *Pod) CommandLoop(pMsg PodMsgBody) {
log.Exit(0)
}
log.Infof("pkg pod; *** Waiting for the next command ***")
msg, didTimeout := p.ble.ReadMessageWithTimeout(3 * time.Minute)
msg, didTimeout, didReconnect := p.ble.ReadMessageWithTimeout(3 * time.Minute)
if didReconnect {
// The phone dropped the link and came back. The message loop was
// stopped by the CentralConnected handler, so hand off to a fresh
// StartAcceptingCommands, which restarts it and renegotiates the
// EAP-AKA session over the new connection.
log.Infof("pkg pod; new connection — re-establishing session")
go func() {
p.StartAcceptingCommands()
}()
return
}
if didTimeout {
p.ble.ShutdownConnection()
go func() {
Expand Down
Loading