Giter Site home page Giter Site logo

shimmeringbee / zstack Goto Github PK

View Code? Open in Web Editor NEW
26.0 3.0 8.0 201 KB

Implementation of a ZNP and support code designed to interface with Texas Instruments Z-Stack, written in Go.

Home Page: https://shimmeringbee.io/

License: Apache License 2.0

Go 100.00%
cc2531 cc2530 cc253x go znp z-stack zigbee-network-processor

zstack's Issues

Haromnise names of ZStack message structs

The naming of ZStack message stucts is inconsistent. Sometimes the shimmeringbee code has created a "Resp" struct which is the response to a "Req", but ZStack natively calls some async responses "Resp".

Messages should be renamed to be, for example:

SYS_VERSION = SysVersion and SysVersionReply

ZB_BIND_DEVICE = ZbBindDevice/ZbBindDeviceReply
ZB_BIND_CONFIRM = ZbBindConfirm

ZDO_ACTIVE_EP_REQ = ZdoActiveEpReq/ZdoActiveEpReqReply
ZDO_ACTIVE_EP_RSP = ZdoActiveEpResp

That is, when a message is syncronous the name of the SRSP is the same as SREQ, with Reply appended.

Initialize() fails when config is changed (or just generated), but works on second try

Given this code:

netCfg, err := zigbee.GenerateNetworkConfiguration()
if err != nil {
	return err
}

if err := zigbeeComms.Initialise(ctx, netCfg); err != nil {
	return err
}

.. Initialize() fails every time.

