DTMF monitoring via multimon, awk and espeak - linux

How to listen to the spoken DTMD digit every time the sound card capture one?
The objective is radio controlling my pc and interfaces activities dialing dtmf tones via a hand-held transceiver.
I used multimon to hear DTMF tones
I tried to use awk to filter digits and proceed accordingly.
For example, if I key "0" from the radio the system must reboot, etc, but first confirming the operation. " The computer will reboot, send # to confirm"...
I tried to use espeak for a voice confirmation to the remote radio.
The radio connected to the pc soundcard receives the commands and transmits the responses.
I do not simply know how to nest multimon within awk within espeak.
Multimon itself doesnt let me do anything with its stdout because its running ( do not terminate after hearing a digit, which is indeed right).
It would be extremely helpful if I knew how to just speak each digit, without exiting the natural multimon loop.
Say, multimon -a DTMF | awk'{print}' espeak -stdin
If this simply worked!
Is it possible to do? Any help wellcome.
3 years passed and still no advance in linux DTMF decoding.
Once I didnt see any DTMF Radio Controlling project in Linux, I plan to publish this shall I can solve this issue.
Thanks / Mario/ sao paulo brazil

I believe that my answer is out of date and perhaps you have found how to solve this.
I faced the same issue and figured out that the problem is in multimon. When you pipe the stdout from multimon to another program, multimon does not flush the verbose output properly.
Try to patch and recompile multimon, adding a "fflush(stdout);", like this:
(unixinput.c , around line 71 )
void verbprintf(int verb_level, const char *fmt, ...)
{
va_list args;
va_start(args, fmt);
if (verb_level <= verbose_level) {
vfprintf(stdout, fmt, args);
fflush(stdout); //ADD THIS LINE!!!!!!!!!!!!!!!
}
va_end(args);
}
Best regards,
-Eduardo

You can use the system() function to launch espeak from your awk script.

#OP, i am not clear about your question, but seeing that system() interests you, here's how you call external command in awk
multimon -a DTMF | awk '{
cmd="espeak "$0 #$0 comes from the multimon output
system(cmd)
}
'

Related

Is there any way to split a character stream generated from /dev/urandom to different substreams?

I need to take a high-speed stream of random numbers generated by a hardware device and split it to different sub-streams. For the testing purposes I considering /dev/urandom as a data source. Is there any linux tool for it? If not - please help with a bash script to do it.
The sum of sub-stream speeds should add up to initial stream speed ( or to be close ). The sub-streams are later sent to end user by creating a socket between netcat and /dev/tcp with usage of file descriptor 3 (or another).
Kindly consider using the following code:
od -An -t o2 /dev/urandom | awk '{ print $2 }' | awk '{$2= $1/4;$3= $1-$2;print $1" "$2" "$3}'
The first column will be the main stream, you can choose to split it into n number of columns or streams here I have attempted to split it into two columns. That is the main stream and two sub streams, the substreams will add up to the main-stream.
The sample output from the above code is :
032621 8155.25 24465.8
163465 40866.2 122599
023403 5850.75 17552.2
100755 25188.8 75566.2
052763 13190.8 39572.2
015401 3850.25 11550.8
062161 15540.2 46620.8
100415 25103.8 75311.2
142550 35637.5 106912
141450 35362.5 106088
057473 14368.2 43104.8
023430 5857.5 17572.5
007112 1778 5334
036372 9093 27279
P.S. I am not very good with awk, so there can be many improvements possible with awk part of the code.

alsa: How to programmatically find if a device is busy/in use using it name and without opening it

We have a Linux device which has a speaker and MIC devices. These devices are shared among different modules - example a VOIP call can use speaker, a hazard Warning system can use speaker, a Voice prompt can use a speaker etc:
There seems to be a function in ALSA which uses pcm to provide the status.
int snd_pcm_status (snd_pcm_t * pcm, snd_pcm_status_t * status)
However the *pcm is returned by snd_pcm_open. We do not want to open the device as we would like to know the status of the device using its "name"
Alsa API is here
How can we check if a resource/device is busy without opening it and using its name?
The same information for playback stream X of device Y on card Z is available in the file /proc/asound/cardZ/pcmYp/subX/status; when the device is not open, it just says "closed".
Please note that you cannot use this information to decide if you can open the device, because some other process could have openend it just after you've read this information. The only way to check if you can open it is to actually try.
Though it requires /dev/dsp, this seems to work:
#!/bin/dash
## If the speaker is not used by any, returns 0, and prints "free"
## Otherwise, returns 1 and prints "not free"
iExit (){
trap '' 0
exit $1
}
iCatch (){
# The speaker is already in use
echo not free
iExit 1
}
trap iCatch 0
{
exec 3>&1 1>/dev/dsp
# If the execution reaches here, the speaker is not used by any
# Otherwise, it's catched by iCatch
exec 1>&3
echo free
iExit 0
} 2>/dev/null
Without PulseAudio, it seems on some PC only one output is accepted at one time; on others simultaneous playbacks are allowed. But even in the latter case, the above code works.
NB: The above code does not work with bash; for bash, simply use if/else rather than trap.
NB 2: /dev/dsp may be lacking depending on the kernel configuration.

Use perl to send AT commands to modem

