broken out from uci-utils into it's own repository. fixed issues with PLC conversion of multiple bytes and big/little endian
commit
80b50b3b9a
|
@ -0,0 +1,37 @@
|
||||||
|
module.exports = {
|
||||||
|
"ecmaFeatures": {
|
||||||
|
"modules": true,
|
||||||
|
"spread" : true,
|
||||||
|
"restParams" : true
|
||||||
|
},
|
||||||
|
// "plugins": [
|
||||||
|
// "unicorn"
|
||||||
|
// ],
|
||||||
|
"env": {
|
||||||
|
"es6": true,
|
||||||
|
"node": true,
|
||||||
|
"mocha": true
|
||||||
|
},
|
||||||
|
"parserOptions": {
|
||||||
|
"ecmaVersion": 2017,
|
||||||
|
"sourceType": "module"
|
||||||
|
},
|
||||||
|
"extends": "eslint:recommended",
|
||||||
|
"rules": {
|
||||||
|
"indent": [
|
||||||
|
"error",
|
||||||
|
2
|
||||||
|
],
|
||||||
|
// "unicorn/no-array-instanceof": "error",
|
||||||
|
"no-console": 0,
|
||||||
|
"semi": ["error", "never"],
|
||||||
|
"linebreak-style": [
|
||||||
|
"error",
|
||||||
|
"unix"
|
||||||
|
],
|
||||||
|
"quotes": [
|
||||||
|
"error",
|
||||||
|
"single"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,2 @@
|
||||||
|
/node_modules/
|
||||||
|
/coverage/
|
|
@ -0,0 +1,4 @@
|
||||||
|
tests/
|
||||||
|
test/
|
||||||
|
*.test.js
|
||||||
|
testing/
|
|
@ -0,0 +1,39 @@
|
||||||
|
{
|
||||||
|
"name": "@uci-utils/byte",
|
||||||
|
"version": "0.2.0",
|
||||||
|
"description": "Byte Class and related functions",
|
||||||
|
"main": "src/byte.js",
|
||||||
|
"scripts": {
|
||||||
|
"test": "./node_modules/.bin/mocha -r esm --timeout 30000",
|
||||||
|
"testd": "UCI_ENV=dev ./node_modules/.bin/nodemon --exec './node_modules/.bin/mocha -r esm --timeout 30000' || exit 0",
|
||||||
|
"testdd": "UCI_LOG_LEVEL='trace' npm run testd",
|
||||||
|
"testde": "UCI_LOG_LEVEL='warn' npm run testd",
|
||||||
|
"testl": "UCI_ENV=pro UCI_LOG_PATH=./test/test.log 0 npm run test || exit 0"
|
||||||
|
},
|
||||||
|
"author": "David Kebler",
|
||||||
|
"license": "MIT",
|
||||||
|
"repository": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "git+https://github.com/uCOMmandIt/uci-utils.git"
|
||||||
|
},
|
||||||
|
"keywords": [
|
||||||
|
"node.js",
|
||||||
|
"communication",
|
||||||
|
"serial",
|
||||||
|
"utilities",
|
||||||
|
"helpers"
|
||||||
|
],
|
||||||
|
"bugs": {
|
||||||
|
"url": "https://github.com/uCOMmandIt/uci-utils/issues"
|
||||||
|
},
|
||||||
|
"homepage": "https://github.com/uCOMmandIt/uci-utils#readme",
|
||||||
|
"dependencies": {
|
||||||
|
"bitwise": "^2.0.1"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"chai": "^4.2.0",
|
||||||
|
"esm": "^3.2.4",
|
||||||
|
"mocha": "^5.2.0",
|
||||||
|
"nodemon": "^1.18.10"
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,2 @@
|
||||||
|
### Byte Me
|
||||||
|
#### a uCOMmandIt Byte Class and Utility Functions
|
|
@ -0,0 +1,51 @@
|
||||||
|
// example jsdoc syntax
|
||||||
|
// // -----------------------------------
|
||||||
|
// // Values
|
||||||
|
//
|
||||||
|
// /**
|
||||||
|
// * Get the object type string
|
||||||
|
// * @param {any} value
|
||||||
|
// * @returns {string}
|
||||||
|
// */
|
||||||
|
// function getObjectType (value /* :mixed */) /* :string */ {
|
||||||
|
// return Object.prototype.toString.call(value)
|
||||||
|
// }
|
||||||
|
|
||||||
|
function flatten(array) {
|
||||||
|
const flatten = arr => arr.reduce((a, b) => a.concat(Array.isArray(b) ? flatten(b) : b), [])
|
||||||
|
return flatten(array)
|
||||||
|
}
|
||||||
|
|
||||||
|
function sum(arr) {
|
||||||
|
return arr.reduce(function (a, b) {
|
||||||
|
return a + b
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
function padStart (arr, len, c) {
|
||||||
|
len = len || 8
|
||||||
|
c = c || 0
|
||||||
|
if (len < arr.length) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
let pad = len - arr.length
|
||||||
|
for (var i = 0; i < pad; i++) {
|
||||||
|
arr.unshift(c)
|
||||||
|
}
|
||||||
|
return arr
|
||||||
|
}
|
||||||
|
|
||||||
|
function padEnd (arr, len, c) {
|
||||||
|
len = len || 8
|
||||||
|
c = c || 0
|
||||||
|
if (len < arr.length) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
let pad = len - arr.length
|
||||||
|
for (var i = 0; i < pad; i++) {
|
||||||
|
arr.push(c)
|
||||||
|
}
|
||||||
|
return arr
|
||||||
|
}
|
||||||
|
|
||||||
|
export { flatten, sum, padStart, padEnd }
|
|
@ -0,0 +1,437 @@
|
||||||
|
// third party modules
|
||||||
|
import bits from 'bitwise/bits'
|
||||||
|
import toBits from 'bitwise/string/to-bits'
|
||||||
|
import readUInt from 'bitwise/buffer/read-u-int'
|
||||||
|
import createBuffer from 'bitwise/buffer/create'
|
||||||
|
import readByte from 'bitwise/byte/read'
|
||||||
|
import writeByte from 'bitwise/byte/write'
|
||||||
|
//local
|
||||||
|
import * as array from './array'
|
||||||
|
|
||||||
|
// Classes
|
||||||
|
|
||||||
|
// Byte Class is a single byte value with an attached format designation which allows easy
|
||||||
|
// conversion of the byte to any of the other formats
|
||||||
|
// of ['STR', 'BUF', 'BUF', 'DEC', 'HEX', 'ARY', 'PLC'] like this
|
||||||
|
// examples:
|
||||||
|
// '1100101', 'STR' will be left padded to 8 chars with 0
|
||||||
|
// Buffer.from([0x65]), 'BUF'
|
||||||
|
// 101, 'DEC'
|
||||||
|
// 65, 'HEX'
|
||||||
|
// [1,1,0,0,1,0,1], 'ARY' will be left padded/unshifted to 8 elements, with 0
|
||||||
|
// [7,3,1,6], 'PLC' any order, the number of the bit that is "on" or "1" from 1-8, 1=rightmost LSB
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Byte - A class to hold and manipulate a bitwise byte
|
||||||
|
*/
|
||||||
|
class Byte {
|
||||||
|
/**
|
||||||
|
* constructor - Description
|
||||||
|
*
|
||||||
|
* @param {number} [byte=0] Description
|
||||||
|
* @param {string} [format=DEC] Description
|
||||||
|
*
|
||||||
|
* @returns {Object} instance of Byte Class
|
||||||
|
*/
|
||||||
|
|
||||||
|
constructor(byte = 0, format = 'DEC') {
|
||||||
|
this.cur = byte
|
||||||
|
this.prv = byte
|
||||||
|
this.format = format
|
||||||
|
}
|
||||||
|
|
||||||
|
static validateFmt(fmt) {
|
||||||
|
return ['STR', 'BUF', 'DEC', 'HEX', 'ARY', 'PLC'].indexOf(fmt) === -1
|
||||||
|
? false
|
||||||
|
: true
|
||||||
|
}
|
||||||
|
|
||||||
|
// getter/setters
|
||||||
|
get value() {
|
||||||
|
return this.cur
|
||||||
|
}
|
||||||
|
set value(byte) {
|
||||||
|
this.prv = this.cur
|
||||||
|
this.cur = byte
|
||||||
|
}
|
||||||
|
|
||||||
|
get fmt() {
|
||||||
|
return this.format
|
||||||
|
}
|
||||||
|
|
||||||
|
set fmt(f) {
|
||||||
|
this.cur = this.toFmt(f)
|
||||||
|
this.prv = byteFormat(this.prv, { in: this.format, out: f })
|
||||||
|
this.format = f
|
||||||
|
}
|
||||||
|
|
||||||
|
get prev() {
|
||||||
|
return this.prv
|
||||||
|
}
|
||||||
|
|
||||||
|
toFmt(fmt) {
|
||||||
|
return byteFormat(this.cur, { in: this.format, out: fmt })
|
||||||
|
}
|
||||||
|
|
||||||
|
toFmtPrev(fmt) {
|
||||||
|
return byteFormat(this.prv, { in: this.format, out: fmt })
|
||||||
|
}
|
||||||
|
|
||||||
|
reset(byte, fmt) {
|
||||||
|
this.cur = byte
|
||||||
|
this.prv = byte
|
||||||
|
this.format = fmt ? fmt : 'DEC'
|
||||||
|
}
|
||||||
|
|
||||||
|
// used for setting bytes when passed byte format needs to be adapted to current instance's format
|
||||||
|
adaptFmt(byte, format) {
|
||||||
|
return byteFormat(byte, { in: format, out: this.format })
|
||||||
|
}
|
||||||
|
|
||||||
|
bwOp(byte, op, format = { in: 'DEC', out: 'DEC' }) {
|
||||||
|
let bwop
|
||||||
|
switch (op) {
|
||||||
|
case 'toggle':
|
||||||
|
bwop = bits.xor
|
||||||
|
break
|
||||||
|
case 'off': // NOT mask then AND which is not the same as NAND = AND then NOT result
|
||||||
|
bwop = (byte, mask) => {
|
||||||
|
return bits.and(byte, bits.not(mask))
|
||||||
|
}
|
||||||
|
break
|
||||||
|
case 'on':
|
||||||
|
bwop = bits.or
|
||||||
|
break
|
||||||
|
case 'check':
|
||||||
|
bwop = bits.and
|
||||||
|
break
|
||||||
|
}
|
||||||
|
// console.log('byte and state as passed', byte, this.value)
|
||||||
|
let opbyte = bwop(
|
||||||
|
this.toFmt('ARY'),
|
||||||
|
byteFormat(byte, { in: format.in, out: 'ARY' })
|
||||||
|
)
|
||||||
|
return byteFormat(opbyte, { in: 'ARY', out: format.out })
|
||||||
|
}
|
||||||
|
|
||||||
|
changes() {
|
||||||
|
return bitChanges(this.toFmt('ARY'), this.toFmtPrev('ARY'))
|
||||||
|
}
|
||||||
|
|
||||||
|
stateChanges() {
|
||||||
|
return stateChanges(this.toFmt('ARY'), this.toFmtPrev('ARY'))
|
||||||
|
}
|
||||||
|
} // end Byte Class
|
||||||
|
|
||||||
|
// Library functions and objects
|
||||||
|
|
||||||
|
const BYTE_FORMATS = ['STR', 'BUF', 'DEC', 'HEX', 'ARY', 'PLC']
|
||||||
|
|
||||||
|
//can be used with the BYTE Class or stand alone if you supply by and fmt object
|
||||||
|
//can accept single multiple byte input
|
||||||
|
// multiple bytes stored in array with most significant byte with index 0
|
||||||
|
function byteFormat(bytes, fmt) {
|
||||||
|
// TODO support STR and ARY formats that a long string or single flat array rather than array of each
|
||||||
|
|
||||||
|
if (fmt.in === 'PLC') {
|
||||||
|
bytes = plc2bytes(bytes)
|
||||||
|
return byteFormat(bytes.length === 1 ? bytes[0] : bytes, {
|
||||||
|
in: 'DEC',
|
||||||
|
out: fmt.out
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fmt.in === 'BUF') {
|
||||||
|
bytes = buf2ary(bytes)
|
||||||
|
return byteFormat(bytes.length === 1 ? bytes[0] : bytes, {
|
||||||
|
in: 'DEC',
|
||||||
|
out: fmt.out
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// It's a single byte
|
||||||
|
if (
|
||||||
|
(fmt.in === 'ARY' && !Array.isArray(bytes[0])) ||
|
||||||
|
(fmt.in !== 'ARY' && !Array.isArray(bytes))
|
||||||
|
) {
|
||||||
|
return format(bytes, fmt)
|
||||||
|
}
|
||||||
|
|
||||||
|
// process multiple bytes
|
||||||
|
|
||||||
|
if (fmt.out === 'PLC') {
|
||||||
|
return bytes2plc(byteFormat(bytes, { in: fmt.in, out: 'DEC' }))
|
||||||
|
}
|
||||||
|
if (fmt.out === 'BUF') {
|
||||||
|
if (fmt.in !== 'DEC') {
|
||||||
|
bytes = byteFormat(bytes, { in: fmt.in, out: 'DEC' })
|
||||||
|
}
|
||||||
|
return Buffer.from(bytes)
|
||||||
|
}
|
||||||
|
// everything else
|
||||||
|
return bytes.map(byte => {
|
||||||
|
return format(byte, fmt)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// curr and prev need to be arrays of bits as arrays ARY
|
||||||
|
// returns changes if any otherwise false
|
||||||
|
function bitChanges(curr, prev) {
|
||||||
|
let changes = bits.xor(curr, prev)
|
||||||
|
|
||||||
|
// nothing changed
|
||||||
|
if (!array.sum(changes)) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
// something changed
|
||||||
|
return changes
|
||||||
|
}
|
||||||
|
|
||||||
|
// all bit changes
|
||||||
|
// changes and curr need to be an array of arrays of 8 bits/byte in ARY format
|
||||||
|
// returns array of array pairs
|
||||||
|
// where each pair is the bit that changed and it's current state (1=on,0=off)
|
||||||
|
function stateChanges(curr, prev) {
|
||||||
|
let bitchanges = bitChanges(curr, prev)
|
||||||
|
if (!bitchanges) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
console.log(prev)
|
||||||
|
console.log(curr)
|
||||||
|
console.log(bitchanges)
|
||||||
|
|
||||||
|
let nowon = curr.map((bit, i) => {
|
||||||
|
console.log(bit, bitchanges[i], bit & bitchanges[i])
|
||||||
|
return bit & bitchanges[i]
|
||||||
|
})
|
||||||
|
nowon = byteFormat(nowon, {
|
||||||
|
in: 'ARY',
|
||||||
|
out: 'PLC'
|
||||||
|
})
|
||||||
|
|
||||||
|
console.log('nowon', nowon)
|
||||||
|
|
||||||
|
return byteFormat(bitchanges, {
|
||||||
|
in: 'ARY',
|
||||||
|
out: 'PLC'
|
||||||
|
}).map(swtch => {
|
||||||
|
return [swtch, nowon.indexOf(swtch) === -1 ? 'off' : 'on']
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
function bitsReverse(byte) {
|
||||||
|
// in DEC out DEC
|
||||||
|
return writeByte(readByte(byte).reverse())
|
||||||
|
}
|
||||||
|
|
||||||
|
// exports here
|
||||||
|
export default Byte
|
||||||
|
export { Byte, byteFormat, BYTE_FORMATS, bitsReverse, bitChanges, stateChanges }
|
||||||
|
|
||||||
|
|
||||||
|
///////// module scoped not exported functions /////
|
||||||
|
|
||||||
|
/*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
// Takes a SINGLE byte in one format and returns it in another,
|
||||||
|
// byteFormat function above allows multiple bytes and uses this
|
||||||
|
const format = function(byte, fmt) {
|
||||||
|
let ifmt = fmt.in || 'STR' // default STR
|
||||||
|
let ofmt = fmt.out || 'DEC' // default DEC
|
||||||
|
// debug.L2('input: ', byte, ' input format: ', ifmt, ' output format:', ofmt);
|
||||||
|
|
||||||
|
let decimal = NaN
|
||||||
|
switch (ifmt) {
|
||||||
|
case 'STR':
|
||||||
|
decimal = writeByte(toBits(byte.padStart(8,'0')))
|
||||||
|
break
|
||||||
|
case 'BUF':
|
||||||
|
decimal = readUInt(byte, 0, 8)
|
||||||
|
break
|
||||||
|
case 'DEC':
|
||||||
|
decimal = byte
|
||||||
|
break
|
||||||
|
case 'HEX':
|
||||||
|
decimal = parseInt(byte, 16)
|
||||||
|
break
|
||||||
|
case 'ARY':
|
||||||
|
decimal = writeByte(array.padStart(byte))
|
||||||
|
break
|
||||||
|
case 'PLC':
|
||||||
|
decimal = plc2dec(byte)
|
||||||
|
break
|
||||||
|
default:
|
||||||
|
ofmt = false
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
let output
|
||||||
|
//TODO only BIT and DEC are working
|
||||||
|
switch (ofmt) {
|
||||||
|
case 'STR':
|
||||||
|
output = bits.toString(readByte(decimal))
|
||||||
|
break
|
||||||
|
case 'BUF':
|
||||||
|
output = createBuffer(readByte(decimal))
|
||||||
|
break
|
||||||
|
case 'DEC':
|
||||||
|
output = decimal
|
||||||
|
break
|
||||||
|
case 'HEX':
|
||||||
|
output = decimal.toString(16)
|
||||||
|
break
|
||||||
|
case 'ARY':
|
||||||
|
output = readByte(decimal)
|
||||||
|
break
|
||||||
|
case 'PLC':
|
||||||
|
output = dec2plc(decimal)
|
||||||
|
break
|
||||||
|
default:
|
||||||
|
console.log('unknown input or output format')
|
||||||
|
output = false
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
return output
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
function bytes2plc(bytes) {
|
||||||
|
// bytes must be in 'DEC' format first
|
||||||
|
|
||||||
|
let plc = bytes.map((byte, bytenum) => {
|
||||||
|
return format(byte, {
|
||||||
|
in: 'DEC',
|
||||||
|
out: 'PLC'
|
||||||
|
}).map(cmpt => {
|
||||||
|
return bytenum * 8 + cmpt
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
plc = plc.reduce(function(a, b) {
|
||||||
|
// combine plc arrays
|
||||||
|
return a.concat(b)
|
||||||
|
}, [])
|
||||||
|
plc.sort((a, b) => a - b)
|
||||||
|
return plc
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
function plc2bytes(cmpts) {
|
||||||
|
// cmpts is an array of bit numbers that can be of any value (beyond 8 ok)
|
||||||
|
// returns an object of pairs, each pair a byte number (bank) and the value for that byte(bank) in
|
||||||
|
// in 'DEC' format.
|
||||||
|
|
||||||
|
let UCI_ENDIAN = process.env.UCI_ENDIAN || 'little'
|
||||||
|
|
||||||
|
let byte = 0,
|
||||||
|
cmpt = 0,
|
||||||
|
maxbyte = 0,
|
||||||
|
bytes = {}
|
||||||
|
|
||||||
|
for (let i in cmpts) {
|
||||||
|
cmpt = cmpts[i]
|
||||||
|
byte = Math.floor((cmpt - 1) / 8) + 1
|
||||||
|
if (byte > maxbyte) {
|
||||||
|
maxbyte = byte
|
||||||
|
}
|
||||||
|
if (bytes[byte] === undefined) {
|
||||||
|
bytes[byte] = []
|
||||||
|
}
|
||||||
|
bytes[byte].push(cmpt % 8 === 0 ? 8 : cmpt % 8)
|
||||||
|
}
|
||||||
|
let bytearr = []
|
||||||
|
// bytes index 0 with be least signficant, need to reverse that
|
||||||
|
for (byte in bytes) {
|
||||||
|
bytes[byte] = format(bytes[byte], {
|
||||||
|
in: 'PLC',
|
||||||
|
out: 'DEC'
|
||||||
|
})
|
||||||
|
if (UCI_ENDIAN==='little') bytearr[byte-1] = bytes[byte]
|
||||||
|
else bytearr[maxbyte - byte] = bytes[byte]
|
||||||
|
}
|
||||||
|
|
||||||
|
// pad in "zero" for missing byte elements
|
||||||
|
for (let i = 0; i < maxbyte-1; i++) {
|
||||||
|
if (!bytearr[i]) {
|
||||||
|
bytearr[i] = 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// log.debug({places:cmpts, bytes:bytearr, endian:UCI_ENDIAN, msg:'plc to bytes conversion')
|
||||||
|
return bytearr
|
||||||
|
}
|
||||||
|
|
||||||
|
// can't just do split map because split doesn't work on single number
|
||||||
|
function numStr2Arr(str, del) {
|
||||||
|
del = del || ' ' //default delimimter is a space, see string.protoype.split
|
||||||
|
// let arr = []
|
||||||
|
// TODO change to single line
|
||||||
|
if (typeof str === 'number') {
|
||||||
|
// just a single number
|
||||||
|
// arr[0] = parseInt(str, 10)
|
||||||
|
// return arr;
|
||||||
|
return parseInt(str, 10)
|
||||||
|
} else {
|
||||||
|
//it's a string of numbers
|
||||||
|
return str.split(del).map(Number)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function bits2dec(bits) {
|
||||||
|
let decimal = 0
|
||||||
|
let place = bits.length
|
||||||
|
bits.split('').forEach(function(bit) {
|
||||||
|
decimal += Math.pow(2, bit * (place - 1))
|
||||||
|
--place
|
||||||
|
})
|
||||||
|
return decimal
|
||||||
|
}
|
||||||
|
|
||||||
|
function plc2dec(nums, string) {
|
||||||
|
let decimal = 0
|
||||||
|
// log.debug('nums', nums)
|
||||||
|
|
||||||
|
if (string) {
|
||||||
|
nums = numStr2Arr(nums)
|
||||||
|
}
|
||||||
|
nums.forEach(function(num) {
|
||||||
|
decimal += Math.pow(2, num - 1)
|
||||||
|
// log.debug('place', num, 'dec ', decimal);
|
||||||
|
})
|
||||||
|
return decimal
|
||||||
|
}
|
||||||
|
|
||||||
|
function dec2plc(decimal, toStr) {
|
||||||
|
//outputs an array unless str is true
|
||||||
|
let place = 8
|
||||||
|
let plc = []
|
||||||
|
readByte(decimal).forEach(function(bit) {
|
||||||
|
if (bit) {
|
||||||
|
plc.push(place)
|
||||||
|
}
|
||||||
|
--place
|
||||||
|
})
|
||||||
|
if (toStr) {
|
||||||
|
return plc.join(' ')
|
||||||
|
} else {
|
||||||
|
return plc
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function buf2ary(buf) {
|
||||||
|
return Array.from(new Uint8Array(buf))
|
||||||
|
}
|
|
@ -0,0 +1,47 @@
|
||||||
|
let date = new Date(Date.now())
|
||||||
|
console.log('run:', date.getMinutes(), ':', date.getSeconds())
|
||||||
|
|
||||||
|
import { expect } from 'chai'
|
||||||
|
import * as _ from '../src/array'
|
||||||
|
|
||||||
|
|
||||||
|
describe('Array Library - ', function () {
|
||||||
|
|
||||||
|
it('Should flatten an array', function () {
|
||||||
|
expect(_.flatten([
|
||||||
|
[1],
|
||||||
|
[2],
|
||||||
|
[3]
|
||||||
|
])).deep.equal([1, 2, 3])
|
||||||
|
expect(_.flatten([1, 2, 3])).deep.equal([1, 2, 3])
|
||||||
|
})
|
||||||
|
it('Should sum an array', function () {
|
||||||
|
expect(_.sum([1, 2, 3])).to.equal(6)
|
||||||
|
expect(_.sum([1, 'shut', 'up'])).to.equal('1shutup')
|
||||||
|
})
|
||||||
|
|
||||||
|
it('Should pad left an array to 8 with zeros by defaul', function () {
|
||||||
|
expect(_.padStart([1, 2, 3])).to.deep.equal([0,0,0,0,0,1,2,3])
|
||||||
|
})
|
||||||
|
|
||||||
|
it('Should ignore pad when not longer than array', function () {
|
||||||
|
expect(_.padStart([1, 2, 3],3,'a')).to.deep.equal([1,2,3])
|
||||||
|
})
|
||||||
|
|
||||||
|
it('Should pad left an array with character', function () {
|
||||||
|
expect(_.padStart([1, 2, 3],5,'a')).to.deep.equal(['a','a',1,2,3])
|
||||||
|
})
|
||||||
|
|
||||||
|
it('Should pad right an array to 8 with zeros by defaul', function () {
|
||||||
|
expect(_.padEnd([1, 2, 3])).to.deep.equal([1,2,3,0,0,0,0,0])
|
||||||
|
})
|
||||||
|
|
||||||
|
it('Should ignore pad when not longer than array', function () {
|
||||||
|
expect(_.padEnd([1, 2, 3],3,'a')).to.deep.equal([1,2,3])
|
||||||
|
})
|
||||||
|
|
||||||
|
it('Should pad left an array with character', function () {
|
||||||
|
expect(_.padEnd([1, 2, 3],5,'a')).to.deep.equal([1,2,3,'a','a'])
|
||||||
|
})
|
||||||
|
|
||||||
|
})
|
|
@ -0,0 +1,135 @@
|
||||||
|
let date = new Date(Date.now())
|
||||||
|
console.log('run:', date.getMinutes(), ':', date.getSeconds())
|
||||||
|
|
||||||
|
import { expect } from 'chai'
|
||||||
|
import * as _ from '../src/byte'
|
||||||
|
|
||||||
|
describe('Byte Library - ', function () {
|
||||||
|
|
||||||
|
it('Should Convert Byte Format for Single Byte', function () {
|
||||||
|
|
||||||
|
let byte = '10000001'
|
||||||
|
let fmt = {}
|
||||||
|
|
||||||
|
let results = ['10000001', Buffer.from([0x81]), 129, '81', [1, 0, 0, 0, 0, 0, 0, 1],
|
||||||
|
[8, 1]
|
||||||
|
]
|
||||||
|
|
||||||
|
_.BYTE_FORMATS.forEach((ifmt, i) => {
|
||||||
|
byte = results[i]
|
||||||
|
fmt.in = ifmt
|
||||||
|
// console.log('input', ifmt, byte)
|
||||||
|
_.BYTE_FORMATS.forEach((ofmt, o) => {
|
||||||
|
fmt.out = ofmt
|
||||||
|
// console.log(fmt.out, _.byteFormat(byte, fmt))
|
||||||
|
expect(_.byteFormat(byte, fmt)).deep.equal(results[o])
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
})
|
||||||
|
|
||||||
|
it('Should Convert from Any Format to Any Other', function () {
|
||||||
|
|
||||||
|
let bytes
|
||||||
|
let fmt = {}
|
||||||
|
|
||||||
|
let results = [
|
||||||
|
['10000001', '01010111'],
|
||||||
|
Buffer.from([0x81, 0x57]), [129, 87],
|
||||||
|
['81', '57'],
|
||||||
|
[
|
||||||
|
[1, 0, 0, 0, 0, 0, 0, 1],
|
||||||
|
[0, 1, 0, 1, 0, 1, 1, 1]
|
||||||
|
],
|
||||||
|
[1, 8, 9, 10, 11, 13, 15]
|
||||||
|
]
|
||||||
|
|
||||||
|
_.BYTE_FORMATS.forEach((ifmt, i) => {
|
||||||
|
bytes = results[i]
|
||||||
|
fmt.in = ifmt
|
||||||
|
// console.log('input', ifmt, bytes)
|
||||||
|
_.BYTE_FORMATS.forEach((ofmt, o) => {
|
||||||
|
fmt.out = ofmt
|
||||||
|
// console.log('=',i, fmt.in, bytes, o, fmt.out, _.byteFormat(bytes, fmt))
|
||||||
|
expect(_.byteFormat(bytes, fmt)).deep.equal(results[o])
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
})
|
||||||
|
|
||||||
|
it('It should deal with missing byte when converting from PLC', function () {
|
||||||
|
|
||||||
|
let fmt={}
|
||||||
|
|
||||||
|
// check for missing place
|
||||||
|
fmt.in = 'PLC'
|
||||||
|
fmt.out = 'DEC'
|
||||||
|
let bytes = [1, 8, 17]
|
||||||
|
expect(_.byteFormat(bytes, fmt)).deep.equal([129, 0, 1])
|
||||||
|
|
||||||
|
})
|
||||||
|
|
||||||
|
it('PLC should return as with Big Endian when set in environment', function () {
|
||||||
|
// check Big endian
|
||||||
|
|
||||||
|
let fmt={}
|
||||||
|
process.env.UCI_ENDIAN='big'
|
||||||
|
fmt.in = 'PLC'
|
||||||
|
fmt.out = 'DEC'
|
||||||
|
let bytes = [1, 8, 17]
|
||||||
|
expect(_.byteFormat(bytes, fmt)).deep.equal([1, 0, 129])
|
||||||
|
|
||||||
|
})
|
||||||
|
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('Byte Class - ', function () {
|
||||||
|
|
||||||
|
let byte = new _.Byte(20, 'HEX')
|
||||||
|
let byte2 = new _.Byte(20)
|
||||||
|
|
||||||
|
it('Should set the default format to DEC', function () {
|
||||||
|
|
||||||
|
expect(byte2.fmt).to.equal('DEC')
|
||||||
|
})
|
||||||
|
|
||||||
|
it('Should output an alternative format', function () {
|
||||||
|
expect(byte.toFmt('DEC')).to.equal(32)
|
||||||
|
expect(byte.toFmt('STR')).to.equal('00100000')
|
||||||
|
})
|
||||||
|
|
||||||
|
it('Verify getters and setters ', function () {
|
||||||
|
// value getter and setter
|
||||||
|
expect(byte.value, 'value getter failed').to.equal(20)
|
||||||
|
byte.value = 40
|
||||||
|
expect(byte.value, 'value setter failed').to.equal(40)
|
||||||
|
expect(byte.prev, 'previous value not set').to.equal(20)
|
||||||
|
|
||||||
|
// format getter/setter
|
||||||
|
expect(byte.fmt, 'format getter failed').to.equal('HEX')
|
||||||
|
byte.fmt = 'STR'
|
||||||
|
expect(byte.fmt, 'format setter failed').to.equal('STR')
|
||||||
|
expect(byte.value, 'format getter value change failed').to.equal('01000000')
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should update value with format', function () {
|
||||||
|
// change the value with same format
|
||||||
|
// change value and set format
|
||||||
|
byte.reset(32)
|
||||||
|
expect(byte.value, 'value reset failed').to.equal(32)
|
||||||
|
expect(byte.value, 'previous value reset failed').to.equal(32)
|
||||||
|
expect(byte.fmt, 'default format reset failed').to.equal('DEC')
|
||||||
|
byte.reset(20, 'HEX')
|
||||||
|
expect(byte.value, 'value reset failed').to.equal(20)
|
||||||
|
expect(byte.fmt, 'format reset failed').to.equal('HEX')
|
||||||
|
byte.reset('10000000', 'STR')
|
||||||
|
expect(byte.toFmt('DEC'), 'string reset and convert failed').to.equal(128)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('!!!-should find bit changes and state of those changes between previous and current', function () {
|
||||||
|
// change the value with same format
|
||||||
|
// change value and set format
|
||||||
|
expect(true, 'value reset failed').to.equal(true)
|
||||||
|
})
|
||||||
|
|
||||||
|
})
|
Loading…
Reference in New Issue