Skip to content

Commit

Permalink
Add waiting for state change message on CC2531 based adapters during …
Browse files Browse the repository at this point in the history
…initial network initialisation, this is required to allow time for the application to configure, this was a regression caused by introducing CC26X2R1 support. Closes #21.
  • Loading branch information
pwood committed Jan 13, 2021
1 parent 35282bb commit e8df774
Show file tree
Hide file tree
Showing 2 changed files with 86 additions and 5 deletions.
35 changes: 32 additions & 3 deletions adapter_initialise.go
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ func (z *ZStack) Initialise(pctx context.Context, nc zigbee.NetworkConfiguration
}

z.logger.LogInfo(ctx, "Starting Zigbee stack.")
if err := z.startZigbeeStack(ctx); err != nil {
if err := z.startZigbeeStack(ctx, version); err != nil {
return err
}

Expand Down Expand Up @@ -215,10 +215,39 @@ func (z *ZStack) retrieveAdapterAddresses(ctx context.Context) error {
})
}

func (z *ZStack) startZigbeeStack(ctx context.Context) error {
return retry.Retry(ctx, DefaultZStackTimeout, DefaultZStackRetries, func(invokeCtx context.Context) error {
func (z *ZStack) startZigbeeStack(ctx context.Context, version Version) error {
if err := retry.Retry(ctx, DefaultZStackTimeout, DefaultZStackRetries, func(invokeCtx context.Context) error {
return z.requestResponder.RequestResponse(invokeCtx, ZDOStartUpFromAppRequest{StartDelay: 100}, &ZDOStartUpFromAppRequestReply{})
}); err != nil {
return err
}

if version.IsV3() {
return nil
}

ch := make(chan bool, 1)
defer close(ch)

err, cancel := z.subscriber.Subscribe(&ZDOStateChangeInd{}, func(v interface{}) {
stateChange := v.(*ZDOStateChangeInd)

if stateChange.State == DeviceZBCoordinator {
ch <- true
}
})
defer cancel()

if err != nil {
return err
}

select {
case <-ch:
return nil
case <-ctx.Done():
return errors.New("context expired while waiting for adapter start up")
}
}

func (z *ZStack) waitForCoordinatorStart(ctx context.Context) error {
Expand Down
56 changes: 54 additions & 2 deletions adapter_initialise_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -452,7 +452,7 @@ func Test_verifyAdapterNetworkConfig(t *testing.T) {
}

func Test_startZigbeeStack(t *testing.T) {
t.Run("starts zigbee stack and waits for confirmation", func(t *testing.T) {
t.Run("starts zigbee stack for Z-Stack 3.X.X and waits for start response", func(t *testing.T) {
ctx, cancel := context.WithTimeout(context.Background(), 2*time.Second)
defer cancel()

Expand All @@ -467,11 +467,63 @@ func Test_startZigbeeStack(t *testing.T) {
Payload: []byte{0x00},
})

err := zstack.startZigbeeStack(ctx)
err := zstack.startZigbeeStack(ctx, Version{ProductID: 1})
assert.NoError(t, err)

unpiMock.AssertCalls(t)
})

t.Run("starts zigbee stack for Z-Stack 1.2.X and waits for confirmation", func(t *testing.T) {
ctx, cancel := context.WithTimeout(context.Background(), 2*time.Second)
defer cancel()

unpiMock := unpiTest.NewMockAdapter()
zstack := New(unpiMock, NewNodeTable())
defer unpiMock.Stop()

unpiMock.On(SREQ, ZDO, ZDOStartUpFromAppRequestId).Return(Frame{
MessageType: SRSP,
Subsystem: ZDO,
CommandID: ZDOStartUpFromAppRequestReplyID,
Payload: []byte{0x00},
})

go func() {
time.Sleep(50 * time.Millisecond)
unpiMock.InjectOutgoing(Frame{
MessageType: AREQ,
Subsystem: ZDO,
CommandID: ZDOStateChangeIndID,
Payload: []byte{0x09},
})
}()

err := zstack.startZigbeeStack(ctx, Version{ProductID: 0})
assert.NoError(t, err)

unpiMock.AssertCalls(t)
})

t.Run("context timeout for Z-Stack 1.2.X while waiting for state change", func(t *testing.T) {
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Millisecond)
defer cancel()

unpiMock := unpiTest.NewMockAdapter()
zstack := New(unpiMock, NewNodeTable())
defer unpiMock.Stop()

unpiMock.On(SREQ, ZDO, ZDOStartUpFromAppRequestId).Return(Frame{
MessageType: SRSP,
Subsystem: ZDO,
CommandID: ZDOStartUpFromAppRequestReplyID,
Payload: []byte{0x00},
})

err := zstack.startZigbeeStack(ctx, Version{ProductID: 0})
assert.Error(t, err)

unpiMock.AssertCalls(t)
})
}

func Test_waitForCoordinatorStart(t *testing.T) {
Expand Down

0 comments on commit e8df774

Please sign in to comment.