bin

Allocate, pack, and parse binary buffers used by Modbus, EtherNet/IP, MQTT and crypto.

The bin object converts between JavaScript numbers/arrays and the packed binary buffers used across the protocol and crypto APIs.

Data types. Valid types for packing and unpacking:

Type Meaning
F32 IEEE 754 single-precision float
F64 IEEE 754 double-precision float
BITS Single-bit array
RBITS Reverse-bit-order single-bit array
U8 / S8 Unsigned / signed 8-bit integer (0…255 / −128…127)
U16 / S16 Unsigned / signed 16-bit integer (0…65,535 / −32,768…32,767)
U32 / S32 Unsigned / signed 32-bit integer

Byte order defaults to ABCD if not specified. It can be given as a suffix on the format ("F32BADC", "U32DCBA", "U16AB") or as a separate argument — AB (16-bit) and ABCD, BADC, DCBA, CDAB (32-bit) cover the big-endian, little-endian and word-swapped layouts found across Modbus devices. Bit types (BITS/RBITS) take no byte order.

Round trips. bin.fromArraybin.toArray convert between arrays and packed binary; bin.toHexbin.fromHex convert between binary and hex text — see the Binary Packing, Bits & Hex example.

Buffer objects returned by bin.alloc(), modbus.read().data and eip.read().data carry their own cursor-based methods:

  • buffer.seek(byte) — set the cursor position.
  • buffer.read(format, [count]) — read one value (or an array of count values) and advance.
  • buffer.write(format, value | array) — write a value or array and advance.

Functions

bin.alloc()

bin.alloc(bytes) → buffer

Allocates a empty buffer (string) that can be used to store and read binary values.

Creates an empty string bytes long. String objects in mJS are byte strings, so they can hold arbitrary binary data — null characters do not terminate them. After any call to bin.alloc() the binary read/write cursor is automatically positioned at the start of the new buffer.

Arguments

NameTypeRequiredDefaultDescription
bytes number yes Buffer size in bytes — 4 bytes per 32-bit register/float.

Returns

string A buffer with seek/read/write methods, cursor positioned at byte 0.

Example

let mbData = bin.alloc(20*4); // room for 20 float registers
modbus.setData(mbData); // Assign the data buffer for to modbus read and write requests.

while(run()){


mbData.write("F32ABCD",75); // Write a float32 (4 bytes) to our modbus data table
waitMS(1000);

}

buffer.seek() / .read() / .write()

buffer.seek(byte)  ·  buffer.read(format, [count])  ·  buffer.write(format, value|array)

Tools to store and read binary data structures.

There is only one string type in mJS which is used to store either textual strings or raw byte buffers.

Payload data returned from RS485 reads, CANBus messages, Http requests, Modbus Queries etc can all be directly parsed into regular numbers easily with these methods.

seek(byte) sets the position (byte 0 = start). (Always call this before .read() or .write()) read(format) returns one value; read(format, count) returns an array of count values. The cursor advances. write(format, value) writes one value; write(format, array) appends the whole array. The cursor advances. The "BIT" format packs elements of 1/0 (or boolean) values into bits — see eip.handle() for a worked status-word example.

  • seek(byte) sets the position (byte 0 = start).
  • read(format) returns one value; read(format, count) returns an array of count values. The cursor advances.
  • write(format, value) writes one value. The cursor advances.
  • write(format, array) appends the whole array. The cursor advances.

