I am having problems with my code architecture and am looking for advice. I am sending multiple read request to a server via udp and printing the read response out. An example of how the request and response look are below. I am getting the response back as one large hex string starting at 0008.. I need a way for the code to know how many addresses were sent to be read and what data size was requested and take that into account on printing out the data. Since the data size can change, I can not just split the string up using a definite value. I am not looking for actual code but rather just some ideas on how one could tackle this.
Request
00 06 - Opcode
00 00 - Block #
02 - Count
34 97 00 20 - Address 1
04 00 - Data Size 1 (bytes)
30 97 00 20 - Address 2
01 00 - Data Size 2 (bytes)
Response- 00080001e60300009
00 08 - Opcode
00 01 - Block #
e6 03 00 00 - Data 1
09 - Data 2
What I am printing right now- e603000009
How I want it printed - Address 1 = e6030000
Address 2 = 09 ...
Address 3 = 00 00
etc.
(it would know what it is a new data by the data size that was requested and the # of addresses that were requested)
Part of code where I am sending a read request and emitting it to html
app.post('/output3', function(req, res){
res.sendFile(__dirname + '/upload3.html');
//Define the host and port values of UDP
var HOST= '192.168.0.136';
var PORT= 69;
var io = require('socket.io')(http);
//Mulitple parameters
//setInterval will send message constantly.
var client= dgram.createSocket('udp4');
var counter = 0;
//array for addresses
var address=[];
//array for size
var size=[];
//iterate through all addresses and convert to little endian
for (var i=0; i<req.body.address.length; i++) {
var n= req.body.address[i];
var s = n.toString(16).match(/.{1,2}/g);
address[i]= s.reverse().join("").toString(16); // ==> "0x985c0020" (= 2556166176)
}
//iterate through all size and make hex strings and little endian
for (var i=0; i<req.body.size.length; i++) {
function pad(number, length) {
var my_string = '' + number;
while (my_string.length < length) {
my_string = '0' + my_string;
}
return my_string;
}
var n2= pad(req.body.size[i], 4);
var s2 = n2.toString(16).match(/.{1,2}/g);
size[i]= s2.reverse().join("").toString(16);
}
//empty string to add address and size together
var x='';
for (var i=0; i<req.body.address.length; i++) {
x += address[i]+size[i];
}
console.log(req.body.size);
var mrq= read(x);
//Open listener to recieve intial message and print in to webpage
io.on('connection', function(socket){
var mrq= read(x);
io.emit('mrq', mrq);
});
function read() {
// Memory Read Request is a 16-bit word with a value of 6
var message = '0006'
// Block number is a 16-bit word that we will always set to 0
message += '0000'
// Count is variable, and calculated by the size of the parameter list
message += '02'
for (var i=0; i < arguments.length; i++) {
message += arguments[i];
}
return message;
}
var message = new Buffer(mrq, 'hex');
counter++;
var loop= setInterval(function () {
//Sends packets to UDP and setInterval sends packets again for specific time
client.send(message, 0, message.length, PORT, HOST, function (err, bytes) {
if (err) throw err;
});
if (counter === 1000000000000000) {
clearInterval(loop);
}
}, 1/50);
//Open listener to recieve intial message and print in to webpage
io.on('connection', function(socket){
client.on('message', function( message, rinfo ){
//hex string
var temp = message.readUIntBE(0, 2);
//console.log(message.toString(16));
io.emit('temp', temp);
});
});
Showing your current code would help us answer this better.
but in general, the way would be to use a write stream and push your string out in chunks, rather than as a whole block.
Related
I'm tinkering w/ zwack (https://github.com/paixaop/zwack) and trying to see what(HEX) are being written to the buffer in an effort to try to simulate a FTMS machine/server
The code
onReadRequest(offset, callback) {
debugFTMS('[SupportedPowerRangeCharacteristic] onReadRequest');
let buffer = new Buffer.alloc(6);
let at = 0;
let minimumPower = 0;
buffer.writeInt16LE(minimumPower, at);
at += 2;
let maximumPower = 1000;
buffer.writeInt16LE(maximumPower, at);
at += 2;
let minimumIncrement = 1;
buffer.writeUInt16LE(minimumIncrement, at);
at += 2;
debugFTMS('[SupportedPowerRangeCharacteristic] onReadRequest:' + buffer);
console.log(buffer);
callback(this.RESULT_SUCCESS, buffer);
}
the console.log(buffer) command outputs
<Buffer 00 00 e8 03 01 00>
I would like to roll this up into the debug messages instead. Specifically into this line
debugFTMS('[SupportedPowerRangeCharacteristic] onReadRequest:' + buffer);
but the result I'm getting is some unprintable characters
ftms [SupportedPowerRangeCharacteristic] onReadRequest:� +0ms
You can use util.inspect to format a buffer that way.
const util = require('util');
...
debugFTMS('[SupportedPowerRangeCharacteristic] onReadRequest:' + util.inspect(buffer));
const net = require('net')
const sockets = []
server.on('connection', sock => {
log("tcp_server", "info", `Connected at ${sock.remoteAddress}:${sock.remotePort}`)
sockets.push(sock);
// Write the data back to all the connected, the client will receive it as data from the server
sockets.forEach((sock, index, array) => {
})
sock.on('data', data => {
})
// Add a 'close' event handler to this instance of socket
sock.on('close', data => {
}) // end sock.on
})
server.listen(conf.port, conf.serverHost, () => {
const address = server.address()
const port = address.port
const family = address.family
const ipaddr = address.address
log("tcp_server", "info", 'Server is listening at port ' + port)
log("tcp_server", "info", 'Server ip :' + ipaddr)
log("tcp_server", "info", 'Server is IP4/IP6 : ' + family)
})
this is my socket tcp server
and i faced problem with receive chunk data in c# its easy to receive every chunk if i know the size of it
and i can control how much byte i want to receive every time
now in NodeJs i can get the buffer length by get first 5 byte
and then get the size of the message
var size = (buff[1] << 24) | (buff[2] << 16) | (buff[3] << 8) | buff[4];
i tried this simple code for get the chunk data and process it
first i define a Buffer in top
var mybuffer = Buffer.alloc(30);
var length = 0;
sock.on('data', data => {
data.copy(mybuffer, length , 0, data.length); //copy buffer to mybuffer
length += data.length;
//now check if my length is 5 or greater i can determine the buffer size i sent
size = (buff[1] << 24) | (buff[2] << 16) | (buff[3] << 8) | buff[4];
//now need to continue receive until i reach (size - length) = total bytes i sent
})
this what i tried for receive all the chunk but still need more work
any idea how to receive all data depend on size i sent on first 5 bytes of every message
I found this code easysocket! similar to what i want i just made simple edit to the code and its work like charm
I am sending a valid JSON object constructed with ArduinoJSON to a RaspberryPi running node.js with the library https://github.com/natevw/node-nrf over a nrf24 radio link. The node.js server receives the data seemingly without problem. But for some reason I can't JSON.parse() the object (or buffer?) without getting a SyntaxError: Unexpected token in JSON at position ...
For some reason the node-nrf library receives data backwards, so i need to reverse the order of the bytes with Array.prototype.reverse.call(d), and then console.log(d.toString()) and everything seems fine. In this case, the console gets Got data: [{"key":"a1","value":150}]. At this point, the content of the buffer looks like : Buffer 5b 7b 22 6b 65 79 22 3a 22 61 31 22 2c 22 76 61 6c 75 65 22 3a 31 35 30 7d 5d 00 00 00 00 00 00. Those are the actual 32 bytes that the nrf24 buffer contains i guess.
But then, when the code gets to the JSON.parse() call, i get SyntaxError: Unexpected token in JSON at position 26. This is the position my object data actually ends in the buffer.
I've also experimented with .toJSON() and JSON.stringify() , but can't actually get a proper object to use ( ie. obj.key, obj.value). It's only returning undefined properties. It seems to me the parsing fails when it reaches the end of the object. I've also tried to match the buffer size with the actual size of the message just to see if the parsing would succeed to no avail !
I am probably very mixed up in concepts of buffers, streams, pipes and objects ... what am i doing wrong ?
I need ideas (or fixes!)
Code running on the receiving end in node.js:
var nrf = NRF24.connect(spiDev, cePin, irqPin);
nrf.printDetails();
nrf.channel(0x4c).transmitPower('PA_MIN').dataRate('1Mbps').crcBytes(2).autoRetransmit({count:15, delay:4000}).begin(function () {
var rx = nrf.openPipe('rx', pipes[0]);
rx.on('data', d => {
let obj = Array.prototype.reverse.call(d);
try {
console.log("Got data: ", d.toString());
console.log(obj);
obj = JSON.parse(obj);
console.log(obj);
} catch (err) {
console.error(err)
}
});
});
I don't think the problem is here in forming the JSON message. But for reference purposes, this is the code running on the Arduino:
#include <SPI.h>
#include <nRF24L01.h>
#include <RF24.h>
#include <ArduinoJson.h>
const uint64_t addresses[5] = {0x65646f4e32LL,0x65646f4e31LL} ;
RF24 radio(7,8);
char output[32];
void setup()
{
Serial.begin(115200);
radio.begin();
radio.setAutoAck(true);
radio.setDataRate(RF24_1MBPS);
radio.enableDynamicPayloads();
radio.setCRCLength(RF24_CRC_16);
radio.setChannel(0x4c);
radio.setPALevel(RF24_PA_MAX);
radio.openWritingPipe(addresses[0]);
}
void loop()
{
const int capacity = JSON_ARRAY_SIZE(2) + 2*JSON_OBJECT_SIZE(2);
StaticJsonBuffer<capacity> jb;
JsonArray& arr = jb.createArray();
JsonObject& obj1 = jb.createObject();
obj1["key"] = "a1";
obj1["value"] = analogRead(A1);
arr.add(obj1);
arr.printTo(output);
bool ok = radio.write(&output, sizeof(output));
arr.printTo(Serial);
Serial.print(ok);
delay(1000);
}
Most likely you have NUL characters at the end of the string. JSON.parse will refuse to parse it.
let obj = '[{"key":"a1","value":150}]\x00\x00\x00\x00\x00\x00';
JSON.parse(obj);
Uncaught SyntaxError: Unexpected token in JSON at position 26
If you remove the NUL characters, parsing succeeds:
let obj = '[{"key":"a1","value":150}]\x00\x00\x00\x00\x00\x00';
obj = obj.replace(/\0/g, "");
JSON.parse(obj);
Parse 'buffer data' into 'string' like:
rx.on('data', d => {
try {
let obj = d.toString();
console.log(obj);
obj = JSON.parse(obj);
console.log(obj);
} catch (err) {
console.error(err)
}
});
To create a utf-8 buffer from a string in javascript on the web you do this:
var message = JSON.stringify('ping');
var buf = new TextEncoder().encode(message).buffer;
console.log('buf:', buf);
console.log('buf.buffer.byteLength:', buf.byteLength);
This logs:
buf: ArrayBuffer { byteLength: 6 }
buf.buffer.byteLength: 6
However in Node.js if I do this:
var nbuf = Buffer.from(message, 'utf8');
console.log('nbuf:', nbuf);
console.log('nbuf.buffer:', nbuf.buffer);
console.log('nbuf.buffer.byteLength:', nbuf.buffer.byteLength);
it logs this:
nbuf: <Buffer 22 70 69 6e 67 22>
nbuf.buffer: ArrayBuffer { byteLength: 8192 }
nbuf.buffer.byteLength: 8192
The byteLength is way to high. Am I doing something wrong here?
Thanks
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/ArrayBuffer
ArrayBuffer.prototype.byteLength Read only
The size, in bytes, of the array. This is established when the array is constructed and cannot be changed. Read only.
It seems you should not assume byteLength property to be equal to the actual byte length occupied by the elements in the ArrayBuffer.
In order to get the actual byte length, I suggest using Buffer.byteLength(string[, encoding])
Documentation: https://nodejs.org/api/buffer.html#buffer_class_method_buffer_bytelength_string_encoding
For example,
var message = JSON.stringify('ping');
console.log('byteLength: ', Buffer.byteLength(message));
correctly gives
byteLength: 6
I have a BLE (Bluetooth 4.0)pedometer device from which I want to read the characteristic data using Evothings plugin (which uses Javascript API to interact with the device)
I am using following code -
callback when device is connected =
function deviceConnected(device) {
console.log('Connected to device: ' + device.name)
console.log('Reading services... Have patience!')
device.readServices(
null, // null means "read all services".
readAllServicesCharacteristicsAndNotifications,
// listAllServicesCharacteristicsDescriptors,
readServicesError)
}
callback code for readAllServicesCharacteristicsAndNotifications -
function readAllServicesCharacteristicsAndNotifications(device) {
// Get data for each service
console.log('number of services ' + device.__services.length)
console.log('number of characteristic ' + device.__services[0].__characteristics.length)
//var characteristic = service.__characteristics[characteristicUUID]
device.readCharacteristic(
device.__services[0].__characteristics[8]['uuid'],
function (data) {
var test = new Uint8Array(data);
var result = "";
for (var i = 0; i < test.length; i++) {
console.log('data element is ' + test[i]);
console.log('data element string is ' + String.fromCharCode(parseInt(test[i], 2)));
result += String.fromCharCode(parseInt(test[i], 2));
}
console.log('data is ' + result);
},
function (errorCode) {
console.log('BLE readCharacteristic error: ' + errorCode);
});
}
I think BLE data formatsuggests that data is exchanged as binary code bytes.
I see the value in the byte array but I don't know how to interpret it.
Has anyone used Evothings Javascript to interact with BLE device?
H i, the data received in JavaScript over BLE is a byte buffer.
See if you can find the documentation for the pedometer. Lookup at the format of the data sent from the pedometer. Then access the data in the buffer accordingly.
Here are some examples.
Access byte values in the data buffer:
var buf = new Uint8Array(data);
var value1 = buf[0];
var value2 = buf[1];
To get a 16-bit value use bitwise OR, for example:
var value = buf[0] | (buf[1] << 8);
Depending on data being little endian or big endian, the bitwise OR needs to be done in different ways.
Here is a library you can use that has functions for accessing values in a byte buffer: https://github.com/evothings/evothings-examples/blob/master/resources/libs/evothings/util/util.js
Here is an example:
// Get the signed int value in the buffer thats starts at
// byte index 2 (the int value represented by byte 2 and 3).
var value = evothings.util.littleEndianToInt16(data, 2)
Hope this helps!