In my application, any phone can voice-connect to my 3G USB modem and the call gets picked up immediately. It receives audio as PCM (8000 samples, 16 bits, mono) through a serial port and uses Microsoft's Speech Synthesizer to talk back to the caller.
The problem is, the application should talk back only when the caller has stopped speaking. How can I detect that ?
I tried implementing a 3-second timer which resets itself when data is received from the serial port, so when the timer gets 'ticked' it should mean that that the caller was silent for 3 seconds. But it doesn't work that way. What did I do wrong ?
private void DataRecdFromSerial(object sender, SerialDataReceivedEventArgs e)
{
say.Stop(); say.Start(); // reset timer with interval 5000
int n = usb.BytesToRead;
byte[] comBuffer = new byte[90000];
usb.Read(comBuffer, 0, n);
if(comBuffer.Length > 0)
{
wfw.Write(comBuffer, 0, n); // NAudio Wave File Writer
}
}
private void say_Tick(object sender, EventArgs e)
{
// Caller stopped speaking for 5 seconds (not working)
}
By what magic on earth should data flow interrupt when there is silence ? you will get a continuous stream as long as the line is connected that is the most logical of all software and electronical engineering implementation that one can excpect today. So you need to analyze the spectrum of the sound wave and calculate root mean square amplitude to get energy. you compare to a threshold that you fix by empirical testing (because silence is actually a small noise that you need to accept).
Related
Morning all,
I'm developing a C# WPF application which continuously reads barcodes (about one every minute) from a DATALOGIC scanner (DS4800-1000) and send them to a server which replies with details about that specific barcode. This scanner is connected to a tablet running Windows 8.1 (non RT) through a USB-to-serial converter from MOXA (model UPort 1100).
Whenever a new barcode is read, the DataReceived event is fired and handled with the following method:
private void port1_DataReceived(object sender, SerialDataReceivedEventArgs e)
{
Log.log(Log.LogLevel.Info, "MainScreen.port1_DataReceived");
Thread.Sleep(100);
String data = "";
// If the com port has been closed, do nothing
if (!comport1.IsOpen)
{
Log.log(Log.LogLevel.Info, "MainScreen.port1_DataReceived - COM CLOSED");
data = "COM CLOSED"; // Must be < 16 chars
}
else
{
// Obtain the number of bytes waiting in the port's buffer
int bytes = comport1.BytesToRead;
// Create a byte array buffer to hold the incoming data
byte[] buffer = new byte[bytes];
// Read the data from the port and store it in our buffer
comport1.Read(buffer, 0, bytes);
data = Encoding.Default.GetString(buffer);
Log.log(Log.LogLevel.Info, "Data received from barcode scanner number 1: " + data);
}
// COM port is handled by a different thread; this.Dispatcher calls the original thread
this.Dispatcher.Invoke((Action)(() =>
{
ExtractBarcodeData(data);
} ));
}
I'm observing a strange behavior: at random times, I see no reaction at all on the application, although the scanner actually reads a new barcode, while I would expect a new DataReceived event as the previous barcodes. Logs say me that the port is actually open and I can also close it using a specific button which closes and reopen it. Here comes the exception (on the Open() call): A device attached to the system is not functioning.
I can not reproduce this error in no way, it's totally unpredictable and random! Anyone has got any idea why the DataReceived event is not triggering?
Thanks,
FZ
Most USB-to-serial converters have this problem. They may disappear from the system and appear again. All opened handles at this situation become invalid.
Please, open the Device Manager and verify the power management tab for each USB hubs there. The system should not power off the hub.
I'm taking data from a serial instrument for plotting on a chart. The data stream is 230 kbps, and the serial pipeline is less than 50% full, data arrives about 100 kbps and actually doesn't vary really and rate or quantity.
Having used just a serial terminal program, like Teraterm, on the same computer; I can capture data and prove that both the source of the data as well as the test reception method are fine and I see no errors to the captured data.
The Windows Forms application I'm developing loses data. I've reduced it from receiving, capturing (in parallel), parsing, and plotting, to just receiving and capturing. And have found that I still see lost data in the capture.
I'm not a long experienced Windows person, so therefore may not know of better ways to accomplish the same functions. Here are the actions I'm taking to perform receive actions:
I'm using a System.IO.Ports.SerialPort class.
I modify the .DataReceived event via:
+= new SerialDataReceivedEventHandler(comPort_DataReceive);
I then call the open() method.
Note: I may be doing something incorrect here, I never clear the .DataReceived event with a -= at any point, instead each time I open, the event is added yet again. Nevertheless, these problems occur even when I've only talked to the port once.
Here's my code for the data receive function. RxString is a string.
private void comPort_DataReceive(object sender, SerialDataReceivedEventArgs e)
{
RxString = comPort.ReadExisting();
this.Invoke(new EventHandler(ParseData));
}
private void ParseData(object sender, EventArgs e)
{
// Save to capture file, if capture is enabled
if ((WriteToFileEnabled == true) && (WriteToFileName != null))
{
writeFileHandle.Write(RxString);
}
return;
// Previously would parse and plot data
}
So, how would persons execute a receive in this situation to get this data without losing it?
Follow on questions are things like: How big is the buffer for serial receive, or do I need to worry about that if I have a reasonably responsive application? Flow control is irrelevant, the remote device is going to send data no matter what, so it would be up to my computer to take that data and process it or ignore it. But how would I know if I've lost data or experienced framing errors and stuff? (I ask that last one without having searched much on the SerialPort class structure, sorry.)
Lets assume that your device is sending messages that are 85 bytes in length. The DataReceive event handler may or may not fire once to receive those 85 bytes. Since it might fire more than once your code must account for that. The DataReceive event handler should read the bytes available and append them to a buffer that is processed later.
Also, only one of the events raised by the SerialPort class can execute at a time. In the example assume the handler has to fire three times to receive the 85 bytes. While processing the first part the other two can't execute. If while processing the first part one of the other events, PinChanged or ErrorReceived, are needed they can't be executed either.
My first two experiences with the SerialPort class were a 9600 bps terminal and a 1 Mbps bluetooth device. What worked for the slower did not work for the faster, but when I figured out how to get the faster to work the slower could use the same methodology.
My methodology:
Before opening the serial port I start two other background threads that run in a do loop. The first one(Receive) reads all available bytes from the serial port, adds them to a buffer, and signals the second thread on every read. The second one(Protocol) determines if a full message has arrived, does any byte to string conversion, updates the UI, etc. Depending on the application I may start a third thread that handles errors and pin changes. All of these threads are throttled by a Threading AutoResetEvent.
My DataReceive event handler has one line in it, a Set on the AutoResetEvent that is throttling Receive.
A VB example of this can be found here SerialPort Methodology. Since adopting this methodology I have not had any of the problems that seem to plague other SerialPort users and have used it successfully with speeds up to 2Mbps.
I am working on a GPS vehicle tracking project . Here the device used to send Latitude and Longitude signals to a particular IP (Static IP) on the port 5000. There are 17 devices in total.
My problem is when all the 17 device are activated I am not getting the readings from all device in a proper time duration. This means if I got the readings of Device 1 I will continuously get 5 to 6 readings from that device after that when Device 2 I will continuously get 5 to 6 readings similarly it goes on.
What I am going to say here is all the device transmit the readings (Latitude and Longitude) for every 1 minte to my IP but when i get the Signal from a device I will get only from device 1 after few 5 to 6 minutes Device 2 then 3 .
My problem is that my application is losing the packets. This means when my application is receiving data from Device 17 the application is receiving the last 5 to 6 minutes readings but it has lost the readings from past 10 to 30 minutes.
How can I get the signal from all the devices parallely to same port using one socket?
This is the code I have implemented:
Thread th_main, th_sub;
bool bool_Start_subTH;
Socket Socket_Client;
TcpListener objListener;
private void Form1_Load(object sender, EventArgs e)
{
bool_Start_subTH=false;
th_main = new Thread(GetDataFromClient);
th_main.Start();
}
void GetDataFromClient()
{
objListener = new TcpListener(5000);
objListener.Start();
while (th_main.IsAlive)
{
Socket_Client= objListener.AcceptSocket();
if(!bool_Start_subTH)
{
th_sub=new Thread (SubFunctionThread);
th_sub.start();
bool_Start_subTH=false;
}
}
}
void SubFunctionThread()
{
while(th_sub.IsAlive)
{
if(Socket_Client.Avilable>0)
{
byte[] something = new byte[Socket_Client.Available];
Socket_Client.Receive(something);
string strmessage = Encoding.ASCII.GetString(something);
Listbox1.Items.Add( strmessage);
}
}
}
I think the problem is in the thread which deals with the clients, it stay in a loop eating all the CPU. You should avoid the Available and read the socket directly (in fact that's all you suppose to do, wait until something comes in), making it to stop until some data gets in. Also, you may change
if (Socket_Client.Avilable > 0)
by
if (Socket_Client.Poll(1000000, SelectMode.SelectRead))
in case you need to check something once in a while, for example the thread is not alive.
I need to write a program, that will listen to communication in ModBus network through RS485.
I am connected to the network with RS485 <> USB dongle.
I can read some data using SerialPort.DataReceived event, but it gives strange results.
Data is often split, when it should come in one piece. (Modbus Master transmits every 100ms).
class Serial
{
private SerialPort port;
Queue<byte[]> buffer;
public Serial()
{
buffer = new Queue<byte[]>();
port = new SerialPort("COM3", 19200, Parity.Even, 8, StopBits.One);
port.DataReceived += port_DataReceived;
}
public void Open()
{
if (port.IsOpen)
{
port.Close();
}
port.Open();
}
void port_DataReceived(object sender, SerialDataReceivedEventArgs e)
{
byte[] buff = new byte[port.BytesToRead];
port.Read(buff, 0, port.BytesToRead);
buffer.Enqueue(buff);
}
}
I don't have any start sign in transmission.
Delay between frames is min. 3.5 chars, and max delay between chars is 1.5 chars.
This is entirely normal, serial ports are very slow devices. The DataReceived event is fired as soon as one byte was received. You'll need to call Read() and pay attention to the value it returns, the number of bytes it was able to retrieve from the input buffer. Which might be more than one but is only very rarely equal to the number of bytes in a "packet", that could only happen if the machine got very slow for some reason.
Beware that the debugger is one way to make it that slow, a breakpoint or single-stepping the event handler code gives the driver enough time to receive all the bytes in a packet. So that the Read() call returns them all. But that stops working as soon as you stop debugging that code.
You could use the ReceivedBytesThreshold property to delay the event but that can only work when a packet has a fixed size. Simply append the bytes you get into byte[], using the 2nd argument of the Read() call. And don't process the packet until you have them all.
I developed a C# application for reading calls from GSM Modem. I used a timer to read the port regularly and notify me when there is a incoming call.
Now i am trying to use another timer which will write AT+CSQ -To know the signal quality, on the port and read the port for the quality value. In both the timers i used regular expressions to match and separate the data i need. Now the problem is that only my timer2 which is reading the signal quality is only working but not timer reading for incoming calls.
Timer reading signal strength:
private void tmr_sig_quality_Tick(object sender, EventArgs e)
{
if (port.IsOpen)
{
port.WriteLine("AT+CSQ");
string s= port.ReadExisting();
var match= Regex.Match(s,#"\+CSQ: (\d+),(\d+)");
if (match.Success)
{
progressBar1.Value = int.Parse(match.Groups[1].Value);
}
}
}
Timer reading incoming calls:
private void timer1_Tick(object sender, EventArgs e)
{
s = port.ReadExisting();
var match = Regex.Match(s, "RING[^\\+]*\\+CLIP:\\s*\"(?<phone>[^\"]*)\",(\\d+),\"([^\"]*)\",(\\w*),\"(\\w*)\",(\\w*)");
if (match.Success && s.Contains("RING"))
{
incall_status.Text = "Incoming Call...." + match.Groups["phone"].Value;
incall_status.Visible = true;
}
}
Why is this happening and solution please?
Two major problems. First is ReadExisting(), that will always return an empty string. Except when you are debugging and stepping through the code line by line. That gives the modem enough time to send the response. But this won't work when you run at full speed, you'll need to make a blocking call that ensures your program waits long enough to get all the returned characters. Use ReadLine() instead.
Second killer problem is that you are mixing commands. Your tmr_sig_quality_Tick() method is likely to read whatever timer1_Tick() was supposed to read. You'll need to re-think this approach. Something like a queue of commands that doesn't advance until the response to a command is received.
Not an actual answer to your question, but a general advice for communicating with a GSM modem:
Keep in mind that you have only one serial port, thus only one communication channel. A GSM modem can send spontaneous events, such as the RING, FAX, VOICE events, so there is no guarantee that when you write AT+CSQ the first reply is what you expect, i.e. the signal quality.
Having two timers like you're intending is not a good idea since you'll eventually end up with the response of one command in timer A when it was expected in B, because A read one of the spontaneous events...etc.
A much better and robust way is to have a worker thread that reads and interprets the incoming data and then distributes that in you application as needed. It can also handle the outgoing data. Use concurrent queues and some signaling mechanism (i.e. AutoResetEvent) for exchanging data with this thread, that way you get a cleaner interface to your hardware device and don't need to worry about timing and such in your application.