zigbee-herdsman
Version:
An open source ZigBee gateway solution with node.js.
213 lines (188 loc) • 7.87 kB
text/typescript
import {Constants, Frame, Parser, Writer} from "../../../src/adapter/z-stack/unpi";
describe("Parser", () => {
let parser;
let parsed = [];
beforeEach(() => {
parser = new Parser();
parser.on("parsed", (result) => parsed.push(result));
parsed = [];
});
it("Parse simple message", () => {
const buffer = Buffer.from([
0xfe, 0x0e, 0x61, 0x02, 0x02, 0x00, 0x02, 0x06, 0x03, 0xd9, 0x14, 0x34, 0x01, 0x02, 0x00, 0x00, 0x00, 0x00, 0x92,
]);
parser._transform(buffer, "", () => {});
expect(parsed.length).toBe(1);
expect(parsed[0].type).toBe(Constants.Type.SRSP);
expect(parsed[0].subsystem).toBe(Constants.Subsystem.SYS);
expect(parsed[0].commandID).toBe(2);
expect(parsed[0].data).toStrictEqual(Buffer.from([2, 0, 2, 6, 3, 217, 20, 52, 1, 2, 0, 0, 0, 0]));
expect(parsed[0].length).toBe(14);
expect(parsed[0].fcs).toBe(0x92);
});
it("Parse two messages", () => {
const buffer = Buffer.from([
0xfe, 0x0e, 0x61, 0x02, 0x02, 0x00, 0x02, 0x06, 0x03, 0xd9, 0x14, 0x34, 0x01, 0x02, 0x00, 0x00, 0x00, 0x00, 0x92, 0xfe, 0x03, 0x61, 0x08,
0x00, 0x01, 0x55, 0x3e,
]);
parser._transform(buffer, "", () => {});
expect(parsed.length).toBe(2);
expect(parsed[0].type).toBe(Constants.Type.SRSP);
expect(parsed[0].subsystem).toBe(Constants.Subsystem.SYS);
expect(parsed[0].commandID).toBe(2);
expect(parsed[0].data).toStrictEqual(Buffer.from([2, 0, 2, 6, 3, 217, 20, 52, 1, 2, 0, 0, 0, 0]));
expect(parsed[0].length).toBe(14);
expect(parsed[0].fcs).toBe(0x92);
expect(parsed[1].type).toBe(Constants.Type.SRSP);
expect(parsed[1].subsystem).toBe(Constants.Subsystem.SYS);
expect(parsed[1].commandID).toBe(8);
expect(parsed[1].data).toStrictEqual(Buffer.from([0, 1, 85]));
expect(parsed[1].length).toBe(3);
expect(parsed[1].fcs).toBe(0x3e);
});
it("Dont throw error on fcs mismatch", () => {
const buffer = Buffer.from([0xfe, 0x03, 0x61, 0x08, 0x00, 0x01, 0x55, 0x3f]);
parser._transform(buffer, "", () => {});
expect(parsed.length).toBe(0);
});
it("Message in two chunks", () => {
let buffer = Buffer.from([0xfe, 0x03, 0x61, 0x08, 0x00, 0x01]);
parser._transform(buffer, "", () => {});
expect(parsed.length).toBe(0);
buffer = Buffer.from([0x55, 0x3e]);
parser._transform(buffer, "", () => {});
expect(parsed.length).toBe(1);
expect(parsed[0].type).toBe(Constants.Type.SRSP);
expect(parsed[0].subsystem).toBe(Constants.Subsystem.SYS);
expect(parsed[0].commandID).toBe(8);
expect(parsed[0].data).toStrictEqual(Buffer.from([0, 1, 85]));
expect(parsed[0].length).toBe(3);
expect(parsed[0].fcs).toBe(0x3e);
});
it("Message in two chunks, fcs as separate", () => {
let buffer = Buffer.from([0xfe, 0x03, 0x61, 0x08, 0x00, 0x01, 0x55]);
parser._transform(buffer, "", () => {});
expect(parsed.length).toBe(0);
buffer = Buffer.from([0x3e]);
parser._transform(buffer, "", () => {});
expect(parsed.length).toBe(1);
expect(parsed[0].type).toBe(Constants.Type.SRSP);
expect(parsed[0].subsystem).toBe(Constants.Subsystem.SYS);
expect(parsed[0].commandID).toBe(8);
expect(parsed[0].data).toStrictEqual(Buffer.from([0, 1, 85]));
expect(parsed[0].length).toBe(3);
expect(parsed[0].fcs).toBe(0x3e);
});
it("Parse message when it doenst start with SOF and buffer is empty (throw away everything until SOF)", () => {
const buffer = Buffer.from([
95, 27, 37, 254, 3, 69, 196, 212, 23, 0, 65, 254, 27, 68, 129, 0, 0, 8, 0, 212, 23, 1, 1, 0, 55, 0, 153, 178, 219, 0, 0, 7, 8, 122, 10, 0,
0, 32, 243, 212, 23, 29, 160, 254, 7, 69, 196, 111, 244, 2, 122, 155, 246, 95, 87, 254, 27, 68, 129, 0, 0, 6, 0, 111, 244, 1, 1, 0, 118,
0, 245, 236, 220, 0, 0, 7, 8, 2, 10, 0, 0, 16, 0, 246, 95, 27, 85,
]);
parser._transform(buffer, "", () => {});
expect(parsed.length).toBe(4);
expect(parsed[0].type).toBe(Constants.Type.AREQ);
expect(parsed[0].subsystem).toBe(Constants.Subsystem.ZDO);
expect(parsed[0].commandID).toBe(196);
expect(parsed[0].data).toStrictEqual(Buffer.from([0xd4, 0x17, 0x00]));
expect(parsed[0].length).toBe(3);
expect(parsed[0].fcs).toBe(65);
expect(parsed[1].type).toBe(Constants.Type.AREQ);
expect(parsed[1].subsystem).toBe(Constants.Subsystem.AF);
expect(parsed[1].commandID).toBe(129);
expect(parsed[1].data).toStrictEqual(
Buffer.from([0, 0, 8, 0, 212, 23, 1, 1, 0, 55, 0, 153, 178, 219, 0, 0, 7, 8, 122, 10, 0, 0, 32, 243, 212, 23, 29]),
);
expect(parsed[1].length).toBe(27);
expect(parsed[1].fcs).toBe(160);
});
it("Continue parsing on fcs mismatch", () => {
const buffer1 = Buffer.from([
0x01,
0x02,
0xfe,
0x03,
0x61,
0x08,
0x00,
0x01,
0x55,
0x3f, // fcs mismatch
0x08,
0x09,
0x12, // Noise
]);
const buffer2 = Buffer.from([
0x08,
0x09,
0x12, // Noise
]);
const buffer3 = Buffer.from([
0x08,
0x09,
0x12, // Noise
0xfe,
0x0e,
0x61,
0x02, // Valid message part 1
]);
const buffer4 = Buffer.from([
0x02,
0x00,
0x02,
0x06,
0x03,
0xd9,
0x14,
0x34,
0x01,
0x02,
0x00,
0x00,
0x00,
0x00,
0x92, // Valid message part 2
]);
parser._transform(buffer1, "", () => {});
parser._transform(buffer2, "", () => {});
parser._transform(buffer3, "", () => {});
parser._transform(buffer4, "", () => {});
expect(parsed.length).toBe(1);
expect(parsed[0].type).toBe(Constants.Type.SRSP);
expect(parsed[0].subsystem).toBe(Constants.Subsystem.SYS);
expect(parsed[0].commandID).toBe(2);
expect(parsed[0].data).toStrictEqual(Buffer.from([2, 0, 2, 6, 3, 217, 20, 52, 1, 2, 0, 0, 0, 0]));
expect(parsed[0].length).toBe(14);
expect(parsed[0].fcs).toBe(0x92);
});
});
describe("Frame", () => {
it("To buffer", () => {
const frame = new Frame(Constants.Type.SRSP, Constants.Subsystem.SYS, 3, Buffer.from([0x06, 0x01]));
const buffer = frame.toBuffer();
expect(buffer).toStrictEqual(Buffer.from([0xfe, 0x02, 0x61, 0x03, 0x06, 0x01, 0x67]));
});
});
describe("Writer", () => {
let writer;
beforeEach(() => {
writer = new Writer();
});
it("Write frame", () => {
const frame = new Frame(Constants.Type.SRSP, Constants.Subsystem.SYS, 3, Buffer.from([0x06, 0x01]));
const push = vi.spyOn(writer, "push").mockReturnValue(undefined);
writer.writeFrame(frame);
expect(push).toHaveBeenCalledTimes(1);
expect(push.mock.calls[0][0]).toStrictEqual(frame.toBuffer());
});
it("Write buffer", () => {
const buffer = Buffer.from([0x01, 0x02]);
const push = vi.spyOn(writer, "push").mockReturnValue(undefined);
writer.writeBuffer(buffer);
expect(push).toHaveBeenCalledTimes(1);
expect(push.mock.calls[0][0]).toStrictEqual(buffer);
});
it("Read should do nothing (satisfy coverage)", () => {
writer.read();
});
});