How to store a 32-bit integer in an arraybuffer? - javascript

I seem to not be understanding the Uint32Array. According to what I've read about the Uint8Array I could just feed it a number inside an array (Uint8Array([16]) or Uint8Array([96,56])) and the results are exactly that. However, when I try the same thing for a larger number like Uint32Array([21640]), it seems to truncate it. Where 21640 should equal 5488 in hex, I only get 88. How does this actually work?
Edit: Elaborations
I am also attempting to concatenate several ArrayBuffers together. If I'm not mistaken readAsArrayBuffer produces an Uint8Array, and I am trying to append to that some 32-bit numbers using https://gist.github.com/72lions/4528834
There is so much information and examples on Uint8Array and what little there was on Uint32Array makes me think that one of these 32 would store a value as if it was 4 of the 8.

The largest value of an unsigned 8 bit number is 255. Larger numbers will be truncated or rolled over depending on the os/cpu. If you want to convert a 32 bit numbers in an 8 bit array try something like this.
var number = 21640;
var byte1 = 0xff & number;
var byte2 = 0xff & (number >> 8);
var byte3 = 0xff & (number >> 16);
var byte4 = 0xff & (number >> 24);
var arr1 = Uint8Array([byte1,byte2,byte3,byte4]);
Just reverse the order of the bytes when you create the array depending on if you want little or big endian.

Here is a working example showing 5488 in console
var bigNumber = new Uint32Array([21640]);
console.log(bigNumber[0].toString(16));
Since you've added more to the question. If you wanted to convert
var byte1 = 0x88;
var byte2 = 0x54;
var byte3 = 0;
var byte4 = 0;
var bigValue = (byte4 << 24) | (byte3 << 16) | (byte2 << 8) | (byte1);
console.log(bigValue);
Although you will need to factor in Endianness

Related

javascript: convert binary string to UInt32 big-endian without use of bitwise operations

I'm writing on a shared codebase, and we have a linting rule for 'no bitwise operations'. However I'm using a short utility function for converting a binary string to an unsigned int 32, big-endian. It works well:
// converts a four-character string into a big endian 32-bit unsigned integer
stringAsUInt32BE(binString) {
return (binString.charCodeAt(0) << 24) + (binString.charCodeAt(1) << 16) +
(binString.charCodeAt(2) << 8) + binString.charCodeAt(3);
};
How can I do this without bitwise operations? Thanks!
You can replace << x with * Math.pow(2, x).
The main difference between these two statements is the behavior for very big or negative input x, e.g. bitwise operators turn their operands into two-complement numbers while the other arithmetic operators don't.
// converts a four-character string into a big endian 32-bit unsigned integer
function stringAsUInt32BE(binString) {
return binString.charCodeAt(0) * 16777216 + binString.charCodeAt(1) * 65536 + binString.charCodeAt(2) * 256 + binString.charCodeAt(3);
}
console.log(stringAsUInt32BE('\xFF\xFF\xFF\xFF')); // 4294967295
console.log(stringAsUInt32BE('\x00\x00\x00\x00')); // 0
Note the behavior for stringAsUInt32BE('\xFF\xFF\xFF\xFF'): Your original function would return -1 which I consider a bug. This is because '\xFF'.charCodeAt(0) << 24 === 255 << 24 exceeds the maximum range Math.pow(2, 32-1)-1 of a two-complement and thus overflows to -16777216. The function given here does not suffer from that conversion issue.
You could use an ArrayBuffer with 2 different views. Write the bytes in using a Uint8Array and read out a value using a DataView specifying big-endianness like this:
stringAsUInt32BE(binString) {
var buffer = new ArrayBuffer(4);
var uint8View = new Uint8Array(buffer);
uint8View[0] = binString.charCodeAt(0);
uint8View[1] = binString.charCodeAt(1);
uint8View[2] = binString.charCodeAt(2);
uint8View[3] = binString.charCodeAt(3);
return new DataView(buffer).getUint32(0, false); // false for big endian
}
Using bit-manipulation will work better on older browsers when typed arrays aren't supported.

Javascript, serialport can't output numbers, just ascii

