I have an encoder connected from Siemens PLC with data block "DB1.DBD56".
My problem is, the two textbox has the same result or value.
Scenario:
Read Before 1seconds and
Read After 1seconds
I want the result like this:
[For reference]
(https://i.stack.imgur.com/HK9zU.png)
[PLC Ladder]
(https://i.stack.imgur.com/kGN62.png)
#region EVENT TO START READING THE ENCODER
private void timer_anvilState_Tick(object sender, EventArgs e)
{
try
{
Edata_convertion();
read_lastweld_result();
bool anvilState = (bool)plc_s7_1200.Read("DB1.DBX68.4");
if (plc_s7_1200.IsConnected)
{
if (anvilState == true)
{
timer_OneCycleProcess.Start(); //STATE MACHINE TIMER
}
else
{
timer_OneCycleProcess.Stop();
command = "IDLE";
}
}
}
catch (Exception ex)
{
MessageBox.Show("Please check between PC and PLC connection " + "\n" + ex.Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
}
#region READ BEFORE
public void Read_Before()
{
if (plc_s7_1200.IsConnected)
{
bool anvilState = (bool)plc_s7_1200.Read("DB1.DBX68.4");
if (anvilState == true)
{
string Edata = string.Format("{0:0.0}", convertTomm);
txtbefore.Text = Edata;
}
}
}
#endregion
#region READ AFTER
public void Read_After()
{
bool gen_US_on = (bool)plc_s7_1200.Read("DB1.DBX78.2");
if (gen_US_on == true)
{
string Edata = string.Format("{0:0.0}", convertTomm);
txtafterWeld.Text = Edata;
}
}
#endregion
Here's my solution.
Only revised the PLC ladder as stated my replied at comment section.
https://i.stack.imgur.com/GUBtg.png
My C# program nothing changes.
Sharing my basic state machine code
#region ONE CYCLE PROCESS
private void timer_OneCycleProcess_Tick(object sender, EventArgs e)
{
switch (command)
{
case "IDLE":
command = "BEFORE";
break;
case "BEFORE":
before();
command = "AFTER";
break;
case "AFTER":
after();
prev_result();
read_maintenanceCounter();
read_outputCounter();
command = "SAVE";
break;
case "SAVE":
command = "STOP";
save();
save_history();
break;
case "STOP":
timer_OneCycleProcess.Stop();
plc_s7_1200.Write("DB1.DBX38.0", 0);
break;
default:
break;
}
}
#endregion
Related
I am writing winForm app which have to listem SerialPort and print the data into multi line textbox in real time.
Here is the code:
using System;
using System.Drawing;
using System.Windows.Forms;
using System.IO.Ports;
using System.Threading;
using System.ComponentModel;
namespace SCPListener
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
backgroundWorker1.DoWork += new DoWorkEventHandler(backgroundWorker1_DoWork);
GetAvailablePortNames();
panel1.BackColor = ColorTranslator.FromHtml("#f44147");
cbDefaultValue();
}
String[] PortNames;
bool conn = true;
String data;
public string datetime;
Form2 frm = new Form2();
void GetAvailablePortNames()
{
PortNames = SerialPort.GetPortNames();
comboBox1.Items.AddRange(PortNames);
}
void RefreshAvailablePortNames()
{
comboBox1.Items.Clear();
PortNames = SerialPort.GetPortNames();
comboBox1.Items.AddRange(PortNames);
}
public string getDataTime()
{
DateTime time = DateTime.Now;
string date = time.ToString(#"hh\:mm\:ss");
return date;
}
public void GetData()
{
string date = getDataTime();
data = serialPort1.ReadLine();
textBox1.AppendText("[" + date + "] " + "Received: " + data + "\r\n");
}
public void cbDefaultValue()
{
comboBox1.SelectedIndex = 0;
comboBox5.SelectedIndex = 0;
comboBox2.SelectedIndex = 0;
comboBox3.SelectedIndex = 0;
comboBox4.SelectedIndex = 0;
}
private void button1_Click(object sender, EventArgs e)
{
try
{
if (comboBox1.Text == "" || comboBox2.Text == "" || comboBox3.Text == "" || comboBox4.Text == "" || comboBox5.Text == "")
{
MessageBox.Show("Please port settings", "Incorrect port settings", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
else
{
DateTime time = DateTime.Now;
string date = time.ToString(#"hh\:mm\:ss");
serialPort1.PortName = comboBox1.Text;
serialPort1.BaudRate = Convert.ToInt32(comboBox2.Text);
switch (comboBox3.Text)
{
case "5":
serialPort1.DataBits = 5;
break;
case "6":
serialPort1.DataBits = 6;
break;
case "7":
serialPort1.DataBits = 7;
break;
case "8":
serialPort1.DataBits = 8;
break;
default:
serialPort1.DataBits = 5;
break;
}
switch (comboBox4.Text)
{
case "None":
serialPort1.Parity = Parity.None;
break;
case "Odd":
serialPort1.Parity = Parity.Odd;
break;
case "Even":
serialPort1.Parity = Parity.Even;
break;
case "Mark":
serialPort1.Parity = Parity.Mark;
break;
case "Space":
serialPort1.Parity = Parity.Space;
break;
}
switch (comboBox5.Text)
{
case "One":
serialPort1.StopBits = StopBits.One;
break;
case "Two":
serialPort1.StopBits = StopBits.Two;
break;
case "OnePointFive":
serialPort1.StopBits = StopBits.OnePointFive;
break;
}
serialPort1.Open();
string CurrentPornName = comboBox1.Text;
label7.Text = "Opened " + CurrentPornName;
panel1.BackColor = ColorTranslator.FromHtml("#42f477");
comboBox1.Enabled = false;
comboBox2.Enabled = false;
comboBox3.Enabled = false;
comboBox4.Enabled = false;
comboBox5.Enabled = false;
//button5.Enabled = false;
//button6.Enabled = false;
}
}
catch (Exception ex)
{
if (ex is UnauthorizedAccessException)
{
MessageBox.Show("Unauthorized Acces","Access Error",MessageBoxButtons.OK, MessageBoxIcon.Error);
}
else if (ex is System.IO.IOException)
{
MessageBox.Show("Please plug in your device", "IO Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
}
}
private void button2_Click(object sender, EventArgs e)
{
panel1.BackColor = ColorTranslator.FromHtml("#f44147");
string CurrentPornName = comboBox1.Text;
label7.Text = "Closed " + CurrentPornName; ;
serialPort1.Close();
comboBox1.Enabled = true;
comboBox2.Enabled = true;
comboBox3.Enabled = true;
comboBox4.Enabled = true;
comboBox5.Enabled = true;
//button5.Enabled = true;
//button6.Enabled = true;
}
private void button5_Click(object sender, EventArgs e)
{
RefreshAvailablePortNames();
}
private void button3_Click(object sender, EventArgs e)
{
//backgroundWorker1.RunWorkerAsync();
Thread thread = new Thread(start: ()=>
{
try
{
datetime = getDataTime();
string date = getDataTime();
startListening:
if (serialPort1.BytesToRead > 0)
{
datetime = getDataTime();
data = serialPort1.ReadLine();
textBox2.AppendText("[" + datetime + "] " + "Received: " + data + "\r\n");
}
else
textBox2.AppendText("[" + datetime + "] " + "Error: There is no data to read" + "\r\n");
if (conn)
goto startListening;
}
catch (Exception ex)
{
DateTime time = DateTime.Now;
string date = time.ToString(#"hh\:mm\:ss");
if (ex is TimeoutException)
{
textBox1.AppendText("[" + date + "] " + "Timuot Exception" + "\r\n");
}
else if (ex is InvalidOperationException)
{
MessageBox.Show("Plese check settings", "Error: Invalid Operation", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
else if (ex is System.IO.IOException)
{
MessageBox.Show("Port opened, but device unpluged..", "IO Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
}
});
thread.Start();
}
private void button4_Click(object sender, EventArgs e)
{
conn = false;
}
private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
try
{
datetime = getDataTime();
string date = getDataTime();
startListening:
if (serialPort1.BytesToRead > 0)
{
datetime = getDataTime();
data = serialPort1.ReadLine();
textBox2.AppendText("[" + datetime + "] " + "Received: " + data + "\r\n");
}
else
textBox2.AppendText("[" + datetime + "] " + "Error: There is no data to read" + "\r\n");
if (conn)
goto startListening;
}
catch (Exception ex)
{
DateTime time = DateTime.Now;
string date = time.ToString(#"hh\:mm\:ss");
if (ex is TimeoutException)
{
textBox1.AppendText("[" + date + "] " + "Timuot Exception" + "\r\n");
}
else if (ex is InvalidOperationException)
{
MessageBox.Show("Plese check settings", "Error: Invalid Operation", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
else if (ex is System.IO.IOException)
{
MessageBox.Show("Port opened, but device unpluged..", "IO Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
}
}
}
}
About Code:
comboBox1 -> where the Ports are listed
comboBox2 -> where the Baud Rates options are listed
comboBox3 -> where the Stop Bits options are listed
comboBox4 -> where the Data Bits options are listed
comboBox5 -> where the Parity options are listed
button1 -> to connect chosen port
button2 -> to disconnect port
button3 -> to start listening and print data into textBox in real time
button4 -> to stop listening
button5 -> refresh available ports
panel1-> to identify port is connected or not (if connected it is green if it is not connected it is red)
So, what i want to do is that when I click the stop button (button4), program have to stop listening. I am trying to achieve this result using backgroundWorker .
Using this code when i try to listen port (clicking start button button3 there is opening the small error window and tell please check settings (so it catching InvalidOperationException according to my code); If I wont use backgoundWorker and also remove try{...} cath{...} program start do display the received data from port but blocking the UI. Any ideas will be very helpful.
button4_click needs to call backgroundWorker1.CancelAsync() instead of setting a bool. With BackgroundWorkers, you need to specify that you want them to end and then check for it, setting and checking an outside bool will not work. The try block in your backgroundWorker1_DoWork() method should look like the following. Keep in mind, it is easier for you and others to help you if you rename your variables (either done in the UI or by right clicking the variable and selecting 'Rename'). Another note before the code, it is almost never ok to use 'goto', there is almost always a better option (a while loop in this case).
datetime = getDataTime();
string date = getDataTime();
while (!backgroundWorker1.CancellationPending)
{
if (serialPort1.BytesToRead > 0)
{
datetime = getDataTime();
data = serialPort1.ReadLine();
textBox2.AppendText($"[{datetime}] Received: {data}\r\n");
}
else
{
textBox2.AppendText($"[{datetime}] Error: There is no data to read\r\n");
}
}
Edit to say: This should get you started, you will also want to check out this link to access your UI from backgroundWorker1, the problem is your UI is on one thread and your BackgroundWorker on another, threads do not work well together without some complimenting code
private void serialPort_DataReceived(object sender, System.IO.Ports.SerialDataReceivedEventArgs e)
{
if (Clos_flag) return;
try
{
Listening = true;
if (serialPort.IsOpen)
{
this.txt_weight.Invoke(new MethodInvoker(delegate
{
serialPort.NewLine = "\r";
string weight = serialPort.ReadLine();
weight = weight.Trim();
MessageBox.Show(weight);
if (weight.IndexOf("i") > 0)
{
weight = weight.Substring(3, 8);
txt_weight.Text = weight.Substring(0, weight.LastIndexOf("0") + 1);
}
}));
}
}
catch (Exception eg)
{
MessageBox.Show(eg.ToString());
}
finally
{
Listening = false;
}
}
I use the above code to read the weighing machine, but it keep on prompt the timeout error I'm not sure which part of the coding is wrong.
You check your configure serialport.
It may be error while run code serialPort.Open().
you can refer code:
void InitialComport1()
{
mySerialPort1 = new SerialPort(Temp._comport1);
if (mySerialPort1.IsOpen)
{
mySerialPort1.Close();
}
mySerialPort1.BaudRate = Temp._baudRate1;
mySerialPort1.Parity = Parity.None;
mySerialPort1.StopBits = StopBits.One;
mySerialPort1.DataBits = Temp._dataBit1;
mySerialPort1.Handshake = Handshake.None;
mySerialPort1.RtsEnable = true;
mySerialPort1.DataReceived += new SerialDataReceivedEventHandler(DataReceivedHandler1);
try
{
mySerialPort1.Open();
}
catch
{
Messagebox.Show("Error myserialPort1")
}
}
private void DataReceivedHandler1(object sender, SerialDataReceivedEventArgs e)
{
try
{
string indata = mySerialPort1.ReadLine();
try
{
string mass = indata.Substring(7, 7);
SetText1((Convert.ToInt32(mass)).ToString());
}
catch
{
string mass = indata.Substring(3, 7);
SetText1((Convert.ToInt32(mass)).ToString());
}
}
catch (Exception eg)
{
MessageBox.Show(eg.ToString());
}
}
I am trying to On/Off a led from desktop app on C# to Arduino using Ethernet (for serial port communication works), I am connecting to an IP Address to communicate with Arduino, but it looks something wrong with my code or my sketch for Arduino. (I am working with Ethernet shield)
my code Arduino
//////////INCLUDE HEADER FILES //////////////////
#include <Ethernet.h>
#include <SPI.h>
#include <EEPROM.h>
#include <LiquidCrystal.h>
#include <SD.h>
#include <Wire.h>
EthernetServer server(23 );
String content;
File myFile;
int ledPin = 7;
int outputpin = 0;
void setup()
{
IPAddress ip( 192, 168,1,110);
byte mac[] = {
0xDE,0xAE,0xBE,0xEF,0xFE,0xED
};
Ethernet.begin( mac, ip );
server.begin();
if ( ! SD.begin( 4 ) )
{
return;
}
Serial.begin(9600);
}
void loop()
{
waitIncommingConnection();
}
void waitIncommingConnection()
{
String pwd = "";
String inData = "";
EthernetClient client = server.available();
if ( client )
{
while ( client.connected() )
{
if ( client.available() > 0)
{
char recieved = client.read();
inData += recieved;
if (recieved == '\n')
{
switch( inData[0] )
{
case (char)'o' :
client.println("o");
digitalWrite(ledPin, HIGH);
break;
case (char)'f' :
client.println("f");
digitalWrite(ledPin, LOW);
break;
case (char)'*' :
Logout(client);
break;
default:
client.println('d');
break;
}
inData = "";
}
}
}
}
else
{
client.println('v');
}
}
void Logout(EthernetClient client )
{
client.print('x');
client.stop();
}
My C# code
public partial class Form1 : Form
{
public Client client;
public delegate void FeedBackCallback(string text);
public delegate void UpdateMessageBoxCallback(string text);
public Form1()
{
InitializeComponent();
}
private void connect_Click(object sender, EventArgs e)
{
string ipAddr = ip1.Text + "." + ip2.Text + "." + ip3.Text + "." + ip4.Text;
string port = portInput.Text;
if (IsValidIPAddress(ipAddr) == true)
{
try
{
if (client == null)
client = new Client(this);
client.Connect(ipAddr, port);
// client.Send(Encoding.GetEncoding(Constant.EncodingFormat).GetBytes("c"+'\n'));
disconect.Enabled = true;
connect.Enabled = false;
on.Enabled = true;
}
catch (SocketException se)
{
MessageBox.Show("Unable to Connect.\r\n" + se.ToString());
}
}
else
{
MessageBox.Show("Invaild Ip Adrress", "Invaild Ip Adrress", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
}
private bool IsEmptyUserNamePasswordFields(string userName, string password)
{
if (userName.Length == 0 || password.Length == 0)
{
MessageBox.Show("Password and Username field is required!", "Required Fileds Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
return false;
}
else
{
return true;
}
}
private bool IsValidIPAddress(string ipaddr)//Validate the input IP address
{
try
{
IPAddress.Parse(ipaddr);
return true;
}
catch (Exception e)
{
return false;
}
}
private void on_Click(object sender, EventArgs e)
{
disconect.PerformClick();
connect.PerformClick();
try
{
if (client == null)
client = new Client(this);
client.Send(Encoding.GetEncoding(Constant.EncodingFormat).GetBytes("o" + '\n'));
off.Enabled = true;
on.Enabled = false;
}
catch (SocketException se)
{
MessageBox.Show("Unable to Connect.\r\n" + se.ToString());
}
}
private void off_Click(object sender, EventArgs e)
{
disconect.PerformClick();
connect.PerformClick();
try
{
if (client == null)
client = new Client(this);
client.Send(Encoding.GetEncoding(Constant.EncodingFormat).GetBytes("f" + '\n'));
on.Enabled = true;
off.Enabled = false;
}
catch (SocketException se)
{
MessageBox.Show("Unable to Connect.\r\n" + se.ToString());
}
}
private void disconect_Click(object sender, EventArgs e)
{
connect.Enabled = true;
disconect.Enabled = false;
client.Disconnect();
}
}
images for the Arduino
I don't know where is my problem, the app connect to the arduino, but the On/Off button not works for the led.
if u want to see the code foe serial port communication this is the link here, Serial Port
Yesterday I have created two forms, the first form listen requests of client out network, the second form is form alert (MessageBox custom) like MessageBox, but when a client sends a connection request to the first form, affter the form second will show, but affter click on any button to close form and I received an message below:
Title: System.InvalidOperationException
Details:
The Undo operation encountered a context that is different from what was applied in the corresponding Set operation. The possible cause is that a context was Set on the thread and not reverted(undone).
The First From:
//Nhận các yêu cầu và kiểm tra và gửi phản hồi
private void OnReceive(IAsyncResult ar)
{
try
{
EndPoint receivedFromEP = new IPEndPoint(IPAddress.Any, 0);
//Get the IP from where we got a message.
clientSocket.EndReceiveFrom(ar, ref receivedFromEP);
//Convert the bytes received into an object of type Data.
Data(byteData);
//Act according to the received message.
switch (cmdCommand)
{
//We have an incoming call.
case Command.Invite:
{
if (bIsCallActive == false)
{
//We have no active call.
//Ask the user to accept the call or not.
DialogResult result = ThongBaoCoDienThoai.HienHopThoai(strName);
if (result == DialogResult.Yes)
{
//SendMessage(Command.OK, receivedFromEP);
//Bắt đầu kết nôi
//**********************************GOI PHUONg THUC GUI NHAN DONG BO AM THANH****************
}
else
{
//The call is declined. Send a busy response.
//SendMessage(Command.Busy, receivedFromEP);
}
}
else
{
//We already have an existing call. Send a busy response.
SendMessage(Command.Busy, receivedFromEP);
}
break;
}
//OK is received in response to an Invite.
case Command.OK:
{
//Start a call.
break;
}
//Remote party is busy.
case Command.Busy:
{
MessageBox.Show("User busy.", "VoiceChat", MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
break;
}
case Command.Bye:
{
//Check if the Bye command has indeed come from the user/IP with which we have
//a call established. This is used to prevent other users from sending a Bye, which
//would otherwise end the call.
if (receivedFromEP.Equals(otherPartyEP) == true)
{
//End the call.
}
break;
}
}
byteData = new byte[1024];
//Get ready to receive more commands.
clientSocket.BeginReceiveFrom(byteData, 0, byteData.Length, SocketFlags.None, ref receivedFromEP, new AsyncCallback(OnReceive), null);
}
catch (Exception ex)
{
MessageBox.Show("OnReceive: " + ex.Message, "Error");
}
}
The Second Form:
static ThongBaoCoDienThoai tbcdt;
static DialogResult kq = DialogResult.No;
private Timer thoiGian;
int henGioTat; //Hẹn thời gian tắt form
SoundPlayer player; //Khởi tạo thiết bị phát (Loa)
public ThongBaoCoDienThoai()
{
InitializeComponent();
try
{
henGioTat = 30;
thoiGian = new Timer();
thoiGian.Interval = 1000;
thoiGian.Enabled = true;
thoiGian.Start();
thoiGian.Tick += new EventHandler(this.thoiGian_Tick);
//Hiển thị hộp thông báo ở góc màng hình dưới bên phải
Rectangle r = Screen.PrimaryScreen.WorkingArea;
this.StartPosition = FormStartPosition.Manual;
this.Location = new Point(Screen.PrimaryScreen.WorkingArea.Width - this.Width, Screen.PrimaryScreen.WorkingArea.Height - this.Height);
//Phát âm thành khi form được mở
player = new SoundPlayer(Properties.Resources.ringing);
player.Load();
player.PlayLooping();
}
catch (Exception ex)
{
MessageBox.Show("ThongBaoCoDienThoai_Load :" + ex.Message, "Error");
}
}
public static DialogResult HienHopThoai(string tenNguoiGoi)
{
try
{
tbcdt = new ThongBaoCoDienThoai();
tbcdt.lbThongBao.Text = tenNguoiGoi + " đang gọi........";
tbcdt.ShowDialog();
}
catch (Exception ex)
{
MessageBox.Show("HienHopThoai: "+ex.Message,"Error");
}
return kq;
}
private void btHuy_Click(object sender, EventArgs e)
{
tbcdt.thoiGian.Stop();
tbcdt.thoiGian.Dispose();
kq = DialogResult.No;
tbcdt.Dispose();
}
private void btNhan_Click(object sender, EventArgs e)
{
ThongBaoCoDienThoai tbcdt = new ThongBaoCoDienThoai();
alertControl1.Show(tbcdt);
tbcdt.thoiGian.Stop();
tbcdt.thoiGian.Dispose();
kq = DialogResult.Yes;
tbcdt.Dispose();
}
private void thoiGian_Tick(object sender, EventArgs e)
{
henGioTat--;
if (henGioTat == 0)
{
tbcdt.thoiGian.Stop();
tbcdt.thoiGian.Dispose();
tbcdt.Dispose();
}
}
private void ThongBaoCoDienThoai_FormClosing(object sender, FormClosingEventArgs e)
{
player.Stop();
}
I wrote code to send an SMS using my GSM phone which is attached to the computer through COM port. The code is below.
The problem is I do see that it is in the outbox of the phone and it actually appears to have been sent, but when I contact the recipient they say that I have not received the message.
I test the phone, and I create and send a message using only the phone and it works perfectly. However, when I do this with my code, it APPEARS to have been sent, and I am getting all the correct AT COMMAND responses from the phone, but the message is actually NOT sent.
Here is the code:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Threading;
using System.IO.Ports;
namespace WindowsFormsApplication1
{
public partial class Form1 : Form
{
SerialPort serialPort1;
int m_iTxtMsgState = 0;
const int NUM_MESSAGE_STATES = 4;
const string RESERVED_COM_1 = "COM1";
const string RESERVED_COM_4 = "COM4";
public Form1()
{
InitializeComponent();
this.Closing += new CancelEventHandler(Form1_Closing);
}
private void Form1_Load(object sender, EventArgs e)
{
serialPort1 = new SerialPort(GetUSBComPort());
if (serialPort1.IsOpen)
{
serialPort1.Close();
}
serialPort1.Open();
//ThreadStart myThreadDelegate = new ThreadStart(ReceiveAndOutput);
//Thread myThread = new Thread(myThreadDelegate);
//myThread.Start();
this.serialPort1.DataReceived += new SerialDataReceivedEventHandler(sp_DataReceived);
}
private void Form1_Closing(object sender, System.ComponentModel.CancelEventArgs e)
{
serialPort1.Close();
}
private void SendLine(string sLine)
{
serialPort1.Write(sLine);
sLine = sLine.Replace("\u001A", "");
consoleOut.Text += sLine;
}
public void DoWork()
{
ProcessMessageState();
}
public void ProcessMessageState()
{
switch (m_iTxtMsgState)
{
case 0:
m_iTxtMsgState = 1;
SendLine("AT\r\n"); //NOTE: SendLine must be the last thing called in all of these!
break;
case 1:
m_iTxtMsgState = 2;
SendLine("AT+CMGF=1\r\n");
break;
case 2:
m_iTxtMsgState = 3;
SendLine("AT+CMGW=" + Convert.ToChar(34) + "+9737387467" + Convert.ToChar(34) + "\r\n");
break;
case 3:
m_iTxtMsgState = 4;
SendLine("A simple demo of SMS text messaging." + Convert.ToChar(26));
break;
case 4:
m_iTxtMsgState = 5;
break;
case 5:
m_iTxtMsgState = NUM_MESSAGE_STATES;
break;
}
}
private string GetStoredSMSID()
{
return null;
}
/* //I don't think this part does anything
private void serialPort1_DataReceived_1(object sender, System.IO.Ports.SerialDataReceivedEventArgs e)
{
string response = serialPort1.ReadLine();
this.BeginInvoke(new MethodInvoker(() => textBox1.AppendText(response + "\r\n")));
}
*/
void sp_DataReceived(object sender, SerialDataReceivedEventArgs e)
{
try
{
Thread.Sleep(500);
char[] msg;
msg = new char[613];
int iNumToRead = serialPort1.BytesToRead;
serialPort1.Read(msg, 0, iNumToRead);
string response = new string(msg);
this.BeginInvoke(new MethodInvoker(() => textBox1.AppendText(response + "\r\n")));
serialPort1.DiscardInBuffer();
if (m_iTxtMsgState == 4)
{
int pos_cmgw = response.IndexOf("+CMGW:");
string cmgw_num = response.Substring(pos_cmgw + 7, 4);
SendLine("AT+CMSS=" + cmgw_num + "\r\n");
//stop listening to messages received
}
if (m_iTxtMsgState < NUM_MESSAGE_STATES)
{
ProcessMessageState();
}
}
catch
{ }
}
private void button1_Click(object sender, EventArgs e)
{
m_iTxtMsgState = 0;
DoWork();
}
private void button2_Click(object sender, EventArgs e)
{
string[] sPorts = SerialPort.GetPortNames();
foreach (string port in sPorts)
{
consoleOut.Text += port + "\r\n";
}
}
private string GetUSBComPort()
{
string[] sPorts = SerialPort.GetPortNames();
foreach (string port in sPorts)
{
if (port != RESERVED_COM_1
&& port != RESERVED_COM_4)
{
return port;
}
}
return null;
}
}
This is my code that works (tested) with U9 Telia cellular modem:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime.InteropServices;
using System.Diagnostics;
using System.Configuration;
using UsbEject.Library;
using Utils;
namespace Hardware
{
public class TeliaModem : IDisposable
{
public delegate void NewSmsHandler(InboundSMS sms);
public event NewSmsHandler OnNewSMS;
#region private data
System.IO.Ports.SerialPort modemPort;
Timeouter _lastModemKeepAlive;
private delegate void DataReceivedDelegate();
private DataReceivedDelegate dataReceivedDelegate;
Queue<OutboundSMS> _outSmses = new Queue<OutboundSMS>();
enum ModemState
{
Error = -1, NotInitialized, PowerUp, Initializing, Idle,
SendingSMS, KeepAliveAwaitingResponse
};
Timeouter ModemStateTimeouter = new Timeouter(timeout_s: 10, autoReset: false);
ModemState _modemState = ModemState.NotInitialized;
ModemState CurrentModemState
{
get
{
return _modemState;
}
set
{
_modemState = value;
ModemStateTimeouter.Reset();
NihLog.Write(NihLog.Level.Debug, "State changed to: " + value.ToString());
}
}
private System.Windows.Forms.Control _mainThreadOwnder;
#endregion
public TeliaModem(System.Windows.Forms.Control mainThreadOwnder)
{
_mainThreadOwnder = mainThreadOwnder;
dataReceivedDelegate = new DataReceivedDelegate(OnDataReceived);
}
public void SendSMS(string phone, string text)
{
_outSmses.Enqueue(new OutboundSMS(phone, text));
HeartBeat();
}
private void SendSmsNow()
{
OutboundSMS sms = _outSmses.Peek();
sms.Attempt++;
if (sms.Attempt > sms.MaxTries)
{
NihLog.Write(NihLog.Level.Error, "Failure to send after " + sms.MaxTries + " tries");
_outSmses.Dequeue();
return;
}
NihLog.Write(NihLog.Level.Info, "Sending SMS: " + sms.ToString());
WriteToModem("AT+CMGS=\"" + sms.Destination + "\"\r");
System.Threading.Thread.Sleep(500);
WriteToModem(sms.Text);
byte[] buffer = new byte[1];
buffer[0] = 26; // ^Z
modemPort.Write(buffer, offset:0, count:1);
CurrentModemState = ModemState.SendingSMS;
}
public void Dispose()
{
UninitModem();
}
public void HeartBeat()
{
if (CurrentModemState == ModemState.NotInitialized)
{
TryInitModem();
return;
}
if (IsTransitionalState(CurrentModemState) && ModemStateTimeouter.IsTimedOut())
{
NihLog.Write(NihLog.Level.Error, "Modem error. Timed out during " + CurrentModemState);
CurrentModemState = ModemState.Error;
return;
}
if (CurrentModemState == ModemState.Idle && _lastModemKeepAlive.IsTimedOut())
{
// Send keepalive
WriteToModem("AT\r");
CurrentModemState = ModemState.KeepAliveAwaitingResponse;
return;
}
if (CurrentModemState == ModemState.Error)
{
NihLog.Write(NihLog.Level.Debug, "Reenumerating modem...");
UninitModem();
return;
}
if (_outSmses.Count != 0 && CurrentModemState == ModemState.Idle)
{
SendSmsNow();
return;
}
}
private string pendingData;
private void OnDataReceived()
{
// Called in the main thread
string nowWhat = modemPort.ReadExisting();
pendingData += nowWhat;
string[] lines = pendingData.Split(new string[] { "\r\n" }, StringSplitOptions.None);
if (lines.Length == 0)
{
pendingData = string.Empty;
return;
}
else
{
pendingData = lines[lines.Length - 1];
}
// This happens in main thread.
for (int i = 0; i < lines.Length - 1; i++)
{
string line = lines[i];
if (line.Length >= 5 && line.Substring(0, 5) == "+CMT:")
{
// s+= read one more line
if (i == lines.Length - 1) // no next line
{
pendingData = line + "\r\n" + pendingData; // unread the line
continue;
}
string line2 = lines[++i];
NihLog.Write(NihLog.Level.Debug, "RX " + line);
NihLog.Write(NihLog.Level.Debug, "RX " + line2);
InboundSMS sms = new InboundSMS();
sms.ParseCMT(line, line2);
if(OnNewSMS != null)
OnNewSMS(sms);
}
else // Not a composite
NihLog.Write(NihLog.Level.Debug, "RX " + line);
if (line == "OK")
{
OnModemResponse(true);
}
else if (line == "ERROR")
{
OnModemResponse(false);
NihLog.Write(NihLog.Level.Error, "Modem error");
}
}
}
private void ProcessSmsResult(bool ok)
{
if (!ok)
{
OutboundSMS sms = _outSmses.Peek();
if (sms.Attempt < sms.MaxTries)
{
NihLog.Write(NihLog.Level.Info, "Retrying sms...");
return;
}
NihLog.Write(NihLog.Level.Error, "Failed to send SMS: " + sms.ToString());
}
_outSmses.Dequeue();
}
private void OnModemResponse(bool ok)
{
if (CurrentModemState == ModemState.SendingSMS)
ProcessSmsResult(ok);
if (!ok)
{
NihLog.Write(NihLog.Level.Error, "Error during state " + CurrentModemState.ToString());
CurrentModemState = ModemState.Error;
return;
}
switch (CurrentModemState)
{
case ModemState.NotInitialized:
return;
case ModemState.PowerUp:
WriteToModem("ATE0;+CMGF=1;+CSCS=\"IRA\";+CNMI=1,2\r");
CurrentModemState = ModemState.Initializing;
break;
case ModemState.Initializing:
case ModemState.SendingSMS:
case ModemState.KeepAliveAwaitingResponse:
CurrentModemState = ModemState.Idle;
break;
}
}
private void CloseU9TelitNativeApp()
{
bool doneSomething;
do
{
doneSomething = false;
Process[] processes = Process.GetProcessesByName("wirelesscard");
foreach (Process p in processes)
{
p.CloseMainWindow();
doneSomething = true;
NihLog.Write(NihLog.Level.Info, "Killed native U9 app");
System.Threading.Thread.Sleep(1000); // Will not wait if no native app is started
}
} while (doneSomething);
}
void WriteToModem(string s)
{
modemPort.Write(s);
NihLog.Write(NihLog.Level.Debug, "TX " + s);
}
void UninitModem()
{
if (modemPort != null)
modemPort.Dispose();
modemPort = null;
CurrentModemState = ModemState.NotInitialized;
}
private bool IsTransitionalState(ModemState ms)
{
return ms == ModemState.Initializing
|| ms == ModemState.SendingSMS
|| ms == ModemState.PowerUp
|| ms == ModemState.KeepAliveAwaitingResponse;
}
Timeouter _initFailureTimeout =
new Timeouter(timeout_s: 10, autoReset:false, timedOut:true);
void TryInitModem()
{
// Try pistoning the modem with higher frequency. This does no harm (such as redundant logging)
PrepareU9Modem(); // Will do nothing if modem is okay
if (!_initFailureTimeout.IsTimedOut())
return; // Don't try too frequently
if (modemPort != null)
return;
const string modemPortName = "Basecom HS-USB NMEA 9000";
const int speed = 115200;
string portName = Hardware.Misc.SerialPortFromFriendlyName(modemPortName);
if (portName == null)
{
NihLog.Write(NihLog.Level.Error, "Modem not found (yet). ");
_initFailureTimeout.Reset();
return;
}
NihLog.Write(NihLog.Level.Info, string.Format("Found modem port \"{0}\" at {1}", modemPortName, portName));
modemPort = new System.IO.Ports.SerialPort(portName, speed);
modemPort.ReadTimeout = 3000;
modemPort.NewLine = "\r\n";
modemPort.Open();
modemPort.DiscardInBuffer();
modemPort.DataReceived += new System.IO.Ports.SerialDataReceivedEventHandler(delegate { _mainThreadOwnder.Invoke(dataReceivedDelegate); }); // called in different thread!
_lastModemKeepAlive = new Timeouter(60, true);
WriteToModem("AT+CFUN=1\r");
CurrentModemState = ModemState.PowerUp;
}
void CheatU9Telit()
{
// U9 telit appears as USB CDrom on the bus, until disk eject is sent.
// Then, it reappears as normal stuff.
VolumeDeviceClass volumeDeviceClass = new VolumeDeviceClass();
foreach (Volume device in volumeDeviceClass.Devices)
{
if (device.FriendlyName == "PCL HSUPA Modem USB Device")
{
NihLog.Write(NihLog.Level.Info, "Trying to initialize: " + device.FriendlyName);
device.EjectCDRomNoUI();
}
}
}
void PrepareU9Modem()
{
CloseU9TelitNativeApp(); // Closes the autorun native app
CheatU9Telit();
}
}
public class OutboundSMS
{
public string Destination;
public string Text;
public int MaxTries;
public int Attempt = 0;
public OutboundSMS(string dest, string txt)
{
Destination = dest;
Text = txt;
MaxTries = 3;
}
override public string ToString()
{
if(Attempt > 1)
return string.Format("\"{0}\" to {1}, attempt {2}",
Text, Destination, Attempt);
else
return string.Format("\"{0}\" to {1}",
Text, Destination);
}
}
public class InboundSMS
{
public string SourcePhone;
public DateTime ReceiveTime;
public string Text;
public void ParseCMT(string line1, string line2)
{
string[] fields = line1.Split(new char[] { ',', ' ', '/', ':', '"' });
if (fields.Length < 12)
throw new ApplicationException("CMT message too short. Expected 2 fields");
SourcePhone = fields[3];
ReceiveTime = DateTime.Parse("20" + fields[7] + "-" + fields[8] + "-" + fields[9] + " " + fields[10] + ":" + fields[11] + ":" + fields[12].Substring(0, 2)); //test carefully
Text = line2;
}
};
}
Usage example in a winforms application:
Hardware.TeliaModem _modem;
public Form1()
{
InitializeComponent();
_modem = new Hardware.TeliaModem(this);
_modem.OnNewSMS += new Hardware.TeliaModem.NewSmsHandler(ProcessNewSMS);
_timer.Interval = 1000; // milliseconds
_timer.Tick += new EventHandler(OnTimerTick);
_timer.Start();
}
To send an SMS:
_modem.SendSMS(sms.SourcePhone, "Aircon is now " + BoolToString.ON_OFF(_aircon.On));
On timer event, once every second:
private void OnTimerTick(object o, EventArgs e)
{
_modem.HeartBeat();
}
This is registered as Winforms timer handler, so that modem will not have a thread.
Some utility classes used:
namespace Utils
{
public class StopWatch
{
protected DateTime _resetTime;
public StopWatch() { Reset(); }
public void Reset() { _resetTime = DateTime.Now; }
public double TotalSeconds { get { return (DateTime.Now - _resetTime).TotalSeconds; } }
public TimeSpan Time { get { return DateTime.Now - _resetTime; } }
};
public class Timeouter : StopWatch
{
private bool _autoReset;
private double _timeout_s;
public Timeouter(double timeout_s, bool autoReset, bool timedOut = false)
{
_timeout_s = timeout_s;
_autoReset = autoReset;
if (timedOut)
_resetTime -= TimeSpan.FromSeconds(_timeout_s + 1); // This is surely timed out, as requested
}
public bool IsTimedOut()
{
if (_timeout_s == double.PositiveInfinity)
return false;
bool timedout = this.TotalSeconds >= _timeout_s;
if (timedout && _autoReset)
Reset();
return timedout;
}
public void Reset(double timeout_s) { _timeout_s = timeout_s; Reset(); }
public double TimeLeft { get { return _timeout_s - TotalSeconds; } }
}
}
I implemented this in order to turn on air conditioner with SMS (yeah, I live in a hot country). It works. Please feel free to use any of this code.
Enjoy.
Microsoft provides a pretty decent VB.Net example in a KB article "How to access serial and parallel ports by using Visual Basic .NET". I'm not sure what your phone returns, however, if you change the buffer loop in the example, you can at least print out the reply:
MSComm1.Output = "AT" & Chr(13)
Console.WriteLine("Send the attention command to the modem.")
Console.WriteLine("Wait for the data to come back to the serial port...")
' Make sure that the modem responds with "OK".
' Wait for the data to come back to the serial port.
Do
Buffer = Buffer & MSComm1.Input
Console.WriteLine("Found: {0}", Buffer)
Loop Until InStr(Buffer, "OK" & vbCrLf)
GSMComm is a C# library that will allow you to easily interact with a GSM mobile in text or PDU mode. (The site also has a bunch of testing utilities)
Working with GSM modem to send SMS has never been a good idea as such. Here's a checklist to make sure your SMS is sent out properly.
You are sending the SMS in text mode. Try sending it in PDU mode.
Try this library http://phonemanager.codeplex.com/
Do you change SMSC number before sending out the SMS, if so make sure the SMSC is correct.
Also make sure your SIM card has enough credits to let you send outbound SMS.
Check the network status especially when you're sending out SMS from your program. This might be a problem.
I recommend you checkout the Lite edition of NowSMS gateway that comes for free and lets you work with GSM modem very continently. NowSMS will give you api abstraction over a GSM modem connection, so you wil just need to call the Http Api of NowSMS gateway, rest will be taken care by the NowSMS gateway.
Above all this, if your end-users are going to remain internet connected while using your application or if your application is web-based and hosted over internet, I strongly recoomend to do away with GSM modem option and opt-in for reliable Http SMS gateway service providers.