LinuxQuestions.org

LinuxQuestions.org (/questions/)
-   Linux - Newbie (https://www.linuxquestions.org/questions/linux-newbie-8/)
-   -   Serial tty devices (https://www.linuxquestions.org/questions/linux-newbie-8/serial-tty-devices-4175506273/)

sreeharsha1988 05-28-2014 07:04 AM

Serial tty devices
 
Hi,

I am trying to communicate with a serial device by sending packets to it using echo command and the device is responding as expected.

But I am trying to read the response the device is sending me back and that is where I am stuck.

I am able to see the response on another terminal running screen, the response is valid but the problem is that I am unable to catch that data. Moreover that data is in hex form and I need a way to type cast the data.

Any suggestions would be helpful for me.

rtmistler 05-28-2014 09:46 AM

The simplest thing to do is exactly what you are doing, performing echo from one command prompt and performing cat on another command prompt. You can redirect the cat to a file to capture the responses completely, be they printable, versus not. Sounds like the characters are not printable, or you need translation to decode what you're seeing. So what I would do there is to write a short program to listen to the serial port, and output whatever is received from it in a coherent manner; which is to say that the program would decode the data and print it out in a read-able manner.

Minicom is a Linux terminal program, typically you have to run it using sudo, or as root; however I do not believe it gives you any better output translations than what you're seeing from the command prompt performing the cat. Perhaps there are other Linux terminal programs which will convert to HEX.

Here are some program tips for what I'd do in C if you were so inclined:

Substitute "/dev/ttyUSB0" for whatever serial resource you are using on your system:
Code:

int rdHandle;

if((rdHandle = open("/dev/ttyUSB0", O_RDONLY | O_NONBLOCK)) < 0) {
    // error situation, examine errno
}

Code:

char buffer[4096];
int ret;

if((ret = read(rdHandle, buffer, sizeof(buffer))) < 0) {
    // error situation, examine errno
    // NOTE: return can be 0 for no data
}

If ret was > 0, you now have some data. Decode it and print it out using printf().

Code:

int i;

for(i = 0; i < ret; i++) {
    printf("%02X ", buffer[i]);
}


sreeharsha1988 05-29-2014 12:43 AM

Quote:

Originally Posted by rtmistler (Post 5178108)
The simplest thing to do is exactly what you are doing, performing echo from one command prompt and performing cat on another command prompt. You can redirect the cat to a file to capture the responses completely, be they printable, versus not. Sounds like the characters are not printable, or you need translation to decode what you're seeing. So what I would do there is to write a short program to listen to the serial port, and output whatever is received from it in a coherent manner; which is to say that the program would decode the data and print it out in a read-able manner.

Minicom is a Linux terminal program, typically you have to run it using sudo, or as root; however I do not believe it gives you any better output translations than what you're seeing from the command prompt performing the cat. Perhaps there are other Linux terminal programs which will convert to HEX.

Here are some program tips for what I'd do in C if you were so inclined:

Substitute "/dev/ttyUSB0" for whatever serial resource you are using on your system:
Code:

int rdHandle;

if((rdHandle = open("/dev/ttyUSB0", O_RDONLY | O_NONBLOCK)) < 0) {
    // error situation, examine errno
}

Code:

char buffer[4096];
int ret;

if((ret = read(rdHandle, buffer, sizeof(buffer))) < 0) {
    // error situation, examine errno
    // NOTE: return can be 0 for no data
}

If ret was > 0, you now have some data. Decode it and print it out using printf().

Code:

int i;

for(i = 0; i < ret; i++) {
    printf("%02X ", buffer[i]);
}


I have a C code which will communicate with the device as desired but I am looking at the ways in which I can communicate with the device using shell scripting alone. This is because while trying to execute certain c-programs from a shell scripts I am unable to make the script wait until the program is completely executed.

pan64 05-29-2014 04:12 AM

you may try:
a=$(od -t x1 <serial device>)

and you will get the result in a (just you need to process it), but it also depends how many bytes do you want to evaluate.

rtmistler 05-29-2014 07:00 AM

Quote:

Originally Posted by sreeharsha1988 (Post 5178492)
I have a C code which will communicate with the device as desired but I am looking at the ways in which I can communicate with the device using shell scripting alone. This is because while trying to execute certain c-programs from a shell scripts I am unable to make the script wait until the program is completely executed.

Having trouble understanding that statement. For instance cat is a C program, as are many of the binary commands available in the shell. Fact is you can implicitly create a new shell command merely by ensuring that a compiled C program is in your path variable, or you can copy the binary executable to something like /usr/bin or /usr/sbin. When you've had this problem, have you invoked the C program in the background? Or was it a C program not structured to exit, but instead stay operating in a loop?

sreeharsha1988 05-29-2014 07:27 AM

Quote:

Originally Posted by rtmistler (Post 5178653)
Having trouble understanding that statement. For instance cat is a C program, as are many of the binary commands available in the shell. Fact is you can implicitly create a new shell command merely by ensuring that a compiled C program is in your path variable, or you can copy the binary executable to something like /usr/bin or /usr/sbin. When you've had this problem, have you invoked the C program in the background? Or was it a C program not structured to exit, but instead stay operating in a loop?

The C Program which I am invoking with the shell script is performing a series of operations divided into individual cases divided in the code. The program runs in a loop as long as i desire and exits if I ask the code to exit. The problem is if I am running the code using the terminal normally the script and the program it is invoking are executing as they should but if I copy the script in init.d and create a symbolic link to the script in rc2.d folder in /etc to make this script run on boot up the script is invoking the code but it is not waiting till the c program is completely executed and this is causing undesired outcomes.

So to avoid calling a c program to perform the tasks I wish I am preferring to implement my code functionality in shell script completely.

pan64 05-29-2014 07:33 AM

actually your explanation is not clear (for me). Probably you missed something, or I misunderstood something.
The program you invoked should work in the same way any time, therefore its execution must not depend on that fact (if it was executed from a shell or by an init script).
I would add set -xv at the beginning of your script to see what's happening and compare the two cases. You will see what causes the differences...

jpollard 05-29-2014 09:47 AM

One of the things to watch out for with using serial devices is the thing on the other end of the serial device...

Does it use modem signals?
Does respond to cts/rts signals?

One of the things that happens is that cts is off (not clear to send) if the terminal is closed... thus the device stops.

Having the serial line open (ie cat) allows another process to send data, and the response to be read. But note: this takes two processes.

Serial lines are asynchronous devices. Normal commands are synchronous. Now you CAN get the effect by opening ANOTHER file desriptor (not stdin/stdout) to the terminal (see bash manpage for redirection for other than file descriptors 0,1,2). You can then use this file descriptor to send data, and read responses (also bash coprocesses may help, by having a coprocess ready to read a response, the the other process sends a string).

sreeharsha1988 05-29-2014 11:42 PM

Quote:

Originally Posted by pan64 (Post 5178669)
actually your explanation is not clear (for me). Probably you missed something, or I misunderstood something.
The program you invoked should work in the same way any time, therefore its execution must not depend on that fact (if it was executed from a shell or by an init script).
I would add set -xv at the beginning of your script to see what's happening and compare the two cases. You will see what causes the differences...

This shell script is running on an embedded SOC board (zedboard) and this board is running a linux kernel based on Ubuntu, If I execute the script from the terminal when the system is completely booted up this works well. The program gets invoked and I am able to communicate with the device which is an UART based finger-print reader. The C program communicates with my device serially and determines if a user is authenticated or not and then this program returns the control to the script. Problem is that if this is placed on init.d script the program starts, configures the serial ports but the device will not respond, some times the device responds and I can communicate with the program and then abruptly this communication ends and the script stops to execute, If the device is plugged out my program ends prematurely and my script continues.

More surprisingly this same script and the same program works as expected on raspberry pie which is running a linux kernel based on debian.

This is making me think of what is gone wrong on zedboard and I could not identify the problem and hence I am exploring the ways to either execute the program forcefully using a while loop or implementing the entire c code in shell script.

pan64 05-30-2014 01:09 AM

I see, so probably it runs too early, the system has not been fully initialized?
How it is configured in init.d? Probably it should be executed a bit later?

sreeharsha1988 05-30-2014 01:32 AM

Quote:

Originally Posted by pan64 (Post 5179169)
I see, so probably it runs too early, the system has not been fully initialized?
How it is configured in init.d? Probably it should be executed a bit later?

I configured it to run with least possible priority so that it runs after all the drivers are completely loaded.

pan64 05-30-2014 01:39 AM

in that case I can suggest only to insert set -xv in the beginning of the script, save the log and check it. Probably you will find some useful info in it.

rtmistler 05-30-2014 08:04 AM

Quote:

Originally Posted by sreeharsha1988 (Post 5179179)
I configured it to run with least possible priority so that it runs after all the drivers are completely loaded.

No such concept of "priority" where a script is lowest so that it "allows" drivers to load, you run them given a sequence value to ensure that other startup scripts run before they do. The flow of the init is governed by the run level and the numbers following the 'S' in your symbolic link. Furthermore, there are things you can do in your script to test the availability of the /dev/tty<resource> you require.

Code:

# Your script - example
/etc/init.d/my-script.sh

# A sample symbolic link in the /etc/rc5.d directory, likely where it should be by the way
/etc/rc5.d/S99my-script

# Which when the details are viewed shows as
lrwxrwxrwx 1 root root ## dd mon yy S99my-script -> ../init.d/my-script.sh

Therefore the fact that it is in runlevel 5 means it runs as part of loading that runlevel, which should be the most typical one for a user script which also requires that most drivers be loaded.

The 'S' is for Starting the script, as opposed to a 'K' which you would use in say runlevels 2, 4, or 6 as the system is going down if you needed to cleanup anything.

The '99' is the important part; which is the numerical ordering of when the script gets run. I honestly don't know if you can use one, three, or more digit numbers; I've always used 2 digit numbers, but they work in counting order, therefore 01, 02, 03, 04, ... 97, 98, 99 would be run in sequence; if symbolic links existed for every number.

I should also state some added ignorance on my part which is that there is also rcS.d (Letter S) and I've successfully placed start scripts there versus the rc5.d (number 5) directory. I don't know the reason, but have heard that use of the rcS.d (Letter S) tree is discouraged.


All times are GMT -5. The time now is 11:39 PM.