so I want my program to pass an int into the serialport, but javascript makes all numbers floats, that is bad.
even more if i try
sp.write(255)//outputs 0x080000010000000000000000020000
sp.write(256)//outputs infinitely
I hooked it up to a bus pirate so I could check the output
if I convert numbers to a hex string then the serialport sends out the char equivalent of my number, this is also bad.
var hex=(0xFF).toString(8);
sp.write(hex); //out=0x333737 which is 377=>0x0255 oh and not 8 bits...
hex=(0xFF).toString(16);
sp.write(hex); //out=0x6666 which is FF so at least that one makes some sense
hex=0b10101010; // error... binary does work when i run javascript in html though
but it does output asci characters so that i get the proper hex on the other side
ive tried
function hex2a(hexx) {
var hex = hexx.toString();//force conversion
var str = '';
for (var i = 0; i < hex.length; i += 2)
str += String.fromCharCode(parseInt(hex.substr(i, 2), 16));
return str;
}
but for that 0xff=>0x2505
and ive also tried
hex = String.fromCharCode(hex)
which works perfectly up to 127, after that it is 2 bytes with either a 194 or 195 in first byte
I need to be able to send 8 bytes of integer bit data to an arduino.
var buffer = new Buffer([ 8, 6, 7, 5, 3, 0, 9]);
which works for any value between 0 and 255.
thanks to Traktor53 for point out it is a buffer object
and to https://docs.nodejitsu.com/articles/advanced/buffers/how-to-use-buffers
for confirming how to consruct a Buffer

JavaScript - Negative byte from integer

I transmit a byte that's always less than 127 with a 1 bit flag to the client by ORing the byte with 0x80.
On the client side, in JavaScript, I have an Array() of numbers representing the bytes of the message (yes it's probably dumb but I haven't figured out typed arrays yet).
Everything works fine until I hit a number with the highest bit of the lowest byte set.
Number: 0011 0101
flag: 1000 0000
---------
1011 0101
Stored as
integer in ???
JavaScript
How can I retrieve the original byte (with the highest bit set to 0), plus the flag (denoted by the value of the highest bit)?
EXAMPLE:
(server)
byte x = 90
x | 0x80
> -38
(client - JavaScript)
var x = -38
x ^ 0x80
> -166
How do I get 90 back?
EDIT - I discovered this was due to another bug in my code... I wasn't going crazy with the encoding... sorry all...
Try the following in JavaScript:
var received = -38;
var adjusted = received & 0xFF; // 218
var original = adjusted ^ 0x80; // 90
That should solve your problem.
Explanation: All numbers in JavaScript stored in the double-precision floating point format:
Bitwise operators however can't deal with floating point numbers. Hence they convert their operands into 32-bit signed integers. [source]
-38 = 11111111 11111111 11111111 11011010
Hence if you do -38 ^ 0x80 you get the wrong answer as only the 8th bit from the right is set to 0. You need to first limit -38 to 8-bits before xoring it with 0x80. Only the least significant byte (i.e. 11011010) is needed. Hence we do -38 & 0xFF to get the least significant byte.
Now that you have the correct byte you may simply xor it with 0x80.
TLDR: Use byte & 0xFF ^ 0x80.
Not sure I understand the question, but I will give a shot: you have just to XORing the 0x80:
var received = 181; // 10110101
var num = received ^ 0x80;
console.log(num); // 53, 00110101
If you have a different result, probably there is something different in your code – if you run the code above, should give the expected result.
I'm not seeing a problem.
Here is some code I've written to test, with JSFiddle live demo
var val = 57;
var flag = 1;
var valWithFlag = val | (flag ? 0x80 : 0);
var newVal = (valWithFlag & 0x7F);
var newValFlag = (valWithFlag & 0x80 ? 1 : 0);
alert("Val: " + val.toString() + "\n" +
"Flag: " + flag.toString() + "\n" +
"Val With Flag: " + valWithFlag.toString() + "\n" +
"New Val Without Flag: " + newVal.toString() + "\n" +
"New Val Flag: " + newValFlag.toString() + "\n");
It is giving the desired results...
Val: 57
Flag: 1
Val With Flag: 185
New Val Without Flag: 57
New Val Flag: 1
UPDATE based on extra details provided by the OP
I think this is probably due to integers in javascript being held either as 32 or 64 bit values... so when you pass through -38 to javascript it isn't being held in the same way as the single byte on your server.
You need to convert that -38 into an 8-byte...
var val = -38;
var jsVal = (val & 0xFF);
Which should give you your 90 value to work with. Here is an updated JSFiddle

Convert A Large Integer To a Hex String In Javascript