If I take what GenerateNetworkConfiguration() gives and type it as static config, Initialize() fails for the first time my process runs (when it notices that some config inside the stick doesn't match what I was given), but if I run my process again, it now starts working. So I guess it has something to do with this branch:

z.logger.LogWarn(ctx, "Adapter network configuration is invalid, resetting adapter.")

IIRC the error message I got was adapter rejected permit join state change: state ... (sorry I don't have the dynamic part of that error message written down..) from here

return fmt.Errorf("adapter rejected permit join state change: state=%v", response.Status)

My hardware/firmware is documented in #20

If End Devices parent is the Coordinator, it may have issues after restart

When some low power End Devices choose the Coordinator as their parent, they may have issues if ZStack is restarted.

This is caused by ZStack requiring resolution of the IEEE address for any event. As the coordinator is responsible for the End Device it is also responsible for knowing their IEEE address. When ZStack restarts the adapter on Initialise it issues a hard reset, this clears the CC2530's child cache (amongst other things).

return z.writeNVRAM(invokeCtx, ZCDNVStartUpOption{StartOption: 0x03})

This is not a problem for Routers as they regularily reintroduce themselves and the mesh network reforms, some End Devices do not, or do so very infrequently.

It is sensible to issue the hard reset when the adapter is being reconfigured to be a different network, however during normal operation (and restarts) we should not hard reset the adapter.

We could take a couple of approaches:

  • Defer this choice to the ZStack consumer.
  • Query the CC2530 for Channel, Network ID, PAN ID, Extended PAN ID and Network Key, if they differ hard reset.

Support CC2652 adapter

Add support for CC2652 based adapters, these use firmware from Koenkk which is based on Z-Stack 3.X.0, because this supporst Zigbee 3.0 there are some differences to the initialisation of the adapter. To do this, we will need to:

  • Query the version of the adapter with SYS_VERSION, alternatively it's also returned in SYS_RESET_IND.

CC2531

(*zstack.SysResetInd)(0xc00000b8f0)({
 Reason: (zstack.ResetReason) 0,
 TransportRevision: (uint8) 2,
 ProductID: (uint8) 0,
 MajorRelease: (uint8) 2,
 MinorRelease: (uint8) 6,
 HardwareRevision: (uint8) 3
})

CC2653

(*zstack.SysResetInd)(0xc000204008)({
 Reason: (zstack.ResetReason) 0,
 TransportRevision: (uint8) 2,
 ProductID: (uint8) 1,
 MajorRelease: (uint8) 2,
 MinorRelease: (uint8) 7,
 HardwareRevision: (uint8) 1
})

zStack 1.2.0 is indicated by 0, 3.x.0 is indiciated by 1 and 3.0.x is indiciated by 2. (No not a typo).

Based upon the SysResetInd.ProductID we can switch initialisation behaviour, if the device does not return a valid version, then assume CC2531 behaviour.

  • If > 1.2.0, when verifying if the network configuration is correct, if the PANID reads as 0xffff, then it is not a failure.
  • If == 3.x.0, then reading the network key uses a different call.
  • If > 1.2.0, during initialisation:
    • the trust centre key does not need to be written (already valid)
    • writing network key is done different.
    • the base device behaviour system must be initialised, with the channel, wait for start, then start comissioning.

Zigbee herdsman implementation can be found here: https://github.com/Koenkk/zigbee-herdsman/blob/master/src/adapter/z-stack/adapter/startZnp.ts

Z-Stack appears to crash on CC2652R

On a large network after an short to medium amount of time the USB stick appears to crash. With two sticks running alongside each other, the network with 50 devices will crash, the stick with 2 devices remains stable.

Looking at zigbee2mqtt's zigbee-herdsman the implementation for znp uses a queue with concurrency limits. Searching their previous issues suggests the crashes can happen due to very busy interaction with the stick.

Our implementation needs to look into a technique to limit concurrency, we could either queue go routines in a queue with a pool of go routines (ala zigbee-herdsman), or some kind of syncronisation mechanism similar to a concurrency limited rwmutex.

Implement initialisation of CC253X adapter

Our initial target for support is the CC253X USB adapters flashed with the zigbee2mqtt.io z-stack coordinator firmware. Thus zstack must be capable of initialising the adapter and starting it in a coordinator role.

Finding documentation on this is a little tricky, so learning from other existing open source tooling out there for the CC253X, we should initialise as follows.

Reset Adapter

	// Reset (SOFT)

	// Perform Configuration and State Reset - NVRAM - ZCD_NV_STARTUP_OPTION (0x0003) 0x03 (Clear State, Clear Config)

	// Reset (SOFT)

	// Set Logical Type as COORDINATOR - NVRAM - ZCD_NV_LOGICAL_TYPE (0x0087) 0x00 (Coordinator) (01 = Router, 02 = End Device)

	// Enable Network Security - NVRAM - ZCD_NV_SECURITY_MODE (0x0064) 0x01 (Enable Security)

	// Enable distribution of network keys - NVRAM - ZCD_NV_PRECFGKEYS_ENABLE (0x0063) 0x01 (Use precfg keys)

	// Set Network Key - NVRAM - ZCD_NV_PRECFGKEY (0x0062) [16]byte (Set network key)

	// Set ZDO Direct Callback - NVRAM - ZCD_NV_ZDO_DIRECT_CB (0x008f) 0x01 (True, Don't write in ZDO_MSG_CB_INCOMING)

	// Set Channels - NVRAM - ZCD_NV_CHANLIST (0x0084) Bitmap (Setting 1 statically uses that, multiple scan least busy)

	// Set PAN ID - NVRAM - ZCD_NV_PANID (0x0083) [2]byte (Set PAN ID)

	// Set Extended PAN ID - NVRAM - ZCD_NV_EXTPANID (0x002d) [8]byte (Set extended PAN ID)

	// Set Enable TC Link Key - NVRAM - ZCD_NV_USE_DEFAULT_TCLK (0x006d) 0x01 (Enable TC Link Key)

	// Set TC Link Key - NVRAM - ZCD_NV_TCLK_TABLE_START (0x0101) [20]byte (Default TC Link, more complex than just key structure)

Fix Channel Selection

The channel selection is either ignored or incorrectly managed, as a network of 15 ended up being around 23.

It could be the bitshift logic does not work correctly.

Add support for querying endpoints.

Add support for registering endpoints, ZDO_SIMPLE_DESC_REQ syncronous, command 0x04.

Add support for registering endpoints, ZDO_SIMPLE_DESC_RSP syncronous, command 0x84.

Implement persistable network address and IEEE address cache

The Z-Stack software on the CC chips maintain a mapping of network address to IEEE addresses (extended addresses) while they are operating, once they reboot this means that they loose the cache (unless they are children of the coordinator, or there is a binding).

The Z-Stack library has been designed around accepting the IEEE address as a destination for packets/commands because they do not change - as such once the CC chip restarts this can result in z-stack not being able to send messages or receiving messages.

Thus zstack needs a network<->IEEE cache which can be presisted between program runs. Like znp it's probably worth abstracting this out to something that can be provided to zstack on start up, and persisted periodically.

Join/leave works but cannot receive a single NodeIncomingMessageEvent

I am able to join/leave devices, but no incoming messages come through when I trigger any of the sensors.

I don't know where to start debugging, I tried to insert logging statements into node_receive_message.go.

func (z *ZStack) startMessageReceiver() {
	log.Println("startMessageReceiver: subscribing")

	_, z.messageReceiverStop = z.subscriber.Subscribe(&AfIncomingMsg{}, func(v interface{}) {
		log.Println("startMessageReceiver: got one")

I got "subscribing" but didn't get a single "got one" message. My code is:

	port, err := serial.Open("/dev/ttyACM0", &serial.Mode{
		BaudRate: 115200, // from TI's docs
	})
	if err != nil {
		return err
	}
	defer port.Close()
	port.SetRTS(true) // "modem status bit RequestToSend"

	nodeTable, err := loadNodeTable()
	if err != nil {
		return err
	}

	saveNodeTableToDisk := func() error {
		return jsonfile.Write(nodeTableFilename, nodeTable.Nodes())
	}

	zigbeeComms := zstack.New(port, nodeTable)
	zigbeeComms.WithGoLogger(logex.Prefix("zigbee", rootLogger))
	defer zigbeeComms.Stop()

	netCfg := zigbee.NetworkConfiguration{ // not my actual details
		PANID:         zigbee.PANID(12345),
		ExtendedPANID: zigbee.ExtendedPANID(1357768367493424001),
		NetworkKey:    zigbee.NetworkKey([16]byte{149, 221, 234, 37, 233, 64, 31, 188, 12, 84, 124, 202, 39, 142, 31, 13}),
		Channel:       15,
	}

	// initialise ZStack and CC253X
	if err := func() error {
		ctx, cancel := context.WithTimeout(ctx, 2*time.Minute)
		defer cancel()

		return zigbeeComms.Initialise(ctx, netCfg)
	}(); err != nil {
		return fmt.Errorf("initialize: %w", err)
	}

	if err := zigbeeComms.PermitJoin(ctx, true); err != nil {
		return fmt.Errorf("PermitJoin: %w", err)
	}

	for {
		event, err := zigbeeComms.ReadEvent(ctx)
		if err != nil {
			return err
		}

		switch e := event.(type) {
		case zigbee.NodeJoinEvent:
			logl.Info.Printf("JOIN: %v\n", e.Node)
			go exploreDevice(zigbeeComms, e.Node)
		case zigbee.NodeLeaveEvent:
			logl.Info.Printf("LEAVE: %v\n", e.Node)
		case zigbee.NodeUpdateEvent: // this gets fired every 30s regardless of network activity
			logl.Debug.Printf("UPDATE: %v\n", e.Node)

			// it's a good trigger to update the node table
			// TODO: detect if we have changes
			if err := saveNodeTableToDisk(); err != nil {
				return err
			}
		case zigbee.NodeIncomingMessageEvent:
			logl.Debug.Printf("MSG: %v\n", e)
		default:
			logl.Error.Println("got unrecognized event")
		}
	}
}

I'm running CC2531 with the recommended firmware, I flashed the dongle just to be sure. It works out-of-the-box with https://github.com/dyrkin/zigbee-steward

Initialisation fails on linux/arm7

While trying to run code using zstack on a Raspberry Pi 3, initialisation fails, where as the same configuration works on an AMD64 architectured machine.

This could be to do with different sizes of int on the different platforms, they are the same endian so thankfull doesn't appear to be a byte order issue.

This issue may also effect ZCL, bytecodec or unpi.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.