npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

io-buffer-worker

v1.0.0

Published

A node.js buffer encoder / decoder for PLC data communication

Downloads

2

Readme

io-buffer-worker

A node.js buffer encoder / decoder for PLC data communication.

This project is aimed to provide basic conversion from buffer to javascript object or from javascript object to buffer based on a json description file.

The data profile must always reflect the data table defined in the PLC.

You're free to create the needed javascript object structure you need.

I've built this library because it's not easy to define string length and boolean doesn't exist in Google's protocol buffer.

Install

$ npm install io-buffer-worker

Use

const BufferWorker = require('io-buffer-worker');

const options = {
  endianess: 'LE' // default value: BE
}

// encode
BufferWorker.encode('path/to/json/description/file.json', dataToEncode, options).then(
  data => console.log(data)
).catch(
  err => console.log(err)
);

// decode
BufferWorker.decode('path/to/json/description/file.json', bufferToDecode, options).then(
  data => console.log(data)
).catch(
  err => console.log(err)
);

API

BufferWorker.encode

Params :

  • buffer and object description file : (string|array) required

path to file or object description array

  • dataToEncode : (object) required

The content you want to encode.

  • options : (object) not mandatory

See Options

Returns :

a promise with a Node.js Buffer as parameter.

BufferWorker.decode

Params :

  • buffer and object description file : (string|array) required

path to file or object description array

  • bufferToDecode : (Buffer) required

The buffer you want to decode into a formatted object.

  • options : (object) not mandatory

See Options

Returns :

a promise with a result object as parameter.

Promises

Because encode and decode functions return promise, it can be used with async / await.

Buffer and Object description file param

The path/to/json/description/file.json can be absolue or relative.

Both encode and decode accept the content of the file as parameter instead of a path, for example :

BufferWorker.decode(require('path/to/json/description/file.json'), bufferToDecode, options)

The description file can then be generated by program at runtime.

Options

  • endianness : "BE" for Big Endian, "LE" for Little Endian

Define buffer fields

All length numbers is a count of bytes (8 bits) to stay close to the PLC data types, 'cos we're stick to low level programming ;-)

General representation of a field

{
  "name": "(string) your custom object property name",
  "type": "(string) the PLC data type",
  "default": "defaut value if object property is not defined before encoding",
  "offset": "(unsigned integer) the first byte position number",
  "bitnumber": "(unsigned integer between 0 and 7) required for 'BOOL' only : the bit position in the byte read at offset",
  "length": "(unsigned integer) required for 'STRING' and 'ARRAY OF ...' only : length of the string or char array",
  "properties": "(array of properties) required to define an object",
  "array": "(array of array of properties) required to define an array of objects"
}

PLC Data types

  • BOOL (1 byte + bit number parameter)
  • BYTE (1 byte length)
  • INT/UINT/WORD (2 bytes length)
  • DINT/UDINT/DWORD (4 bytes length)
  • REAL (4 bytes length)
  • CHAR (1 byte length)
  • ARRAY OF [BOOL | INT | UINT | DINT | UDINT | WORD | DWORD | REAL | CHAR] (length bytes as a parameter)
  • STRING (length bytes as a parameter, an alias for ARRAY OF CHAR)
  • S7STRING (maxlength and length are set by PLC, Siemens typed string with maximum length et real length in the first two bytes)

S7STRING format :

{
  maxlength: 16, // Integer
  length: 8,     // Integer
  value: "value" // String
}

BOOL

{
  "name": "fieldName",
  "type": "BOOL",
  "default": false,
  "offset": 32,
  "bitnumber": 4
}

INT

{
  "name": "fieldName",
  "type": "INT",
  "default": 0,
  "offset": 6
}

UINT

{
  "name": "fieldName",
  "type": "UINT",
  "default": 0,
  "offset": 2
}

WORD

{
  "name": "fieldName",
  "type": "WORD",
  "default": 0,
  "offset": 8
}

DINT

{
  "name": "fieldName",
  "type": "DINT",
  "default": 0,
  "offset": 10
}

UDINT

{
  "name": "fieldName",
  "type": "UDINT",
  "default": 0,
  "offset": 56
}

