I have a windows application for sending SMS connecting to a GSM Modem. I only use AT Commands for connecting to port and sending text.
My problem is I can't send a message more that one part (each part is 160 characters for English and 70 characters for Farsi).
Here is the part I command the port to send sms using AT commands:
ExecCommand(port, "AT", 300, "No phone connected at " + strPortName + ".");
ExecCommand(port, "AT+CMGF=1", 300, "Failed to set message format.");
var command = "AT+CSCS=\"" + "HEX" + "\"";
ExecCommand(port, command, 300, "Failed to support unicode");
ExecCommand(port, "AT+CSMP=1,167,0,8", 300, "Failed to set message properties.");
command = "AT+CMGS=\"" + phoneNo + "\"";
ExecCommand(port, command, 300, "Failed to accept phoneNo");
message = message.ToCharArray().Select(Convert.ToInt32).Select(value => String.Format("{0:X}", value)).Aggregate("", (current, hexOutput) => current + hexOutput.PadLeft(4, '0'));
command = message + char.ConvertFromUtf32(26) + "\r";
var recievedData = ExecCommand(port, command, 3000, "Failed to send message");
And here is ExecCommand method
public string ExecCommand(SerialPort port, string command, int responseTimeout, string errorMessage)
{
try
{
// receiveNow = new AutoResetEvent();
port.DiscardOutBuffer();
port.DiscardInBuffer();
receiveNow.Reset();
port.Write(command + "\r");
//Thread.Sleep(3000); //3 seconds
string input = ReadResponse(port, responseTimeout);
if ((input.Length == 0) || ((!input.EndsWith("\r\n> ")) && (!input.EndsWith("\r\nOK\r\n"))))
throw new ApplicationException("No success message was received.");
return input;
}
catch (Exception ex)
{
throw new ApplicationException(errorMessage, ex);
}
}
General AT command handling
You are on the right track, I am pleased to see several basic things done right (terminating AT command lines with \r, waiting for "\r\n> " for AT+CMGS, and waiting for the OK final result code instead of sleeping), very good start!
You do need however to change the structure somewhat. First you need to handle all the other final result codes and not just OK. And you should treat the AT+CMGS command differently from the other commands since you should wait for two things (first the prefix and later the final result code after sending the message text) for that command compared to waiting only for one thing (e.g. the final result code) for those. Also all responses from the modem are complete lines (except the "\r\n> " prefix), so change your algorithm to process the response(s) line by line.
String input;
do {
input = ReadLine(port, responseTimeout);
} while (!isFinalResultCode(input));
None of the commands you are using in the question produces an intermediate response for consumption, but if you were to run a command like AT+CPBR you would consume those intermediate responses inside that loop (and you would have to move the final result test into the loop before attempting to consume the line as an intermediate response).
You can see the is_final_result function in atinout or corresponding functions in ST-Ericsson's U300 RIL (see link and notes in this answer).
Multipart SMS
I think this is not possible in text mode. See the link suggested by Naser Asadi for details on multipart SMS in PDU mode. Also some useful information at
http://mobiletidings.com/2009/02/18/combining-sms-messages/ and http://developer.nokia.com/community/discussion/showthread.php/109602-Concatenated-SMS-in-PDU-Mode.
Related
I made a very simple WindowsService that waits data from an UDP port trough WiFi and once received them, it writes them in a txt file (as many examples/tutorials that you can find on the web). I anticipate I usually develop WIndowsForm. The Service choise arises from the need to have a background process that always works, without showing anything to the user... the latter will check the file with the data saved only when needed.
Through the AppConfig.xml file a set the log path and file name and when I run it through VisualStudio no problems appear, as well when I install it (through prompt cmd) on my PC (where I developed it). Everything seems to work properly!
When I tried to install and run it on others PC (included the one where it's supposed to work), the WindowsService has been correctly installed and looked like to work but actually doesn't write on the file (first strange behaviour).
I think is something related to permission.
The account set in the installer is the LocalSystem.
I tried to compile again my project but with the log path hard coded and equals to the directory where the WindowsService.exe is placed but it works only when I run it from VS. When I run it from Services it has the same behaviour seen before: it starts without any error but it doesn't write to the file (second strange behaviour). Obv it doesn't work also to the other PC.
In both cases (write or not) the output in the Process Monitor is the same.Fail to write and OK
Finally, everytime I modify my code and I run it through VS, my Avast antivirus initially blocks the debug because it has to check the .exe file first. Then, the process starts correctly. It's like this only the first time after a change in the code (and so a change in the .exe). This doesn't happen, for example, when I develop and execute WindowsForm...
I'm blocked here from weeks, I hope so much in your help!
Many thanks in advance fot your time.
SB
Code below.
I search for a string in the text file (workbench station).
If this string is already present, I update its associated counter value.
If this string is not present, I added a new line with the new workbench and its counter value.
// Save data received in text file
using (StreamReader sr = new StreamReader(Path.Combine(docPath, fileName)))
{
lineToFind = bancoDiLavoro.Insert(bancoDiLavoro.Length, receiveBytes[0].ToString());
Console.Write("Line to find in text file: ");
Console.WriteLine(lineToFind);
allLines = File.ReadAllLines(Path.Combine(docPath, fileName));
lineNumber = 0;
while (allLines.Length != 0)
{
line = sr.ReadLine();
lineNumber = lineNumber + 1;
try
{
if (line != null)
{
if (line.Contains(lineToFind))
{
sr.Close();
lineFound = true;
allLines[lineNumber - 1] = lineToFind.Insert(lineToFind.Length, "\tConteggio: " + count.ToString() + "\t");
File.WriteAllLines(Path.Combine(docPath, fileName), allLines);
break;
}
}
else
{
Console.WriteLine("Empty line found.");
lineFound = false;
break;
}
}
catch (Exception ex)
{
Console.WriteLine(ex.ToString());
lineFound = false;
}
}
if (lineFound == false)
{
// Workbench not found: a new workstation has been added
sr.Close();
File.AppendAllText(Path.Combine(docPath, fileName), lineToFind);
File.AppendAllText(Path.Combine(docPath, fileName), "\tConteggio: ");
File.AppendAllText(Path.Combine(docPath, fileName), count.ToString() + "\n");
Thread.Sleep(100);
}
}
[UPDATE]
I've been able to add the EventLog to my service and on the PCs where the service doesn't work, seem that the data are not received on UDP port (even if the port is correctly "opened"). I have to work on this now...
The service remains blocked here:
Byte[] receiveBytes = receivingUdpClient.Receive(ref RemoteIpEndPoint);
try
{
//Creates a UdpClient for reading incoming data.
UdpClient receivingUdpClient = new UdpClient(UDPport);
//Creates an IPEndPoint to record the IP Address and port number of the sender.
// The IPEndPoint will allow you to read datagrams sent from any source.
IPEndPoint RemoteIpEndPoint = new IPEndPoint(IPAddress.Any, 0);
eventLog1.WriteEntry("UDP port opened.");
while (waitForPacket == true)
{
// Blocks until a message returns on this socket from a remote host.
Byte[] receiveBytes = receivingUdpClient.Receive(ref RemoteIpEndPoint);
Console.Write("Workbench: ");
Console.Write(receiveBytes[0]);
Console.Write(", count: ");
Console.WriteLine(receiveBytes[1]);
Console.WriteLine("This message was sent from " +
RemoteIpEndPoint.Address.ToString() +
" on their port number " +
RemoteIpEndPoint.Port.ToString());
eventLog1.WriteEntry("data received.");
// Continues with the data writing...
I am trying to capture the net weight from a IND560 using C#'s streamReader and streamWriter classes. It seems a connection is made, but no matter the command I send, I get a response back: 83 Command not recognized. I see the command (wt0111) in the IND560 under Communications>Template>output for template1.
The code is below if anyone has any suggestions to help me move forward it would be much appreciated!
static void writeToStream(string cmd)
{
if (tcpClient.Connected)
{
Console.WriteLine("Sending CMD: {0}\\n", cmd);
// tried with appending a \r, \n, and \r\n same result: 83 command not found
clientStreamWriter.Write(cmd + '\n');
clientStreamWriter.Flush();
}
}
Here is a sample output of the program showing the response 83:
You would need to use read command for the purpose (according to link here)
Format: read SDV#1 SDV#2
Example 1: read wt0101 wt0103
Response 1: 00R003~ 17.08~lb~
So, in your case
read wt0101
read wt0111
In your case you would need to prepend "read" before the field ID (wt0101).
if (tcpClient.Connected)
{
Console.WriteLine("Sending CMD: {0}\\n", cmd);
clientStreamWriter.Write($"read {cmd}" + '\n');
clientStreamWriter.Flush();
}
I would suggest to provide your users an option to input the command to "read" "write", "help", along with field name, in case you are intending to support more command.
I have a very strange issue, which has been driving me mad for the last two days.
I have a serial device (LS 100 Photometer) which I am trying to control. Using a terminal (termite) set up with the correct parameters, I can send the command ("MES"), followed by the delimeter (CR LF), and I get back some measurement data as expected.
The problem is, from Qt, I do not get any data returned. Using a sniffer program, I have confirmed that I am sending the exact same 5 bytes (MES CR LF) as the terminal is sending, and with the same port setup.
If I change the flow control to "NoFlowControl" then I can get some data back, but it appears to be meaningless and is just one random byte. In any case the device documentation says to use RTS/CTS and that is what the terminal (termite) is set up to use.
Also, if I use the Qt serialport example terminal, I get the same issue where I can't get the device to return data. I have also tried using C# and have had the exact same issue. The only thing that seems capable of communicating with the instrument is the Termite terminal.
Qt Code:
port.setPortName(ui->cmbPort->currentText());
port.setBaudRate(QSerialPort::Baud4800);
port.setDataBits(QSerialPort::Data7);
port.setParity(QSerialPort::EvenParity);
port.setStopBits(QSerialPort::TwoStop);
port.setFlowControl(QSerialPort::HardwareControl);
if (!port.open(QIODevice::ReadWrite))
{
connected = false;
QMessageBox::information(this, "Failed To Open", "Failed to open the serial port");
ui->statusBar->showMessage("Connection to " + ui->cmbPort->currentText() + " failed...");
}
else
{
connected = true;
ui->statusBar->showMessage("Connected to " + ui->cmbPort->currentText() + "...");
}
QByteArray cmdB;
cmdB[0] = 0x4d;
cmdB[1] = 0x45;
cmdB[2] = 0x53;
cmdB[3] = 0x0d;
cmdB[4] = 0x0a;
qint64 r = port.write(cmdB.data(), cmdB.size());
qDebug() << "Written: " << r;
Then the ReadData function which is called on ReadyRead or every 100ms:
QByteArray data = port.readAll();
if (data.count() != 0)
{
qDebug() << "Read " << data.size() << " bytes";
QString str = QString(data);
ui->txtOutput->append(str);
}
Any help would be much appreciated, I'm running out of hair to pull out...
Finally worked it out.
Even though the documentation says to use RTS/CTS, and the terminal program (termite) uses RTS/CTS, the solution was to turn off flow control in the Qt application (i.e. NoFlowControl), then turn on the RTS line manually just before sending data, like this:
port.setRequestToSend(true);
qint64 r = port.write(cmdB.data(), cmdB.size());
port.waitForBytesWritten(5000);
qDebug() << "Written: " << r;
I have code that uses POP3 to access an email account and search for messages that were sent but the address did not exist. After processing them, I delete the failure message. I have one client who can get and process the messages, but is not able to delete them. They keep getting the message Error deleting message 1: -ERR The specified message is out of range.
The code for my delete method is below. This works for most clients, and is pretty simple, so I'm not sure why it isn't working.
public bool Delete(int index)
{
bool result = false;
String response = SendReceive("DELE ", index.ToString());
if (response.StartsWith("+OK"))
result = true;
else
logger.Log("Error deleting message " + index + ": " + response, Verbose.LogImportant);
return result;
}
For the SendReceive method:
private String SendReceive(String command, String parameter)
{
String result = null;
try
{
String myCommand = command.ToUpper().Trim() + " " + parameter.Trim() + Environment.NewLine;
byte[] data = System.Text.Encoding.ASCII.GetBytes(myCommand.ToCharArray());
tcpClient.GetStream().Write(data, 0, data.Length);
result = streamReader.ReadLine();
}
catch { } // Not logged in...
return result;
}
The index is taken directly from the received email, and the connection is not closed until after the delete method has processed. Since there has to be an email returned to run this method, and since the index runs from 1 to n, with a 1 being sent, I don't see what is causing this to fail.
The SendReceive() call looks wrong. My guess is that it should probably have a {0} in the format string. In other words, your code is probably sending DELE instead of DELE 1.
I've been breaking my head over a bug in this system I've been building. Basically, I use sockets to communicate between two C# applications. Or rather a Unity C# script server and a C# client application.
With manual tests, the system works perfectly fine, no anomalies whatsoever.
In order to test performance and multi-user functionality, I wrote up a tester class which launches multiple threads(clients), and have those fire X amount of messages at the server. Here's where my problem occurs...Sometimes.
When a Socket sends or receives, it returns an integer container the amount of bytes that was sent/received. When the problem occurs, I can see that the correct amount of bytes arrived at the server. However, after putting the bytes into a string, suddenly I'm left with an empty string, instead of the message I'd normally see here.
I'm at a loss at to what's causing this problem. I'm using Encoding.Default.GetString() to translate the bytes into a string.
Any help is appreciated!
David
public void ReceiveFromClient (Socket handlerSocket)
{
serverBuffer = new byte[iBufferSize]; //iBufferSize = 8192;
int i = handlerSocket.Receive (serverBuffer);
Debug.Log ("Bytes received: " + i);
string message = Encoding.UTF8.GetString (serverBuffer, 0, i);
Debug.Log ("Message received: " + message);
//Do stuff with the message
}
bool SendMessageToUnity(string input)
{//returns a bool saying whether the message was sent or not
if (clientSocket != null)
{
if (clientSocket.Connected)
{
byte[] bytes = Encoding.UTF8.GetBytes(input+"|");
txtOutput.BeginInvoke(new Action(() => txtOutput.AppendText("Sending message: " + Encoding.UTF8.GetString(bytes) + Environment.NewLine)));
int i = clientSocket.Send(bytes);
txtOutput.BeginInvoke(new Action(() => txtOutput.AppendText("Sending "+i+" bytes. "+ Environment.NewLine)));
return true;
}
}
return false;
}
Look for for a zero value ('\0') in your array of bytes before converting it to a string.
private string GetString(byte[] data)
{
data = data.Where(b => b != 0).ToArray();
return Encoding.UTF8.GetString(data);
}
If you get the byte array correctly than the problem in the Encoding.
Check the sending Encoding usually UTF8 but you have to check it out.
and then var inputStr = Encoding.UTF8.GetString(InputByteArray);
^^