serialport / node-serialport

Access serial ports with JavaScript. Linux, OSX and Windows. Welcome your robotic JavaScript overlords. Better yet, program them!
https://serialport.io
MIT License
5.82k stars 1.01k forks source link

SerialPort in Galileo Gen 2 running Yocto #747

Closed ortizvinicius closed 8 years ago

ortizvinicius commented 8 years ago

I'm trying to set a Serial Communication in a Intel Galileo Gen 2 with Linux Yocto, but I only get the message "Illegal Instruction".

Issue opened before in the wrong place: https://github.com/rwaldron/johnny-five/issues/1086

The code:

var Serialport = require("serialport").SerialPort;
var sp = new Serialport("/dev/ttyS0", {
  baudRate: 57600
});

sp.on("open", function() {
  console.log("Port is open!");

  // Once the port is open, you may read or write to it.
  sp.on("data", function(data) {
    console.log("Received: ", data);
  });

  sp.write(new Buffer("0120000003"));
});

Already tried to use the last beta version of SerialPort.

ortizvinicius commented 8 years ago

To make sure i'm not doing anything wrong:

npm cache clean -f
npm install -g n
n stable
cd /sys/class/gpio                                                                         
echo -n "28" > export
echo -n "32" > export
echo -n "45" > export
cd gpio28
echo -n "out" > direction
echo -n "0" > value
cd gpio32
echo -n "out" > direction
echo -n "1" > value
cd gpio45
echo -n "out" > direction
echo -n "1" > value
stty -F /dev/ttyS0 57600
ortizvinicius commented 8 years ago

I think node-pre-gyp rebuild worked, but i can only test tomorrow, and keep you updated

fivdi commented 8 years ago

Yes, node-pre-gyp rebuild works around the Illegal Instruction issue.

It's definitely the case that pre-compiled binaries that result in Illegal Instruction errors are being installed initially:

root@galileo:~/serialport# npm install serialport
|
> serialport@2.0.7-beta5 install /home/root/serialport/node_modules/serialport
> node-pre-gyp install --fallback-to-build

[serialport] Success: "/home/root/serialport/node_modules/serialport/build/Release/serialport.node" is installed via remote
serialport@2.0.7-beta5 node_modules/serialport
├── bindings@1.2.1
├── sf@0.1.7
├── async@0.9.0
├── debug@2.2.0 (ms@0.7.1)
├── nan@2.2.1
├── object.assign@4.0.3 (function-bind@1.1.0, object-keys@1.0.9, define-properties@1.1.2)
└── optimist@0.6.1 (wordwrap@0.0.3, minimist@0.0.10)
root@galileo:~/serialport# 

And that node-pre-gyp rebuild creates new binaries which don't result in Illegal Instruction errors:

cd node_modules/serialport/
./node_modules/node-pre-gyp/bin/node-pre-gyp rebuild
cd ../..
ortizvinicius commented 8 years ago

YEP, everything seems working fine after the rebuild, thank you guys!! @fivdi @rwaldron @reconbot

ortizvinicius commented 8 years ago

Actually i got another issue, @fivdi have you tested the serial communication? The first time i tested, i sent a string of characters and the arduino in the other side sent a string back, like it should be. So i made a setinterval to send the data repeatedly, the arduino receives and sends back normally, but in the galileo i receive the data only sometimes, and sometimes is a "broken" string.

fivdi commented 8 years ago

Yes, I did a simple read/write test and it worked as expected. Which serialport on the Galileo are you using?

ortizvinicius commented 8 years ago

dev/ttyS0 and baudrate 57600

fivdi commented 8 years ago

I initially tested with /dev/ttyS1 on the Galileo FTDI header to avoid the pin muxing. A second test with /dev/ttyS0 also functioned as expected.

With the following on the Galileo:

var Serialport = require("serialport").SerialPort;
var sp = new Serialport("/dev/ttyS0", {
  baudRate: 57600
});
var i = 0;

sp.on("data", function (data) {
  console.log(''+data);
});

setInterval(function () {
  sp.write("Hello World " + i + "\r\n");
  i += 1;
}, 1000);

And the following at the other end on a Linux PC:

var Serialport = require("serialport").SerialPort;
var sp = new Serialport("/dev/ttyUSB0", {
  baudRate: 57600
});

sp.on("data", function (data) {
  sp.write(''+data);
});