DWORD

{
  "name": "fieldName",
  "type": "DWORD",
  "default": 0,
  "offset": 32
}

REAL

{
  "name": "fieldName",
  "type": "REAL",
  "default": 0,
  "offset": 26
}

CHAR

{
  "name": "fieldName",
  "type": "CHAR",
  "default": "",
  "offset": 4
}

ARRAY OF [BOOL|INT|UINT|WORD|DINT|UDINT|DWORD|REAL|BYTE|CHAR]

{
  "name": "fieldName",
  "type": "ARRAY OF [BOOL|INT|UINT|WORD|DINT|UDINT|DWORD|REAL|BYTE|CHAR]",
  "default": false,
  "offset": 32,
  "length": 64
}

STRING[32]

{
  "name": "fieldName",
  "type": "STRING",
  "default": "",
  "offset": 4,
  "length": 32
}

S7STRING

{
  "name": "fieldName",
  "type": "S7STRING",
  "default": "",
  "offset": 4,
}

Object structure

The json description file has to reflect the source / result javascript object structure from buffer byte #0 to buffer max length.

The json description file is an array of objects.

An object can have properties to generate sub-object.

An object can have array property to generate array of objects.

Basic example

[
  {
    "name": "fieldName1",
    "type": "INT",
    "default": 0,
    "offset": 0
  }, {
    "name": "fieldName2",
    "properties": [
      {
        "name": "objectPropertyName1",
        "type": "BOOL",
        "default": false,
        "offset": 2,
        "bitnumber": 0
      }, {
        "name": "objectPropertyName2",
        "type": "BOOL",
        "default": false,
        "offset": 2,
        "bitnumber": 3
      }
    ]
  }, {
    "name": "fieldName3",
    "array": [
      [
        {
          "name": "objectPropertyName3",
          "type": "BOOL",
          "default": false,
          "offset": 4,
          "bitnumber": 0
        }, {
          "name": "objectPropertyName4",
          "type": "BOOL",
          "default": false,
          "offset": 4,
          "bitnumber": 1
        }
      ], [
        {
          "name": "objectPropertyName3",
          "type": "BOOL",
          "default": false,
          "offset": 4,
          "bitnumber": 2
        }, {
          "name": "objectPropertyName4",
          "type": "BOOL",
          "default": false,
          "offset": 4,
          "bitnumber": 3
        }
      ]
    ]
  }, {
    "name": "fieldName2",
    "properties": [
      {
        "name": "objectPropertyName5",
        "type": "STRING",
        "default": false,
        "offset": 6,
        "length": 16
      }, {
        "name": "objectPropertyName6",
        "type": "REAL",
        "default": false,
        "offset": 22
      }
    ]
  }, {
    "name": "fieldName3",
    "type": "ARRAY OF UINT",
    "default": 0,
    "offset": 26,
    "length": 12
  }
]

The example above will result in, the values are just example of what you could have in your PLC :

{
  fieldName1: 32,
  fieldName2: {
    objectPropertyName1: false,
    objectPropertyName2: true,
    objectPropertyName5: "00001254",
    objectPropertyName6: 56.37
  },
  fieldName3: [
    {
      objectPropertyName3: false,
      objectPropertyName4: true
    }, {
      objectPropertyName3: true,
      objectPropertyName4: false
    }
  ],
  fieldName4: [
    32,
    3424,
    7654,
    0,
    0,
    0,
    0,
    0,
    0,
    7,
    0,
    0
  ]
}

Contributing

Please, open an issue or a pull request.

For your code contributions, please, keep in mind to stay as simple as possible and use functional programming as much as possible.

All async function must return a promise, callbacks are not allowed.

All errors must throw an error exception with locatable and unique message.

Feel free to format your code or mine with documentation in english language.

Because I learn javascript by myself and english is not my native language, there's surely a lack in documentation or spelling / grammar errors. Please, don't blame me and feel free to fix ;-)

You'll find some commits for backup in the history : git is for versionning but it's also my backup tool, some commits may not be usefull but, by the way, that's how I work.

TODO

  • create a TODO list

Contributors

Enjoy!