I need to find a way to convert a large number into a hex string in javascript. Straight off the bat, I tried myBigNumber.toString(16) but if myBigNumber has a very large value (eg 1298925419114529174706173) then myBigNumber.toString(16) will return an erroneous result, which is just brilliant. I tried writing by own function as follows:
function (integer) {
var result = '';
while (integer) {
result = (integer % 16).toString(16) + result;
integer = Math.floor(integer / 16);
}
}
However, large numbers modulo 16 all return 0 (I think this fundamental issue is what is causing the problem with toString. I also tried replacing (integer % 16) with (integer - 16 * Math.floor(integer/16)) but that had the same issue.
I have also looked at the Big Integer Javascript library but that is a huge plugin for one, hopefully relatively straightforward problem.
Any thoughts as to how I can get a valid result? Maybe some sort of divide and conquer approach? I am really rather stuck here.
Assuming you have your integer stored as a decimal string like '1298925419114529174706173':
function dec2hex(str){ // .toString(16) only works up to 2^53
var dec = str.toString().split(''), sum = [], hex = [], i, s
while(dec.length){
s = 1 * dec.shift()
for(i = 0; s || i < sum.length; i++){
s += (sum[i] || 0) * 10
sum[i] = s % 16
s = (s - sum[i]) / 16
}
}
while(sum.length){
hex.push(sum.pop().toString(16))
}
return hex.join('')
}
The numbers in question are above javascript's largest integer. However, you can work with such large numbers by strings and there are some plugins which can help you do this. An example which is particularly useful in this circumstance is hex2dec
The approach I took was to use the bignumber.js library and create a BigNumber passing in the value as a string then just use toString to convert to hex:
const BigNumber = require('bignumber.js');
const lrgIntStr = '1298925419114529174706173';
const bn = new BigNumber(lrgIntStr);
const hex = bn.toString(16);

How do I swap endian-ness (byte order) of a variable in javascript

I am receiving and sending a decimal representation of two little endian numbers. I would like to:
shift one variable 8 bits left
OR them
shift a variable number of bits
create 2 8 bit numbers representing the first and second half of the 16 bit number.
javascript (according to https://developer.mozilla.org/en/JavaScript/Reference/Operators/Bitwise_Operators) uses big endian representation when shifting...
endianness is a bit foreign to me (I am only 90 percent sure that my outlined steps are what i want.) so swapping is a bit dizzying. please help! I only really need to know how to swap the order in an efficient manner. (I can only think of using a for loop on a toString() return value)
function swap16(val) {
return ((val & 0xFF) << 8)
| ((val >> 8) & 0xFF);
}
Explanation:
Let's say that val is, for example, 0xAABB.
Mask val to get the LSB by &ing with 0xFF: result is 0xBB.
Shift that result 8 bits to the left: result is 0xBB00.
Shift val 8 bits to the right: result is 0xAA (the LSB has "dropped off" the right-hand side).
Mask that result to get the LSB by &ing with 0xFF: result is 0xAA.
Combine the results from steps 3 and step 5 by |ing them together:
0xBB00 | 0xAA is 0xBBAA.
function swap32(val) {
return ((val & 0xFF) << 24)
| ((val & 0xFF00) << 8)
| ((val >> 8) & 0xFF00)
| ((val >> 24) & 0xFF);
}
Explanation:
Let's say that val is, for example, 0xAABBCCDD.
Mask val to get the LSB by &ing with 0xFF: result is 0xDD.
Shift that result 24 bits to the left: result is 0xDD000000.
Mask val to get the second byte by &ing with 0xFF00: result is 0xCC00.
Shift that result 8 bits to the left: result is 0xCC0000.
Shift val 8 bits to the right: result is 0xAABBCC (the LSB has "dropped off" the right-hand side).
Mask that result to get the second byte by &ing with 0xFF00: result is 0xBB00.
Shift val 24 bits to the right: result is 0xAA (everything except the MSB has "dropped off" the right-hand side).
Mask that result to get the LSB by &ing with 0xFF: result is 0xAA.
Combine the results from steps 3, 5, 7 and 9 by |ing them together:
0xDD000000 | 0xCC0000 | 0xBB00 | 0xAA is 0xDDCCBBAA.
Such function can be used to change endianness in js:
const changeEndianness = (string) => {
const result = [];
let len = string.length - 2;
while (len >= 0) {
result.push(string.substr(len, 2));
len -= 2;
}
return result.join('');
}
changeEndianness('AA00FF1234'); /// '3412FF00AA'
Use the << (bit shift) operator. Ex: 1 << 2 == 4.
I really think that the underlying implementation of JavaScript will use whatever endianess the platform it is running on is using. Since you cannot directly access memory in JavaScript you won't ever have to worry about how numbers are represented physically in memory. Bit shifting integer values always yield the same result no matter the endianess. You only see a difference when looking at individual bytes in memory using pointers.
Here is a oneliner for arrays to swap between big and little endian (and vise versa). The swapping is done using reverse on byte level. I guess for large arrays, it is more efficient than looping over scalar swap function.
function swapbyte(x) {
return new Float64Array(new Int8Array(x.buffer).reverse().buffer).reverse()
}
// Example
buf = new ArrayBuffer(16); // for 2 float64 numbers
enBig = new Float64Array(buf);
enBig[0] = 3.2073756306779606e-192;
enBig[1] = 2.7604354232023903e+199;
enLittle = swapbyte(enBig)
// two famous numbers are revealed
console.log(enLittle)
// Float64Array [ 6.283185307179586, 2.718281828459045 ]
// swapping again yields the original input
console.log(swapbyte(enLittle))
// Float64Array [ 3.2073756306779606e-192, 2.7604354232023903e+199 ]

Categories