The Z-Stick does bi-directional communication over a UART. The connection speed is 115200, '8N1'. There are "requests" and "responses". The client software can make requests to the Z-Stick, and it will send responses. But it seems the Z-Stick can make requests of the client software too. I have yet to figure out the requests the Z-Stick sends to the client software.
There are 4 types of packets, SOF
, ACK
, NAK
, and CAN
. SOF
packets
wrap a request or a response. ACK
and NAK
are used to acknowledge or reject
a packet respectively. CAN
means "send again".
SOF
requests have a variable number of bytes. ACK
, NAK
, and CAN
are one
byte.
SOF
requests look like this (they are variable width, but always start with
0x01
and end with a CRC):
00 04 08 0C
-----------------------------------------------
0000 01 01 00 00 00 .....
| | | | CRC
ACK
looks like this (it's just 0x06):
00 04 08 0C
-----------------------------------------------
0000 06
NAK
looks like this (it's just 0x15):
00 04 08 0C
-----------------------------------------------
0000 15
I haven't figured out how to use CAN
yet, but I think it's just one byte:
00 04 08 0C
-----------------------------------------------
0000 18
Requests and responses are wrapped in a SOF
. The second byte is the length of
the packet. The third byte is whether the packet is a request or response.
Request is 0x00
, response is 0x01
. The final byte is a CRC.
The CRC is is an XOR of all bytes except the first SOF
and request / response
byte, where the CRC starts with 0xFF. Here is pseudo code for calculating the
CRC byte:
crc = 0xFF
for byte in bytes
crc = crc ^ byte
end
return crc
For example, to send 2 bytes 0x01 and 0x04, the length will be 3 (to take in to
account the CRC byte) and the bytes
list in the above example will be
[0x03, 0x01, 0x04], and the CRC will be 0xF9.
Sample request:
00 04 08 0C
-----------------------------------------------
0000 01 03 00 15 e9
a b c d e
a: SOF
b: Length
c: Request
d: Function (In this case "get version" request)
e: CRC
The first byte is SOF
, second byte is the length including CRC byte, the
third byte indicates if this is a request or a response, the fourth byte
indicates the function we are requesting (in this case asking for the version of
the Z stick) and the final byte is a CRC.
After sending a properly formed request, the stick will respond with an ACK
byte. Eventually it will send a response with a function number that is the
same as the function number in the request packet the client software made. The
client software must then send an ACK
to acknowledge receipt of the response.
Here is a sample response, in response to the above request:
00 04 08 0C
-----------------------------------------------
0000 01 10 01 15 5a 2d 57 61 76 65 20 33 2e 39 35 00
a b c d [e
0010 01 99
] f
a: SOF
b: Length
c: Response
d: Function (In this case "get version" response)
e: Response data
f: CRC
This sample response packet is a response to a "get version" request. The decoded response data is "Z-Wave 3.95\x00\x01". In this case, the response is a string, and it looks like the stick assumes client applications deal with null padded strings.
This is a sample of a successful "get version" request. The client software first makes a request, the stick ACKs the request, the stick sends a response, then the client software ACKs the response:
Step 1, Initial request client software:
00 04 08 0C
-----------------------------------------------
0000 01 03 00 15 e9
a b c d e
a: SOF
b: Length
c: Request
d: Function (In this case "get version" request)
e: CRC
Step 2, ACK from stick:
00 04 08 0C
-----------------------------------------------
0000 06
a
a: ACK
Step 3, response from stick:
00 04 08 0C
-----------------------------------------------
0000 01 10 01 15 5a 2d 57 61 76 65 20 33 2e 39 35 00
a b c d [e
0010 01 99
] f
a: SOF
b: Length
c: Response
d: Function (In this case "get version" response)
e: Response data
f: CRC
Step 4, ACK from client software:
00 04 08 0C
-----------------------------------------------
0000 06
a
a: ACK
require 'uart'
require 'io/wait'
SOF = 0x01
ACK = 0x06
REQUEST = 0x00
RESPONSE = 0x01
GET_VERSION = 0x15
def crc buf
buf.inject(0xFF) { |check, byte| check ^ byte }
end
UART.open ARGV[0], 115200, '8N1' do |uart|
uart.wait_writable
req = [0x03, REQUEST, GET_VERSION]
uart.write SOF.chr # Send SOF
uart.write req.pack('C3') # Write packet
uart.write crc(req).chr # Write CRC
loop do
uart.wait_readable
packet_type = uart.read(1).bytes.first
case packet_type
when ACK then puts "Got ACK"
when SOF then
len = uart.read(1).bytes.first
packet = uart.read(len).bytes
request_or_response = packet.shift
if request_or_response == RESPONSE
crc = packet.pop
if crc == crc([len, request_or_response] + packet)
# Send an ACK if the CRC is correct
uart.write ACK.chr
function = packet.shift
if function == GET_VERSION
puts "Version: #{packet.pack('C*')}"
break
else
puts "Got a non-get version response!"
end
else
puts "Bad CRC!"
end
else
puts "Got a request!"
end
else
puts "Unknown #{sprintf("%02x", packet_type)}"
end
end
end
The CAN frame indicates that the receiving end discarded an otherwise valid Data frame. The CAN frame is used to resolve race conditions, where both ends send a Data frame and subsequently expects an ACK frame from the other end.
If a Z-Wave chip expects to receive an ACK frame but receives a Data frame from the host, the Z-Wave chip SHOULD return a CAN frame. A host which receives a CAN frame MUST consider the dataframe lost. The host MUST wait for a period before retransmitting the Data frame.