UNPKG

zigbee-herdsman

Version:

An open source ZigBee gateway solution with node.js.

248 lines (201 loc) 5.78 kB
/* v8 ignore start */ import {logger} from "../../../utils/logger"; import {EZSP_MAX_FRAME_LENGTH} from "../ezsp/consts"; const NS = "zh:ember:uart:queues"; /** * Buffer to hold a DATA frame. * Allocates `data` to `EZSP_MAX_FRAME_LENGTH` filled with zeroes. */ export class EzspBuffer { /** uint8_t[EZSP_MAX_FRAME_LENGTH] */ public data: Buffer; public link?: EzspBuffer; /** uint8_t */ public len: number; constructor() { this.data = Buffer.alloc(EZSP_MAX_FRAME_LENGTH); // inits to all-zeroes this.link = undefined; this.len = 0; } } /** * Simple queue (singly-linked list) */ export class EzspQueue { public tail?: EzspBuffer; constructor() { this.tail = undefined; } /** * Get the number of buffers in the queue. * @returns */ get length(): number { let head = this.tail; let count = 0; for (count; head !== undefined; count++) { head = head.link; } return count; } get empty(): boolean { return this.tail === undefined; } /** * Get a pointer to the buffer at the head of the queue. * @returns */ get head(): EzspBuffer { let head = this.tail; if (head === undefined) { throw new Error("Tried to get head from an empty queue."); } while (head.link !== undefined) { head = head.link; } return head; } /** * Get a pointer to the Nth entry in the queue (the tail corresponds to N = 1). * * @param n * @returns */ public getNthEntry(n: number): EzspBuffer | undefined { if (n === 0) { throw new Error("Asked for 0th element in queue."); } let buf = this.tail; while (--n) { if (buf === undefined) { throw new Error("Less than N entries in queue."); } buf = buf.link; } return buf; } /** * Get a pointer to the entry before the specified entry (closer to the tail). * If the buffer specified is undefined, the head entry is returned. * If the buffer specified is the tail, undefined is returned. * @param entry The buffer to look before. * @returns */ public getPrecedingEntry(entry?: EzspBuffer): EzspBuffer | undefined { let buf = this.tail; if (buf === entry) { return undefined; } if (buf === undefined) { throw new Error("Tried to get preceding entry from an empty queue."); } do { if (buf.link === entry) { return buf; } buf = buf.link; } while (buf !== undefined); throw new Error("Buffer not in queue."); } /** * Add a buffer to the tail of the queue. * @param buf */ public addTail(buf: EzspBuffer): void { if (buf) { buf.link = this.tail; this.tail = buf; } else { throw new Error("Called addTail with undefined buffer"); } } /** * Remove the buffer at the head of the queue. * @returns The removed buffer. */ public removeHead(): EzspBuffer { let head = this.tail; if (head === undefined) { throw new Error("Tried to remove head from an empty queue."); } if (head.link === undefined) { this.tail = undefined; } else { let prev: EzspBuffer; do { prev = head; head = head.link; } while (head.link !== undefined); prev.link = undefined; } return head; } /** * Remove the specified entry from the queue. * @param entry * @returns A pointer to the preceding entry (if any). */ public removeEntry(entry: EzspBuffer): EzspBuffer | undefined { const buf = this.getPrecedingEntry(entry); if (buf !== undefined) { buf.link = entry.link; } else { this.tail = entry.link; } return buf; } } /** * Simple free list (singly-linked list) */ export class EzspFreeList { public link?: EzspBuffer; constructor() { this.link = undefined; } /** * Get the number of buffers in the free list. * @returns */ get length(): number { let next = this.link; let count = 0; for (count; next !== undefined; count++) { next = next.link; } return count; } /** * Add a buffer to the free list. * @param buf */ public freeBuffer(buf: EzspBuffer): void { if (buf) { buf.link = this.link; this.link = buf; } else { throw new Error("Called freeBuffer with undefined buffer"); } } /** * Get a buffer from the free list. * @returns */ public allocBuffer(): EzspBuffer | undefined { const buf = this.link; if (buf !== undefined) { this.link = buf.link; buf.len = 0; if (buf.data.length !== EZSP_MAX_FRAME_LENGTH) { // should never happen if buffers are handled properly, but just in case, re-alloc to max length buf.data = Buffer.alloc(EZSP_MAX_FRAME_LENGTH); const e = new Error(); logger.error(`Pre-allocated buffer had improper size and had to be re-allocated. ${e.stack}`, NS); } else { // (void) memset(buffer->data, 0, EZSP_MAX_FRAME_LENGTH); buf.data.fill(0); } } return buf; } }