The "BIT" format can be used to work with individual bits which could be provided as an array of 1/0(or boolean) or individual values — seeeip.handle()` for a worked status-word example.

Arguments

NameTypeRequiredDefaultDescription
format string yes Format string, e.g. "F32BADC", "U32DCBA".
count / value number | array optional read: how many values to return. write: the value or array to pack.

Example

while(run()){

let data = bin.alloc(8); // allocate a 8 byte buffer

print(bin.toHex(data)); // print the hex for data "0000000000000000"
  
// Write some data to the buffer

data.seek(1); // Set our read/write pointer to start on the second byte
data.write("U8", 255);       // Write a single unsigned 8 with value 255
data.write("U8", [0,1,2,3]);       // Write an array of values as unsigned 8

print(bin.toHex(data)); // print the hex for data "00ff000102030000"
  
  
// Read some data back from the buffer

data.seek(1); // Set the read/write cursor position
print(  data.read("U8") ); // "255"
print( string ( data.read("U8",4) ) ); // "[0,1,2,3]"


waitMS(1000);
  


}

bin.fromArray()

bin.fromArray(array, format, [byteOrder]) → buffer

Packs an array of numbers or bits into a binary buffer.

Packs an array into binary data. For bit types ("BITS"/"RBITS") the array holds 1/0 (or true/false) entries — 16 bits pack into two bytes. The inverse is bin.toArray().

Arguments

NameTypeRequiredDefaultDescription
array array yes Values to pack — numbers, or 1/0 / true/false for bit types.
format string yes Element type: "F32", "F64", "BITS", "RBITS", "U8", "S8", "U16", "S16", "U32", "S32".
byteOrder string optional "ABCD" Byte order, e.g. "AB", "ABCD", "BADC", "DCBA", "CDAB". Not used by bit types.

Returns

buffer Packed binary data ready for modbus.write(), mqtt.publish() or hex conversion.

Example

let data = bin.fromArray([1,2,3,4,5,6,7,8], "U16", "AB");
modbus.write(0, 1, 16, 0, 8, data);

// pack floats, word-swapped
let bytes = bin.fromArray([12345.6789, 100, 200], "F32", "BADC");

// pack a bit array (two bytes)
let flags = bin.fromArray([1,0,0,0,0,0,0,0, 0,1,1,1,1,1,1,1], "RBITS");

bin.toArray()

bin.toArray(data, format, [byteOrder]) → array

Unpacks binary data into an array of numbers or bits.

The inverse of bin.fromArray() — interprets packed binary data as an array of the given type. Use it on data from bin.fromHex(), Modbus reads or MQTT binary messages.

Arguments

NameTypeRequiredDefaultDescription
data buffer | binary yes The packed binary data to unpack.
format string yes Element type — same set as bin.fromArray(), including "BITS"/"RBITS".
byteOrder string optional "ABCD" Byte order (see the class notes). Not used by bit types.

Returns

array The unpacked values.

Example

let bytes = bin.fromHex("01fe");
let bitArray = bin.toArray(bytes, "RBITS");
print("bits:", string(bitArray));

let floats = bin.toArray(bin.fromHex("e6b74640000042c8"), "F32", "BADC");

bin.fromHex()

bin.fromHex(hex) → binary

Converts a hex string into a binary object.

The inverse of bin.toHex(). Handy for pasting captured payloads back into a script, or for decoding hex-encoded configuration values.

Arguments

NameTypeRequiredDefaultDescription
hex string yes Hex text, e.g. "01fe".

Returns

binary The decoded binary data.

Example

let bytes = bin.fromHex("01fe");
print(bin.toHex(bytes)); // 01fe

bin.toHex()

bin.toHex(data) → string

Converts binary data to a printable hex string.

The inverse is bin.fromHex().

Arguments

NameTypeRequiredDefaultDescription
data buffer | string yes Binary data, e.g. a sha256() digest or packed array.

Returns

string Hexadecimal representation.

Example

let aesKey = sha256("flexscadaFlexsQ5!");
print("KEY: ", bin.toHex(aesKey));

bin.enc()

bin.enc(data, key) → binary

Encrypts data with AES-256.

Encrypt payloads before sending them over untrusted networks or to insure data integrity,Keys are 256-bit values — derive one from a passphrase with bin.sha256(). Decrypted results include checksum validation.

The http and udp functions can also encrypt transparently (see setEnv("enc.key", …)).

Data is automatically padded and will be rounded up to the nearest block size.

Arguments

NameTypeRequiredDefaultDescription
data string yes Plaintext. Serialise objects first with string(obj).
key binary yes 256-bit key, e.g. from bin.sha256(passphrase).

Returns

binary Encrypted data (slightly larger than the plaintext).

Example

let aesKey = bin.sha256("password");

let secretMsg = string({ msg: "I LOVE FLEXSCADA", code: 12.454 });
let encrypted = bin.enc(secretMsg, aesKey);
print("Size (Raw, Encrypted)", secretMsg.length, encrypted.length);

bin.dec()

aes.dec(data, key) → { valid, data }

Decrypts AES-256 data and validates its checksums.

Decrypt AES256 encrypted data received from peers. Keys are 256-bit values — derive one from a passphrase with bin.sha256(). Decrypted results include checksum validation via the valid flag.

The http and udp functions can also decrypt transparently (see setEnv("aes.key", …)).

Arguments

NameTypeRequiredDefaultDescription
data binary yes Encrypted data from bin.enc() or a peer.
key binary yes The 256-bit key used to encrypt.

Returns

object { valid, data } — valid is true when decryption succeeded and checksums match; data is the plaintext.

Example

let aesKey = bin.sha256("password");

let decrypted = bin.dec(encrypted, aesKey);
if(decrypted.valid){
  let obj = JSON.parse(decrypted.data);
  print(string(obj));
} else {
  print("AES Decryption Failed.");
}

bin.crc16()

bin.crc16(data,len) → number

Modbus CRC16 checksum function

Generate a crc16 checksum from a chunk of data

Arguments

NameTypeRequiredDefaultDescription
data string yes
len number optional data.length

Returns

number Checksum Value

Example

serial.init(2,9600);

let modbusFrame = bin.alloc(8);
modbusFrame.write("U8",3); // Slave Address
modbusFrame.write("U8",0x06); // 0x06 Function Code (Write Single Register)
modbusFrame.write("U16BA",0); // Register
modbusFrame.write("U16BA",1234); // Value
let crc = modbus.crc16(modbusFrame,6); // Generate the CRC from the first 6 bytes of our payload
modbusFrame.write("U16BA,crc); // write the CRC to the end of our message
 
serial.tx(2,modbusFrame); // Send the frame over the RS485 port.

bin.sha256()

bin.sha256(data) → binary

Computes a SHA-256 hash — the standard way to derive an AES-256 key from a passphrase.

Useful for ensuring data integrity or for generating encryption keys from passphrases (Don't forget to salt your passphrases!)

Arguments

NameTypeRequiredDefaultDescription
data string yes Data to hash, e.g. a passphrase.

Returns

binary 32-byte digest, usable directly as an AES-256 key. Print with bin.toHex().

Example

let aesKey = sha256("flexscadaFlexsQ5!");
print("KEY: ", bin.toHex(aesKey));