I listen to a port in real time, I use the nodejs serialport module, but I use the same port to send other information. I use this following code which prevents me from using the port:
```port.on('readable', function () {
if(port.read() === "h"){
//
}
})```
I was thinking of something like checking the number of bytes in the buffer like in python serialport and arduino, the objective is to avoid blocking the port as the previous code does.
I was thinking of using port.read() to evaluate the buffer bits but it always returns null .
```
if (port.read() > 0){
//read data
}
```
Related
I have a legacy device from which I need to receive serial data and it does not send a delimiter. Therefore I need to send every byte I receive to a function. My code is written in Javascript and I use node.js with the npm serialport package. I have tried the following code, but it still does not send the data to my serialHandler function unless a return (\r) is received.
I was expecting it to send each byte received to the serialHandler function without the need of a delimiter, but in my troubleshooting, it did not send anything to the function until it received the \r delimiter. It then parsed it by each byte as expected.
How can I send each byte received to the serialHandler function without using a delimiter?
node version 16.17.0
serialport version 10.5.0
Here is the code.
const {SerialPort} = require('serialport');
const { ByteLengthParser } = require('#serialport/parser-byte-length');
const port = new SerialPort({ //set serial port pins and baudrate
path: '/dev/ttyAMA1',
baudRate: 115200
});
const serialParser = port.pipe(new ByteLengthParser({ length: 1 }));
serialParser.on('data', serialHandler);
function serialHandler(serialChar){
//does stuff
}
I've figured out that it was actually the sending software I was testing with(Putty) that was causing my issues. It had local line editing forced on, causing it only to send data when you pressed Enter.
I have an esp32 board loaded with this software which is logging values about the number of detected Wi-Fi and Bluetooth devices detected via LoraWAN. In senddata.cpp it seems to be logging out the values that I need (though I'm not quite sure I understand how or where it is sending them via serial):
ESP_LOGD(TAG, "Sending count results: pax=%d / wifi=%d / ble=%d", count.pax, count.wifi_count, count.ble_count);
I set up a node.js app with the SerialPort.io library to be able to read data coming over serial. I've successfully identified the COM port on my PC that is receiving data, and I can log out the data buffer as follows:
const SerialPort = require("serialport").SerialPort;
const serialPort = new SerialPort({
path: "COM4",
baudRate: 9600,
autoOpen: false,
});
serialPort.open(function (error) {
if (error) {
console.log("failed to open: " + error);
} else {
console.log("serial port opened");
serialPort.on("data", function (data) {
// get buffered data and parse it to an utf-8 string
console.log(data);
data = data.toString("utf-8");
console.log(data);
});
serialPort.on("error", function (data) {
console.log("Error: " + data);
});
}
});
Which yields output in node.js as a buffer, e.g. <Buffer bc 08 AD>, but after the toString("utf-8") it is a bunch of gibberish. Clearly I am not encoding or decoding the serial output properly, but I'm not sure where to make adjustments. Does anyone know how I can get this serial output into the proper format to use in node.js?
--- Update Re: Questions ---
The board is a ttgo / lilygo lora32 - the library I used seems to say it supports both this board and communication over SPI. I am able to get readable data via the debug console with the platform.io extension for VSCode on Windows / Mac. I believe the baud is 9600, which was the only thing I seemed to need to specify on the serialports.io side.
I did receive this advice from the library author:
You need
a messagebuffer, to store the payload
a queue, as buffer for the serial data
a protocol, suitable for your application
1+2: see spislave.cpp (change the SPI transmit calls by serial port calls)
3: consider overhead and checksum, e.g. transfer the payload as byte array or UTF8 string, e.g. comma separated string with checksum, as used in NMEA.
Unfortunately I'm a bit out of my depth to make sense of that (though I'm working on it).
Also - the JavaScript code that has successfully worked via the things network uses to decode the payload from the board is here.
Does anyone know how I can get this serial output into the proper format to use in node.js?
It looks like many of the smaller/older boards this software interfaces with use baud 9600, but line 98 of main.cpp specifies a baud rate of 115200 for the debug messages:
// setup debug output or silence device
#if (VERBOSE)
Serial.begin(115200);
esp_log_level_set("*", ESP_LOG_VERBOSE);
I suspect switching to a baud rate of 115200 will help:
const serialPort = new SerialPort({
path: "COM4",
baudRate: 115200,
autoOpen: false,
});
If that doesn't do the trick, you can make sure the other serial parameters match those set in main.cpp, starting at line 394. UART0 is the one that emits the log messages on the ESP:
static void ble_spp_uart_init(void)
{
uart_config_t uart_config = {
.baud_rate = 115200,
.data_bits = UART_DATA_8_BITS,
.parity = UART_PARITY_DISABLE,
.stop_bits = UART_STOP_BITS_1,
.flow_ctrl = UART_HW_FLOWCTRL_RTS,
.rx_flow_ctrl_thresh = 122,
.source_clk = UART_SCLK_DEFAULT,
};
...
Looking at the API, you could specify the other parameters like so:
const serialPort = new SerialPort({
PATH: "COM4"
baudRate: 115200,
databits: 8,
parity: false,
stopbits: 1,
});
though I'm not quite sure I understand how or where it is sending them via serial
The ESP_LOG functions are really just special wrappers around vprintf. vprintf normally writes to stdout by default but the ESP redirects that to a dedicated UART (serial port). Check out the source:
static vprintf_like_t s_log_print_func = &vprintf;
void esp_log_writev(esp_log_level_t level,
const char *tag,
const char *format,
va_list args)
{
if (!esp_log_impl_lock_timeout()) {
return;
}
esp_log_level_t level_for_tag = s_log_level_get_and_unlock(tag);
if (!should_output(level, level_for_tag)) {
return;
}
(*s_log_print_func)(format, args);
}
That UART handles the encoding and buffers required to transmit over the serial port.
You need to check following things :
Check if baud rates of both the esp32 and node.js are same - most of the time garbage data received on COM if COM port configuration is not done properly.
Need to check, what data you are expecting and what is the format -is it in text (utf8) format or some binary format ? Accordingly you need to parse the out put.
It would be clear once you post a sample data the esp32 is sending and the buffer you are receiving on Node.js code.
I'm using the code below to try send OSC messages to a computer on the network. I'm using a package called osc.
I'm unable to send messages to the machine running the OSC server and receive the error below when attempting to send OSC messages:
Error: Uncaught, unspecified "error" event. (Can't send packets on a closed osc.Port object. Please open (or reopen) this Port by calling open().)
Code
let osc = require('osc');
let oscUDP = new osc.UDPPort({
remoteAddress: "192.168.1.5",
remotePort: 8004
});
oscUDP.send({
address: "/carrier/frequency",
args: 440
});
oscUDP.open();
If I put oscUDP.open() before the send call I get a different error:
Error: send EINVAL 192.168.1.5:8004
at Object.exports._errnoException (util.js:1007:11)
at exports._exceptionWithHostPort (util.js:1030:20)
at SendWrap.afterSend [as oncomplete] (dgram.js:402:11)
I am running OSCulator on OSX as the server. The code above lives on a different machine. When I run nmap on the IP address the port is open:
nmap 192.168.1.5 -p 8004
Starting Nmap 6.40 ( http://nmap.org ) at 2016-08-30 08:22 BST
Nmap scan report for 192.168.1.5
Host is up (0.13s latency).
PORT STATE SERVICE
8004/tcp open unknown
If I use osc-cli the messages are received on the machine running the OSC server:
osc --host 192.168.1.5:8004 /test 1 2 3
So it would seem the problem isn't with closed ports at all as the messages are sent and received when using osc-cli.
Any ideas?
I know I'm coming to this quite late, and it looks like you found a different library that works for you, but I thought a response might be helpful for others who are facing this issue. I'm the developer of osc.js, the original library you were trying to use.
First off, as background information, osc.js is factored into two different layers:
The low-level API that provides functions for reading and writing OSC messages and bundles to/from Typed Arrays.
The higher-level, event-based Port API, which provides a collection of platform-specific transport objects, which offer an easy way to do bidirectional communication over protocols like UDP, Web Sockets, etc.
In the case of your example code, you were trying to send an OSC message on your UDPPort object prior to it being ready. When you open() a Port, it may need to perform asynchronous operations such as opening up a socket, etc. As a result, it fires an event (aptly called ready) when the Port is all set to be used. Until ready fires, you won't be able to send or receive OSC packets.
So in the case of your original code, it looks like you were assuming that this line was synchronous and that you could call send() immediately afterwards:
oscUDP.open();
Instead, you just needed to listen for the ready event prior to attempting to send a message on the Port. Like this:
oscUDP.on("ready", function () {
oscUDP.send({
address: "/carrier/frequency",
args: 440
});
});
The osc.js Node.js example illustrates this pattern. But when I saw your question, I realized that the sample code in the osc.js README was a bit ambiguous in this regard. I have improved the event documentation and the inline README sample code to be more clear in this regard. Sorry for the confusion.
There are cases, perhaps such as yours, where the higher-level API isn't quite what you need. osc.js also provides functions for easily encoding an OSC packet as a Uint8Array, which can be converted into a Node.js buffers. So you could have done something similar to your solution just by using osc.js' osc.writeMessage() function. It has always been quite well documented, fortunately. Here's your example, modified to use osc.js' low-level API:
const dgram = require('dgram');
const client = dgram.createSocket('udp4');
const osc = require('osc');
const HOST = '192.168.1.5';
const PORT = 8004;
process.on('SIGINT', function() {
client.close();
});
let oscNoteMessage = function(note, value) {
var message = osc.writeMessage({
address: '/note/' + note,
args: [
{
type: 'i',
value: value
}
]
});
return Buffer.from(message);
}
let noteOn = function(note) {
return oscNoteMessage(note, 1);
}
let noteOff = function(note) {
return oscNoteMessage(note, 0);
}
let send = function(message) {
client.send(message, PORT, HOST, function(err, bytes) {
if(err) throw new Error(err);
})
}
send(noteOn('c'));
setTimeout(function() {
send(noteOff('c'));
}, 1000);
Anyway, I'm glad you were able to come up with a solution that works for your project, and I hope this response helps other users who may encounter similar issues. And of course, feel free to ask questions or file issues on the osc.js issue tracker.
Best regards, and apologies for the trouble you experienced using the library!
I figured it's actually pretty easy to send OSC data over UDP without the need for any packages except a2r-osc which is used for encoding OSC data.
I'm posting the solution incase anyone else in interested:
const dgram = require('dgram');
const client = dgram.createSocket('udp4');
const osc = require('a2r-osc');
const HOST = '192.168.1.5';
const PORT = 8004;
process.on('SIGINT', function() {
client.close();
});
let noteOn = function(note) {
return new osc.Message('/note/' + note, 'i', 1).toBuffer();
}
let noteOff = function(note) {
return new osc.Message('/note/' + note, 'i', 0).toBuffer();
}
let send = function(message) {
client.send(message, PORT, HOST, function(err, bytes) {
if(err) throw new Error(err);
})
}
send(noteOn('c'));
setTimeout(function() {
send(noteOff('c'));
}, 1000);
I am trying to receive and send data from a vacuum gauge (previous Model of https://www.pfeiffer-vacuum.com/en/products/measurement/digiline/gauges/?detailPdoId=13238&request_locale=en_US) with a computer (Linux 16.04) via an USB-to-RS485-Interface (the half-duplex USB485-STISO from http://www.hjelmslund.dk/). When I send a request to the gauge using a specific protocol it is supposed to answer to the request and I should be able to receive it with the interface. I managed to send data but whenever I send data, it seems that nothing comes back. I'm trying to do this with Node.js. The Code that I used so far is:
function pack(address, action, parameter, data) {
var length = String('00' + data.length.toString()).slice(-2);
var bufferAsString = address + action + parameter + length + data;
var check = 0;
for (var i = 0; i < bufferAsString.length; ++i) {
check += bufferAsString.charCodeAt(i)
}
var checkSum = String('000' + String(check % 256)).slice(-3);
var buffer = Buffer.from(bufferAsString + checkSum),
carriageReturn = Buffer.from('\r');
return Buffer.concat([buffer, carriageReturn]);
}
var serialPort = require('serialport');
var SerialPort = serialPort.SerialPort;
var port = new SerialPort('/dev/ttyUSB0', {
baudrate: 9600,
dataBits: 8,
stopBits: 1,
parity: 'none'
}, false);
port.open(function(err) {
if (err) {
return console.log('Error opening port: ', err.message);
}
console.log(port.isOpen());
port.on('data', function (data) {
console.log('Data: ' + data);
});
port.on('close', function() {
console.log('port closed')
});
var sendBuffer = pack('001', '00', '740', '=?');
setInterval(function() {
port.write(sendBuffer, function(err, bytes) {
console.log('send' + bytes)
});
port.drain();
}, 1000)
});
That is supposed to send a request every second to the gauge to measure the pressure. I know that the request is being send since the TxD-Led blinks shortly every second. But I receive no answer to that request.
I also tried other methods of sending data (mostly via python and the terminal) but with similar success. The green lamp for sending always flashes up but then nothing happens and no answer is received.
I am at a loss as to what to try next and would really appreciate any help that you could give me.
UPDATE:
Ok so I seem to have found one possible error in the whole thing. I was working with an oszilloscope to capture the signal that is going out of the interface when I send something. I started with single ascii-characters to see if the most basic signals are cominng out right. For ascii '0' the signal that is being sent is 10000011001, for ascii '1' it is 10100011001. So those are almost what I would expect, except that there seem to be 2 startbits. Normally I would expect there to be only 1 startbit. Is there a way to change the amount of startbits sent?
Here are the outputs of the Oszilloscope:
this is a communication problem:
1 check the protocol-based communications parameters like baud rate, parity, start-/stop-bits they have to be consistent
(if you use UART protocol on RS-485 other protocols like MODBUS, Profibus,... are also possible, this is a difference to normal RS-232)
If the gauge uses 9600 baud for communication you can not use 115200 baud in your command. In the nodejs code you do not set any parameter (i assume you use the UART protocol because of your nodejs). If the gauge uses any other protocol the nodejs code will also not work, despite that there are not set any parameters like baud rate, parity,... in the code
https://en.wikipedia.org/wiki/RS-485
for other protocols node js serial module can not be used
http://libmodbus.org/
http://www.pbmaster.org/
2 check the proprietary commands you send to the gauge. When i want to read out the data of my multimeter i have to send an ASCII 'D' = 0100 0100 (bin) to get an answer (endianness ?) If i send any other value the multimeter stays silent.
http://electronicdesign.com/what-s-difference-between/what-s-difference-between-rs-232-and-rs-485-serial-interfaces
Unless you have DE pulled high and R︦E︦ tied to ground, your conversation will be rather one-sided.
And if you do wire as above, you need to be able to deal with your own echo in the received data.
I'm working on an Arduino project to control motors and read sensors. I decided to use the web view using Node.js as a medium channel to read/write from the serial port to the browser using either libraries (SerialPort and SerialPort2).
Both are working fine when I connect the Arduino directly to the USB device using a wire, but Node.js can't seem to read anything when I connect the Arduino to the USB device through my wireless adapter** (APC220) even though I can read everything received on it using the Arduino serial monitor.
I checked every possible reason behind that; I checked the baud-rate I'm using for the Arduino communication with the wirelss serial and the APC220 and the bridge connector (USB-to-serial converter). They all have the same settings: 9600 baud-rate, no parity /flowcontrol, data bits: 8 , stop bits: 1.
The behavior is as follows. It connects to the COM port without trouble, and then I tried printing the errors, but it seems there are none identified by either SerialPort libraries. Then no reading comes to the event (data), which means it (Node.js) is not interacting with the serialport even though it is open.
Note:
I know I can use another Arduino as a medium between the USB port and the wireless adapter, but I want to understand this problem and solve it cleanly without such work around.
What could the problem be?
server [node.js]:
var SerialPort = require('serialport2').SerialPort;
var portName = 'COM15';
var io = require('socket.io').listen(8000); // Server listens for socket.io communication at port 8000
io.set('log level', 1); // Disables debugging. This is optional. You may remove it if desired.
var sp = new SerialPort(); // Instantiate the serial port.
sp.open(portName, { // portName is instatiated to be COM3, replace as necessary
baudRate: 9600, // This is synchronised to what was set for the Arduino code
dataBits: 8, // This is the default for Arduino serial communication
parity: 'none', // This is the default for Arduino serial communication
stopBits: 1, // This is the default for Arduino serial communication
flowControl: false // This is the default for Arduino serial communication
});
io.sockets.on('connection', function (socket) {
// If socket.io receives message from the client browser then
// this call back will be executed.
socket.on('message', function (msg) {
console.log(msg);
});
// If a web browser disconnects from Socket.IO then this callback is called.
socket.on('disconnect', function () {
console.log('disconnected');
});
});
var cleanData = ''; // This stores the clean data
var readData = ''; // This stores the buffer
sp.on('data', function (data) { // Call back when data is received
readData = data.toString(); // Append data to buffer.
// If the letters '[' and ']' are found on the buffer then isolate what's in the middle
// as clean data. Then clear the buffer.
console.log(readData); // **Here you should be able to print the data if you receive any**
if (readData.indexOf(']') >= 0 && readData.indexOf('[') >= 0) {
cleanData = readData.substring(readData.indexOf('[') + 1, readData.indexOf(']'));
readData = '';
console.log("-- "+cleanData);
io.sockets.emit('message', cleanData);
}else if(readData.indexOf('[') >= 0){
cleanData = readData.substring(readData.indexOf('[') + 1, readData.length);
readData = '';
}else if(readData.indexOf(']') >= 0){
cleanData += readData.substring(0, readData.indexOf(']'));
readData = '';
console.log("-- "+cleanData);
io.sockets.emit('message', cleanData);
}else{
cleanData += readData;
readData = '';
}
//console.log(readData);
//io.sockets.emit('message', readData);
});
While the monitor is running no other program can read the serial port.
In case you do not open both at the same time then things are more tricky. My suggestion would be to spy on the wire. That is: install Wireshark and have a look at the data on the serial connection / USB bus.
You might also want to check how the serial port of the APC220 and the Arduino differ with regard to their serial/USB converters. Another idea would be to analyze this issue under Linux since may allow more insights into the low-level differences of the chip sets / USB activity. Of course if you do not have Linux experience this is hard to do, but maybe you know some Linux enthusiasts.
Well, both your codes look all right, so I'm pretty sure your problem is something obvious (like the nose in the middle of your face) that you don't see because you're too focused on details. So here's a checklist I'd do first:
Are you sure your serial interface is the COM15, and never changes?
Are you sure both APC devices have correct baudrate configured?
Did you try making your Arduino send a simple code that sends the same thing over the channel?
Like:
void loop() {
...println("TEST");
delay(1000);
}
And on your host:
sp.on('data', function (data) {
console.log(data.toString());
});
When you get something buggy in your system, try to build the most simple use case of that buggy part, so you're sure that's nothing else in your codes that interferes with that. You don't need to make your Arduino work on the GPS stuff, as well as your Node.js stuff work on the web stuff.
Just make it the most simple as you can. (And don't forget to add a delay in your Arduino loop, or you may have difficulties reflashing the chip).
You may also want to add to your code the error catching part of serialport2:
port.on('error', function(err) {
console.log("ERROR receiving serial data: ", err);
});
As well as for your open() statement:
sp.open(portName, portConfig, function (err) {
console.log("ERROR opening serial port: ", err);
});
As you may be missing error reporting on the host side!