This is some typical output on the Galileo:

root@galileo:~/serialport# node txrx.js 
Hello World 0

Hello Wo
rld 1

H
ello World 2

Hello Wo
rld 3

Hello Wo
rld 4

Hello Wo
rld 5

H
ello World 6

H
ello World 7

Hello Wo
rld 8

Hello Wo
rld 9

Hello Wo
rld 10

H
ello World 11

Hello Wo
rld 12

Hello Wo
rld 13

Hel
lo World 14

Hello Wo
rld 15

Hello Wo
rld 16

Hello Wo
rld 17

Hello Wo
rld 18

^Croot@galileo:~/serialport# 

This is the expected output on the Galileo. There was no data loss. Parsers can be used for readline style input if needed.

ortizvinicius commented 8 years ago

I think it can be something in the latest beta version, I installed the stable version of serialport and with parser it seems everything is ok now, thank you again

fivdi commented 8 years ago

For the second test I used serialport@2.0.7-beta5 on both the Galileo and the Linux PC.

fivdi commented 8 years ago

@ortizvinicius Can you reopen this issue please? Although everything may be working now a workaround was needed. People shouldn't be expected to node-pre-gyp rebuild after serialport has been installed.

ortizvinicius commented 8 years ago

Ok, sorry, issue opened again

reconbot commented 8 years ago

Can you run this on a Galileo?

console.log("platform:", process.platform);
console.log("arch:" , process.arch);
fivdi commented 8 years ago
platform: linux
arch: ia32
reconbot commented 8 years ago

@fivdi That's really weird, we don't publish binaries for that arch so it shouldn't have downloaded anything.

fivdi commented 8 years ago

@reconbot Are you 100% sure? ia32 is Intels 32-bit architecture. When serialport is installed on a very old Linux PC with a dual core Intel Pentium D CPU pre-compiled binaries are installed:

$ npm install serialport
\
> serialport@2.0.6 install /home/brian/serialport/node_modules/serialport
> node-pre-gyp install --fallback-to-build

[serialport] Success: "/home/brian/serialport/node_modules/serialport/build/Release/node-v46-linux-ia32/serialport.node" is installed via remote
serialport@2.0.6 node_modules/serialport
├── bindings@1.2.1
├── async@0.9.0
├── sf@0.1.7
├── nan@2.0.9
├── debug@2.2.0 (ms@0.7.1)
└── optimist@0.6.1 (wordwrap@0.0.3, minimist@0.0.10)
$ 

One line of the above output is

[serialport] Success: "/home/brian/serialport/node_modules/serialport/build/Release/node-v46-linux-ia32/serialport.node" is installed via remote

node-v46-linux-ia32 indicates that the platform is linux and the architecture is ia32. is installed via remote means that pre-compiled binaries were installed or at least that's what I'm assuming. Is this assumption correct?

reconbot commented 8 years ago

You're absolutely right, our 32bit vm's identify them selves as a ia32 and node-pre-gyp downloads their builds because the platform and arch matches.

I'm not really sure what to do about this. I know prebuild will actually try requiring the downloaded prebuilt binary to see if it actually works and if it doesn't it will build from source. I don't think we have any more flags we could include in the package name to help differentiate the platforms.

There might be build time flags we could pass to ensure this arch is also covered in the resulting binary but would require some investigation.

fivdi commented 8 years ago

It looks like there are two different classes of processors both of which are detected as having an ia32 architecture; old PC 32-bit processors like the Intel Pentium D and newer Intel Quark SoC X1000 Series processors. Unfortunately, the instruction sets supported by these different classes of processors are not identical. For example, the Intel Quark SoC X1000 Series processors lack support for SIMD instruction sets (see here.)

There might be build time flags we could pass to ensure this arch is also covered in the resulting binary but would require some investigation.

Yes, there may be.

Another potential solution would be to stop generating pre-compiled binaries for the combination platform=linux and arch=ia32 in order force a compile during the installation process. I'm unsure as to whether or not this is a good idea. It may not be as dramatic as it first sounds. It will depend on how many old Linux PCs with 32-bit processors are being used. It may also apply to 64-bit processors running the 32-bit variant of Linux. Are there download statistics available for the pre-compiled binaries? This information would help in making a decision.

reconbot commented 8 years ago

There isn't data as far as I know. But I'll see if the API exposes anything.

