Something went wrong. Try again.
[READ-ONLY] Mirror of https://github.com/SantaClaas/embedded-fan-control.
Something went wrong. Try again.
2.4 kB · 73 lines
TypeScript
1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374/** * The CRC-16 every Modbus RTU frame ends with. * * It is the reflected algorithm: polynomial 0xA001 (0x8005 bit-reversed), seeded with 0xFFFF, no * final inversion. On the wire the two bytes go out **low byte first**, which is the opposite * order from every other 16-bit field in the protocol — see `append` and `read`. */
/** * The table costs 512 bytes and turns the per-byte inner loop into one lookup. Built once at * module load rather than written out as a literal, so there is nothing to mistype */const TABLE = /* @__PURE__ */ (() => { const table = new Uint16Array(256);
for (let byte = 0; byte < 256; byte++) { let crc = byte;
for (let bit = 0; bit < 8; bit++) { crc = crc & 1 ? (crc >> 1) ^ 0xa001 : crc >> 1; }
table[byte] = crc; }
return table;})();
/** The CRC of `bytes`, or of the slice `[start, end)` of it */export function crc16(bytes: Uint8Array, start = 0, end = bytes.length): number { let crc = 0xffff;
for (let index = start; index < end; index++) { // The loop bound is the array's own length, so the index is always in range. `!` rather than a // branch that can never be taken const byte = bytes[index]!; crc = (crc >> 8) ^ TABLE[(crc ^ byte) & 0xff]!; }
return crc;}
/** * Whether a whole frame — address, PDU and the two CRC bytes — checks out. * * A frame shorter than four bytes cannot be one: an address, a function code and a CRC is already * four, and there is no function code without at least one more byte after it */export function isValid(frame: Uint8Array): boolean { if (frame.length < 4) return false;
const expected = crc16(frame, 0, frame.length - 2); return expected === read(frame, frame.length - 2);}
/** Reads a CRC from `frame` at `offset`, low byte first */export function read(frame: Uint8Array, offset: number): number { return frame[offset]! | (frame[offset + 1]! << 8);}
/** * Writes the CRC of everything before `offset` into `frame` at `offset`, low byte first. * * Takes the frame with its last two bytes already reserved rather than returning a new array, so * that building a frame is one allocation */export function append(frame: Uint8Array): void { const offset = frame.length - 2; const crc = crc16(frame, 0, offset);
frame[offset] = crc & 0xff; frame[offset + 1] = crc >> 8;}