diff --git a/adapter_initialise.go b/adapter_initialise.go index 42d492c..993564e 100644 --- a/adapter_initialise.go +++ b/adapter_initialise.go @@ -15,11 +15,12 @@ func (z *ZStack) Initialise(ctx context.Context, nc zigbee.NetworkConfiguration) z.NetworkProperties.NetworkKey = nc.NetworkKey z.NetworkProperties.Channel = nc.Channel - if err := z.waitForAdapterReset(ctx); err != nil { + version, err := z.waitForAdapterReset(ctx) + if err != nil { return err } - if valid, err := z.verifyAdapterNetworkConfig(ctx); err != nil { + if valid, err := z.verifyAdapterNetworkConfig(ctx, version); err != nil { return err } else if !valid { if err := z.wipeAdapter(ctx); err != nil { @@ -29,10 +30,10 @@ func (z *ZStack) Initialise(ctx context.Context, nc zigbee.NetworkConfiguration) if err := z.makeCoordinator(ctx); err != nil { return err } - } - if err := z.configureNetwork(ctx); err != nil { - return err + if err := z.configureNetwork(ctx, version); err != nil { + return err + } } if err := z.startZigbeeStack(ctx); err != nil { @@ -53,14 +54,19 @@ func (z *ZStack) Initialise(ctx context.Context, nc zigbee.NetworkConfiguration) return nil } -func (z *ZStack) waitForAdapterReset(ctx context.Context) error { - return retry.Retry(ctx, DefaultZStackTimeout, 18, func(invokeCtx context.Context) error { - _, err := z.resetAdapter(invokeCtx, Soft) +func (z *ZStack) waitForAdapterReset(ctx context.Context) (Version, error) { + retVersion := Version{} + + err := retry.Retry(ctx, DefaultZStackTimeout, 18, func(invokeCtx context.Context) error { + version, err := z.resetAdapter(invokeCtx, Soft) + retVersion = version return err }) + + return retVersion, err } -func (z *ZStack) verifyAdapterNetworkConfig(ctx context.Context) (bool, error) { +func (z *ZStack) verifyAdapterNetworkConfig(ctx context.Context, version Version) (bool, error) { configToVerify := []interface{}{ &ZCDNVLogicalType{LogicalType: zigbee.Coordinator}, &ZCDNVPANID{PANID: z.NetworkProperties.PANID}, @@ -108,8 +114,8 @@ func (z *ZStack) makeCoordinator(ctx context.Context) error { }) } -func (z *ZStack) configureNetwork(ctx context.Context) error { - return retryFunctions(ctx, []func(context.Context) error{ +func (z *ZStack) configureNetwork(ctx context.Context, version Version) error { + if err := retryFunctions(ctx, []func(context.Context) error{ func(invokeCtx context.Context) error { return z.writeNVRAM(invokeCtx, ZCDNVSecurityMode{Enabled: 1}) }, @@ -131,18 +137,32 @@ func (z *ZStack) configureNetwork(ctx context.Context) error { func(invokeCtx context.Context) error { return z.writeNVRAM(invokeCtx, ZCDNVExtPANID{ExtendedPANID: z.NetworkProperties.ExtendedPANID}) }, - func(invokeCtx context.Context) error { - return z.writeNVRAM(invokeCtx, ZCDNVUseDefaultTCLK{Enabled: 1}) - }, - func(invokeCtx context.Context) error { - return z.writeNVRAM(invokeCtx, ZCDNVTCLKTableStart{ - Address: zigbee.IEEEAddress(0xffffffffffffffff), - NetworkKey: zigbee.TCLinkKey, - TXFrameCounter: 0, - RXFrameCounter: 0, - }) - }, - }) + }); err != nil { + return err + } + + if !version.IsV3() { + /* Z-Stack 3.X.X has a valid default Trust Centre key, so this is not required. */ + return retryFunctions(ctx, []func(context.Context) error{ + func(invokeCtx context.Context) error { + return z.writeNVRAM(invokeCtx, ZCDNVUseDefaultTCLK{Enabled: 1}) + }, + func(invokeCtx context.Context) error { + return z.writeNVRAM(invokeCtx, ZCDNVTCLKTableStart{ + Address: zigbee.IEEEAddress(0xffffffffffffffff), + NetworkKey: zigbee.TCLinkKey, + TXFrameCounter: 0, + RXFrameCounter: 0, + }) + }, + }) + } else { + /* Z-Stack 3.X.X requires configuration of Base Device Behaviour. */ + + // TODO + + return nil + } } func (z *ZStack) retrieveAdapterAddresses(ctx context.Context) error { diff --git a/adapter_initialise_test.go b/adapter_initialise_test.go index 2441a06..713592e 100644 --- a/adapter_initialise_test.go +++ b/adapter_initialise_test.go @@ -22,14 +22,8 @@ func Test_Initialise(t *testing.T) { defer zstack.Stop() resetResponse, _ := bytecodec.Marshal(SysResetInd{ - Reason: External, - Version: Version{ - TransportRevision: 2, - ProductID: 1, - MajorRelease: 2, - MinorRelease: 3, - HardwareRevision: 4, - }, + Reason: External, + Version: Version{}, }) resetOn := unpiMock.On(AREQ, SYS, SysResetReqID).Return(Frame{ @@ -141,14 +135,8 @@ func Test_Initialise(t *testing.T) { defer zstack.Stop() resetResponse, _ := bytecodec.Marshal(SysResetInd{ - Reason: External, - Version: Version{ - TransportRevision: 2, - ProductID: 1, - MajorRelease: 2, - MinorRelease: 3, - HardwareRevision: 4, - }, + Reason: External, + Version: Version{}, }) resetOn := unpiMock.On(AREQ, SYS, SysResetReqID).Return(Frame{ @@ -158,14 +146,6 @@ func Test_Initialise(t *testing.T) { Payload: resetResponse, }).Times(1) - nvramWriteResponse, _ := bytecodec.Marshal(SysOSALNVWriteReply{Status: ZSuccess}) - nvramOn := unpiMock.On(SREQ, SYS, SysOSALNVWriteID).Return(Frame{ - MessageType: SRSP, - Subsystem: SYS, - CommandID: SysOSALNVWriteReplyID, - Payload: nvramWriteResponse, - }).Times(9) - unpiMock.On(SREQ, SAPI, SAPIZBStartRequestID).Return(Frame{ MessageType: SRSP, Subsystem: SAPI, @@ -252,15 +232,6 @@ func Test_Initialise(t *testing.T) { assert.Equal(t, nc.Channel, zstack.NetworkProperties.Channel) assert.Equal(t, []byte{0x01}, resetOn.CapturedCalls[0].Frame.Payload) - assert.Equal(t, []byte{0x64, 0x00, 0x00, 0x01, 0x1}, nvramOn.CapturedCalls[0].Frame.Payload) - assert.Equal(t, []byte{0x63, 0x00, 0x00, 0x01, 0x1}, nvramOn.CapturedCalls[1].Frame.Payload) - assert.Equal(t, []byte{0x62, 0x00, 0x00, 0x10, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08}, nvramOn.CapturedCalls[2].Frame.Payload) - assert.Equal(t, []byte{0x8f, 0x00, 0x00, 0x01, 0x01}, nvramOn.CapturedCalls[3].Frame.Payload) - assert.Equal(t, []byte{0x84, 0x00, 0x00, 0x04, 0x00, 0x80, 0x00, 0x00}, nvramOn.CapturedCalls[4].Frame.Payload) - assert.Equal(t, []byte{0x83, 0x00, 0x00, 0x02, 0x02, 0x01}, nvramOn.CapturedCalls[5].Frame.Payload) - assert.Equal(t, []byte{0x2d, 0x00, 0x00, 0x08, 0x08, 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01}, nvramOn.CapturedCalls[6].Frame.Payload) - assert.Equal(t, []byte{0x6d, 0x00, 0x00, 0x01, 0x01}, nvramOn.CapturedCalls[7].Frame.Payload) - assert.Equal(t, []byte{0x01, 0x01, 0x00, 0x20, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x5a, 0x69, 0x67, 0x42, 0x65, 0x65, 0x41, 0x6c, 0x6c, 0x69, 0x61, 0x6e, 0x63, 0x65, 0x30, 0x39, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, nvramOn.CapturedCalls[8].Frame.Payload) assert.Equal(t, zigbee.IEEEAddress(0x08090a0b0c0d0e0f), zstack.NetworkProperties.IEEEAddress) assert.Equal(t, zigbee.NetworkAddress(0x0809), zstack.NetworkProperties.NetworkAddress) @@ -312,7 +283,7 @@ func Test_verifyAdapterNetworkConfig(t *testing.T) { chanListFrame, ).Times(4) - valid, err := zstack.verifyAdapterNetworkConfig(ctx) + valid, err := zstack.verifyAdapterNetworkConfig(ctx, Version{}) assert.NoError(t, err) assert.True(t, valid) @@ -363,7 +334,7 @@ func Test_verifyAdapterNetworkConfig(t *testing.T) { chanListFrame, ).Times(4) - valid, err := zstack.verifyAdapterNetworkConfig(ctx) + valid, err := zstack.verifyAdapterNetworkConfig(ctx, Version{}) assert.NoError(t, err) assert.False(t, valid) diff --git a/adapter_reset.go b/adapter_reset.go index f897f1f..f7266d8 100644 --- a/adapter_reset.go +++ b/adapter_reset.go @@ -42,4 +42,8 @@ type Version struct { HardwareRevision uint8 } +func (v Version) IsV3() bool { + return v.ProductID > 0 +} + const SysResetIndID uint8 = 0x80 diff --git a/adapter_reset_test.go b/adapter_reset_test.go index f194fa3..41eee78 100644 --- a/adapter_reset_test.go +++ b/adapter_reset_test.go @@ -91,3 +91,11 @@ func Test_resetAdapter(t *testing.T) { assert.Error(t, err) }) } + +func Test_Version(t *testing.T) { + t.Run("Version.IsV3 returns true if Version.ProductId > 0", func(t *testing.T) { + assert.False(t, Version{ProductID: 0}.IsV3()) + assert.True(t, Version{ProductID: 1}.IsV3()) + assert.True(t, Version{ProductID: 2}.IsV3()) + }) +}