blob: de83773a6ea77466d8c1e8dabe63b13e2626ff72 [file] [log] [blame]
/**
*
* Copyright (c) 2020 Silicon Labs
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* Binary utilities to deal with hex numbers and such.
*
* @module JS API: Binary utilities
*/
const byteBuffer = require('bytebuffer')
/**
* Takes an int8 value and turns it into a hex.
*
* @param {*} value
* @returns hex string, 2 characters long without '0x'
*/
function int8ToHex(value, littleEndian = false) {
let bb = new byteBuffer(1, littleEndian, byteBuffer.DEFAULT_NOASSERT)
bb.writeInt8(value)
bb.flip()
return bb.toHex().toUpperCase()
}
/**
* Takes an int16 value and turns it into a hex.
*
* @param {*} value
* @returns hex string, 4 characters long without '0x'
*/
function int16ToHex(value, littleEndian = false) {
let bb = new byteBuffer(2, littleEndian, byteBuffer.DEFAULT_NOASSERT)
bb.writeInt16(value)
bb.flip()
return bb.toHex().toUpperCase()
}
/**
* Takes an int32 value and turns it into a hex.
*
* @param {*} value
* @returns hex string, 8 characters long without '0x'
*/
function int32ToHex(value, littleEndian = false) {
let bb = new byteBuffer(4, littleEndian, byteBuffer.DEFAULT_NOASSERT)
bb.writeInt32(value)
bb.flip()
return bb.toHex().toUpperCase()
}
/**
* Converts a string to the hex value.
*
* @param {*} value
* @returns hex string, value.length * 2 + 2 characters long. It appends the terminating NULL, so 0x00 is at the end.
*/
function stringToHex(value) {
let bb = new byteBuffer(value.length, false, byteBuffer.DEFAULT_NOASSERT)
bb.writeCString(value)
bb.flip()
return bb.toHex().toUpperCase()
}
/**
* Given a number, this function returns the number of bits set in the number
*
* @param {*} n
* @returns number of bits set.
*/
function bitCount(n) {
n = n - ((n >> 1) & 0x55555555)
n = (n & 0x33333333) + ((n >> 2) & 0x33333333)
return (((n + (n >> 4)) & 0xf0f0f0f) * 0x1010101) >> 24
}
/**
* Takes the raw hex string, such as `abcd` and
* converts it into a C constant array, such as
* `0xAB, 0xCD`.
*
* @param {*} value
* @returns C byte array
*/
function hexToCBytes(value) {
let out = ''
let infix = ''
for (let i = 0; i < value.length; i += 2) {
out += infix
out += '0x'.concat(value.substring(i, i + 2).toUpperCase())
infix = ', '
}
return out
}
/**
* Getting a binary string ("0001101010010") it returns the number of zero bits at the end.
* @param {*} binary
*/
function bitOffset(binary) {
let lastIndex = binary.lastIndexOf('1')
return binary.length - lastIndex - 1
}
/**
* Convert a hex number to a binary. Hex has to be in a format
* as obtained by intToHex methods above: no '0x' prefix and upper-case
* letters, as in "12AB".
*
* @param {*} hex
*/
function hexToBinary(hex) {
let cleansedHex = hex
if (cleansedHex.startsWith('0x') || cleansedHex.startsWith('0X'))
cleansedHex = cleansedHex.slice(2)
cleansedHex = cleansedHex.toUpperCase()
cleansedHex = cleansedHex.replace(/[^0-F]/g, '')
return parseInt(cleansedHex, 16)
.toString(2)
.padStart(cleansedHex.length * 4, '0')
}
/**
* Returns string as C bytes, prefixed with one-byte length.
* If maxLength is greater than length of value, then
* the resulting array is padded with 0x00.
*
* @param {*} value
* @param {*} maxLength the maximum length of the used memory in bytes
* @param {*} pad If true, then pad with 0x00 until maxLength bytes.
* @returns Object containing 'length' and 'content', where length
* is number of bytes used and content is actual content in C format.
*/
function stringToOneByteLengthPrefixCBytes(value, maxLength, pad = true) {
let len = value.length
let ret = `${len}, `
for (let i = 0; i < len; i++) {
ret = ret.concat(`'${value[i]}', `)
}
let totalBytes = len + 1
if (pad && maxLength > len + 1) {
for (let i = 0; i < maxLength - (len + 1); i++) {
ret = ret.concat('0x00, ')
totalBytes++
}
}
return {
content: ret,
length: totalBytes
}
}
/**
* Returns string as C bytes, prefixed with two-byte length
* If maxLength is greater than length of value, then
* the resulting array is padded with 0x00.
*
* @param {*} value
* @param {*} maxLength the maximum length of the used memory in bytes
* @param {*} pad If true, then pad with 0x00 until maxLength bytes.
* @returns Object containing 'length' and 'content', where length
* is number of bytes used and content is actual content in C format.
*/
function stringToTwoByteLengthPrefixCBytes(value, maxLength, pad = true) {
let len = value.length
let ret = `${len & 0xff}, `
ret = ret.concat(`${(len >> 8) & 0xff}, `)
for (let i = 0; i < len; i++) {
ret = ret.concat(`'${value[i]}', `)
}
let totalBytes = len + 2
if (pad && maxLength > len + 2) {
for (let i = 0; i < maxLength - (len + 2); i++) {
ret = ret.concat('0x00, ')
totalBytes++
}
}
return {
content: ret,
length: totalBytes
}
}
exports.int32ToHex = int32ToHex
exports.int16ToHex = int16ToHex
exports.int8ToHex = int8ToHex
exports.stringToHex = stringToHex
exports.hexToCBytes = hexToCBytes
exports.hexToBinary = hexToBinary
exports.bitOffset = bitOffset
exports.stringToOneByteLengthPrefixCBytes = stringToOneByteLengthPrefixCBytes
exports.stringToTwoByteLengthPrefixCBytes = stringToTwoByteLengthPrefixCBytes
exports.bitCount = bitCount