I have a embedded linux box with perl 5.10 and a GSM modem attached.
I have written a simple perl script to read/write AT commands through the modems device file (/dev/ttyACM0).
If i write a simle command like "ATZ\r" to the modem and wait for a response I receive very odd data like "\n\n\nATZ\n\n0\n\nOK\n\n\n\n\nATZ\n\n\n\n..." and the data keeps coming in. It almost seems like the response is garbled up with other data.
I would expect something like "ATZ\nOK\n" (if echo is enabled).
If i send the "ATZ" command manually with e.g. minicom everything works as expected.
This leads me to think it might be some kind of perl buffering issue, but that's only guessing.
I open the device in perl like this (I do not have Device::Serialport on my embedded linux perl installation):
open(FH, "+<", "/dev/ttyACM0") or die "Failed to open com port $comport";
and read the response one byte at a time with:
while(1) {
my $response;
read(FH, $response, 1);
printf("hex response '0x%02X'\n", ord $response);
}
Am I missing some initialization or something else to get this right?
Regards
Klaus
I don't think you need the while loop. This code should send the ATZ command, wait for the response, then print the response:
open(FH, "+>", "/dev/ttyACM0") or die "Failed to open com port $comport";
print FH ("ATZ\n");
$R = <FH>;
print $R;
close(FH);
It may be something to do with truncation. Try changing "+>" into "+<".
Or it may be something to do with buffering, try unbuffering output after your open():
select((select(FH), $| = 1)[0]);
Thanks for your answer. Although not the explicit answer to my question it certainly brought me on the right track.
As noted by mti2935 this was indeed not a perl problem, but a mere tty configuration problem.
Using the "stty" command with the following parameters set my serial port in the "expected" mode:
-opost: Disable all output postprocessing
-crnl: Do not translate CR to NL
-onlcr: Do not translate NL to CR NL
-echo: Do not echo input (having this echo enabled and echo on the modem itself gave me double echoes resulting in odd behaviour in my script)
It is also possible to use the combination setting "raw" to set all these parameters the correct way.
-

Linux serial port listener and interpreter?

I'm using a serial device for a project, and what I'm trying to accomplish PC side, is listening for a command sent by the serial device, interpreting the query, running some code depending on the query, and transmitting back the result.
To be honest I tried out using PHP as the listener, and it works, unfortunately the infinite loop required to make the script act as a receiver, loads the CPU to 25%. So it's not really the best option.
I'm using cygwin right now, I'd like to create a bash script using linux native commands.
I can receive data by using:
cat /dev/ttyS2
And send a response with:
echo "command to send" > /dev/ttyS2
My question is, how do I make an automated listener to be able to receive and send data? The main issue I have, is actually how do I stop the cat /dev/ttyS2 command once information was received, put it into a variable which then I could compare with a switch, or a series of if else then blocks. Afterwards send back a response and start the cycle all over again?
Thanks
Is this not what you're looking for?
while read -r line < /dev/ttyS2; do
# $line is the line read, do something with it
# which produces $result
echo $result > /dev/ttyS2
done
It's possible that reopening the serial device on every line has some side-effect, in which case you could try:
while read -r line; do
# $line is the line read, do something with it
# which produces $result
echo $result > /dev/ttyS2
done < /dev/ttyS2
You could also move the output redirection, but I suspect you will have to turn off stdout buffering.
To remain fairly system independent, use a cross platform programming language: like Python, use a cross platform serial library like : pySerial and do the processing inside a script. I have used pySerial and I could run the script cross platform with almost no changes in source code. By using BASH you're limiting yourself a fair little.
If you use right tools, it is possible to actually have your CPU usage to be exactly 0 when your device does not have any output.
To accomplish this, you should use some higher level language (Perl, Python, C/C++ would do, but not bash) and use select loop on top of file handle of your serial device. This is an example for Perl http://perldoc.perl.org/IO/Select.html, but you can use any other language as long as it has support for select() syscall.
I would recommend to use C/C++ with Qt 5.1.1, it's really easy and if you are familiar with the framework it'll be a piece of cake!!!
Here you can find more information and here more helpful examples, give it a try,
it's really pain free!! Also you can develop on win and then port your code to linux...straight forward.
Declare an object like this:
QSerialPort mPort; //remember to #include <QtSerialPort/QSerialPort>
//also add QT += serialport to your .pro file
Then add this code:
MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent)
{
setupUi(this);
connect(this->pushButton,SIGNAL(clicked()),this,SLOT(sendData()));
mPort.setPortName("ttyS0");
mPort.setBaudRate(QSerialPort::Baud115200);
mPort.setParity(QSerialPort::EvenParity);
if(!mPort.open(QSerialPort::ReadWrite))
{
this->label->setText(tr("unable to open port, %1").arg(mPort.error()));
}
connect(&(this->mPort),SIGNAL(readyRead()),this,SLOT(readData()));
}
void MainWindow::sendData()
{
QByteArray data = lineEdit->text().toLatin1();
if(mPort.isOpen())
{
mPort.write(data);
}
else
{
this->label->setText(tr("port closed %1").arg( mPort.error()));
}
}
void MainWindow::readData()
{
QString newData;
int bread=0;
while(bread < mPort.bytesAvailable() ){
newData += mPort.readAll();
bread++;
}
this->textEdit->insertPlainText("\n" + newData);
}

Writing to serial port in Perl

I need to communicate with a serial port inside a Perl script. I need to send characters and read the input and search for strings.
What is the simplest way to achieve this? By using "expect" or by opening the /dev/ttys0 device in Perl itself ? Or some other method ?
I prefer to use perl but I don't know if it is simple and featured as expect.
my $port = new Device::SerialPort("/dev/ttyS0");
$port->user_msg(ON);
$port->baudrate(9600);
$port->parity("none");
$port->databits(8);
$port->stopbits(1);
$port->handshake("xoff");
$port->write_settings;
$port->lookclear;
$port->write("some command to com-port");
my $answer = $port->lookfor;
# or my $answer=$port->read(255);
You can try Win32::SerialPort for Win32 and Device::SerialPort for linux.
IO::Termios
Device::SerialPort

Resources