On Mon, Apr 11, 2016, 7:53 AM Brian Cooke notifications@github.com wrote:

It looks like there are two different classes of processors both of which are detected as having an ia32 architecture; old PC 32-bit processors like the Intel Pentium D and newer Intel Quark SoC X1000 Series processors. Unfortunately, the instruction sets supported by these different classes of processors are not identical. For example, the Intel Quark SoC X1000 Series processors lack support for SIMD instruction sets (see here https://en.wikipedia.org/wiki/Intel_Quark.)

There might be build time flags we could pass to ensure this arch is also covered in the resulting binary but would require some investigation.

Yes, there may be.

Another potential solution would be to stop generating pre-compiled binaries for the combination platform=linux and arch=ia32 in order force a compile during the installation process. I'm unsure as to whether or not this is a good idea. It may not be as dramatic as it first sounds. It will depend on how many old Linux PCs with 32-bit processors are being used. It may also apply to 64-bit processors running the 32-bit variant of Linux. Are there download statistics available for the pre-compiled binaries? This information would help in making a decision.

— You are receiving this because you were mentioned. Reply to this email directly or view it on GitHub https://github.com/voodootikigod/node-serialport/issues/747#issuecomment-208307066

reconbot commented 8 years ago

The api provides;

kidrobot:node-serialport$ ruby release_count.rb 2.0.6|sort -n
12  node-v14-darwin-ia32.tar.gz
21  node-v11-darwin-ia32.tar.gz
555 node-v47-linux-ia32.tar.gz
815 node-v46-linux-ia32.tar.gz
870 node-v11-win32-x64.tar.gz
986 node-v11-win32-ia32.tar.gz
1360    node-v14-linux-ia32.tar.gz
1361    node-v47-win32-ia32.tar.gz
1926    node-v11-darwin-x64.tar.gz
2020    node-v14-win32-ia32.tar.gz
2580    node-v14-win32-x64.tar.gz
2985    node-v11-linux-ia32.tar.gz
4040    node-v14-darwin-x64.tar.gz
4089    node-v46-win32-ia32.tar.gz
8075    node-v47-win32-x64.tar.gz
8525    node-v47-linux-x64.tar.gz
8960    node-v47-darwin-x64.tar.gz
9112    node-v46-darwin-x64.tar.gz
9761    node-v46-linux-x64.tar.gz
13093   node-v46-win32-x64.tar.gz
17336   node-v11-linux-x64.tar.gz
21058   node-v14-linux-x64.tar.gz

So there is a significant user base on ia32, there's no way to know more info about who requested them.

fivdi commented 8 years ago

Approximately 4.8% of the downloads were linux-ia32:

555 node-v47-linux-ia32.tar.gz
815 node-v46-linux-ia32.tar.gz
1360    node-v14-linux-ia32.tar.gz
2985    node-v11-linux-ia32.tar.gz

Pre-compiled binaries could still be provided for win32-ia32.

reconbot commented 8 years ago

I'm more inclined to provide the binaries and test them as an install step, ala Prebuild

fivdi commented 8 years ago

If my interpretation of the prebuild documentation is correct, it doesn't really "test" the binaries, it requires them and if that fails it will fallback to building from source. Unfortunately, it's currently possible to require the pre-built binaries on a Galileo without failure even though those binaries contain illegal instructions. The following will not throw illegal instruction errors on a Galileo with the pre-built binaries:

var Serialport = require("serialport").SerialPort;

I may be mistaken but I don't think prebuild will solve the problem. I think it will be necessary to tell the compiler not to generate instructions that the Intel Quark SoC X1000 Series doesn't understand for ia32 builds. According to the comments here, this can be achieved with the -mno-sse and -mno-mmx options. I'm not sure where these options should be specified though.

reconbot commented 8 years ago

I think I've got the gypfile adding these cflags for ia32 on linux. https://github.com/voodootikigod/node-serialport/compare/galileo-prebuilt I don't have a good way to get the compiled binaries off of our CI nor do I have a linux machine handy at the moment, so I can't really test to see if this solves this issue.

fivdi commented 8 years ago

@reconbot is there a link that can be used to install the pre-compiled binaries with npm install some-link-here?

reconbot commented 8 years ago

I just published serialport-galileo-test@3.1.1-beta1 for testing. I still want comment on #779 before we go this direction but at least this will prove if this approach works or not.

reconbot commented 8 years ago

Oh hey, I can dispel the myth that node-pre-gyp might not be requiring the binary. It does as part of the unpacking processes. So that's completely not an option.

node-pre-gyp info tarball done parsing tarball
node-pre-gyp info validate Running test command: '/Users/wizard/.nvm/versions/node/v4.4.3/bin/node --eval 'require(\'/Users/wizard/src/tmp/node_modules/serialport-galileo-test/build/Release/serialport.node\')''
fivdi commented 8 years ago

Oh hey, I can dispel the myth that node-pre-gyp might not be requiring the binary. It does as part of the unpacking processes. So that's completely not an option.

@reconbot I don't understand this. What myth? What's not an option?

I'll do some testing with serialport-galileo-test@3.1.1-beta1 on a Galileo 2 and an ia32 Linux PC.

fivdi commented 8 years ago

Something's wrong on the Galileo 2. Here's the output of npm install serialport-galileo-test

root@galileo:~/serialport-galileo-test# npm install serialport-galileo-test
-
> serialport-galileo-test@3.1.1-beta1 install /home/root/serialport-galileo-test/node_modules/serialport-galileo-test
> node-pre-gyp install --fallback-to-build

module.js:340
    throw err;
          ^
Error: Cannot find module 'nopt'
    at Function.Module._resolveFilename (module.js:338:15)
    at Function.Module._load (module.js:280:25)
    at Module.require (module.js:364:17)
    at require (module.js:380:17)
    at Object.<anonymous> (/home/root/serialport-galileo-test/node_modules/serialport-galileo-test/node_modules/node-pre-gyp/lib/node-pre-gyp.js:14:12)
    at Module._compile (module.js:456:26)
    at Object.Module._extensions..js (module.js:474:10)
    at Module.load (module.js:356:32)
    at Function.Module._load (module.js:312:12)
    at Module.require (module.js:364:17)

npm ERR! serialport-galileo-test@3.1.1-beta1 install: `node-pre-gyp install --fallback-to-build`
npm ERR! Exit status 8
npm ERR! 
npm ERR! Failed at the serialport-galileo-test@3.1.1-beta1 install script.
npm ERR! This is most likely a problem with the serialport-galileo-test package,
npm ERR! not with npm itself.
npm ERR! Tell the author that this fails on your system:
npm ERR!     node-pre-gyp install --fallback-to-build
npm ERR! You can get their info via:
npm ERR!     npm owner ls serialport-galileo-test
npm ERR! There is likely additional logging output above.
npm ERR! System Linux 3.8.7-yocto-standard
npm ERR! command "/usr/bin/node" "/usr/bin/npm" "install" "serialport-galileo-test"
npm ERR! cwd /home/root/serialport-galileo-test
npm ERR! node -v v0.10.35
npm ERR! npm -v 1.4.28
npm ERR! code ELIFECYCLE
npm ERR! not ok code 0
root@galileo:~/serialport-galileo-test# 

See also: https://github.com/voodootikigod/node-serialport/issues/780#issuecomment-217019406

reconbot commented 8 years ago

It's working on some platforms but not others, I bundled and published with 0.12, but 0.10 fails. I've released 3.1.1 to fix this issue and depreciated 3.1.0. I've also documented it in PUBLISHING.md.

Once the preinstall stuff is straightened out this wont be as painful.

reconbot commented 8 years ago

@fivdi I released a new version of the test package, it should have binaries built in 20 minutes or so

fivdi commented 8 years ago

Everything functions as expected on an ia32 Linux PC, but the illegal instruction errors are still occurring on the Galileo 2:

root@galileo:~/serialport-galileo-test# npm list | grep serialport
/home/root/serialport-galileo-test
└─┬ serialport-galileo-test@3.1.2-beta1
root@galileo:~/serialport-galileo-test# node -v
v0.10.35
root@galileo:~/serialport-galileo-test# npm -v
1.4.28
root@galileo:~/serialport-galileo-test# node
> var Serialport = require("serialport-galileo-test").SerialPort;
undefined
> var sp = new Serialport("/dev/ttyS0", {
...   baudRate: 57600
... });
undefined
> Illegal instruction
root@galileo:~/serialport-galileo-test# 

The illegal instruction is fucomi.

To see this, first get a core dump:

root@galileo:~/serialport-galileo-test# ulimit -c unlimited # turn on core dumps
root@galileo:~/serialport-galileo-test# node 
> var Serialport = require("serialport-galileo-test").SerialPort;
undefined
> var sp = new Serialport("/dev/ttyS1", {
...   baudRate: 115200
... });
undefined
> Illegal instruction (core dumped)
root@galileo:~/serialport-galileo-test# 

Then find the illegal instruction with gdb:

root@galileo:~/serialport-galileo-test# gdb node core.251 
GNU gdb (GDB) 7.6.2
Copyright (C) 2013 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.  Type "show copying"
and "show warranty" for details.
This GDB was configured as "i586-poky-linux".
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/>...
Reading symbols from /usr/bin/node...(no debugging symbols found)...done.
[New LWP 251]

warning: Could not load shared library symbols for linux-gate.so.1.
Do you need "set solib-search-path" or "set sysroot"?
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib/libthread_db.so.1".
Core was generated by `node'.
Program terminated with signal 4, Illegal instruction.
#0  0xb76629ac in Open(Nan::FunctionCallbackInfo<v8::Value> const&) () from /home/root/serialport-galileo-test/node_modules/serialport-galileo-test/build/Release/serialport.node
(gdb) 
(gdb) 
(gdb) thread apply all backtrace full

Thread 1 (Thread 0xb776b700 (LWP 251)):
#0  0xb76629ac in Open(Nan::FunctionCallbackInfo<v8::Value> const&) () from /home/root/serialport-galileo-test/node_modules/serialport-galileo-test/build/Release/serialport.node
...
lots of output that's not relevant was removed here
...
No symbol table info available.
#27 0x0814c43b in main ()
No symbol table info available.
(gdb) 
(gdb) 
(gdb) disassemble $pc,+32
Dump of assembler code from 0xb76629ac to 0xb76629cc:
=> 0xb76629ac <_Z4OpenRKN3Nan20FunctionCallbackInfoIN2v85ValueEEE+1212>:    fucomi %st(1),%st
   0xb76629ae <_Z4OpenRKN3Nan20FunctionCallbackInfoIN2v85ValueEEE+1214>:    fstp   %st(1)
   0xb76629b0 <_Z4OpenRKN3Nan20FunctionCallbackInfoIN2v85ValueEEE+1216>:    jbe    0xb7662f38 <_Z4OpenRKN3Nan20FunctionCallbackInfoIN2v85ValueEEE+2632>
   0xb76629b6 <_Z4OpenRKN3Nan20FunctionCallbackInfoIN2v85ValueEEE+1222>:    fldl   0xb76661c0
   0xb76629bc <_Z4OpenRKN3Nan20FunctionCallbackInfoIN2v85ValueEEE+1228>:    mov    $0x2,%eax
   0xb76629c1 <_Z4OpenRKN3Nan20FunctionCallbackInfoIN2v85ValueEEE+1233>:    fucomip %st(1),%st
   0xb76629c3 <_Z4OpenRKN3Nan20FunctionCallbackInfoIN2v85ValueEEE+1235>:    jbe    0xb7662f38 <_Z4OpenRKN3Nan20FunctionCallbackInfoIN2v85ValueEEE+2632>
   0xb76629c9 <_Z4OpenRKN3Nan20FunctionCallbackInfoIN2v85ValueEEE+1241>:    fstp   %st(0)
   0xb76629cb <_Z4OpenRKN3Nan20FunctionCallbackInfoIN2v85ValueEEE+1243>:    mov    -0x50(%ebp),%edi
End of assembler dump.
(gdb) 

According to this document the fucomi instruction was introduced to the Intel Architecture in the Pentium Pro processor family and is not available in earlier Intel Architecture processors.

It looks like the fucomi instruction isn't available in later Intel Architecture processors like the Quark SoC X1000 Series either.

The command gcc -Q --help=target can be used to determine the default options for gcc. If this command is run on an ia32 Linux PC and on a Galileo 2, there are only two differences.

These are default options on an ia32 Linux PC:

-march=i686
-mtune=generic

And these are default options on a Galileo 2:

-march=pentium
-mtune=pentium

At this point I tried the following:

A few tests were then run on the ia32 Linux PC and the Galileo 2 and everything functioned as expected.

If gcc/g++ on the build server that's generating serialport ia32 Linux binaries has the same default options, the same change to bindings.gyp may resolve the issue.

reconbot commented 8 years ago

I added docs about rebuilding.