I want to loop through the available ports:
System.IO.Ports.SerialPort.GetPortNames()
to find if a port is used by a gsm modem.
Any idea please.
What I did in my application for one similar task:
To check that a modem is connected to particular port you can send AT command into this port.
This function below returns true if we found a modem on the current COM port:
private bool CheckExistingModemOnComPort(SerialPort serialPort)
{
if ((serialPort == null) || !serialPort.IsOpen)
return false;
// Commands for modem checking
string[] modemCommands = new string[] { "AT", // Check connected modem. After 'AT' command some modems autobaud their speed.
"ATQ0" }; // Switch on confirmations
serialPort.DtrEnable = true; // Set Data Terminal Ready (DTR) signal
serialPort.RtsEnable = true; // Set Request to Send (RTS) signal
string answer = "";
bool retOk = false;
for (int rtsInd = 0; rtsInd < 2; rtsInd++)
{
foreach (string command in modemCommands)
{
serialPort.Write(command + serialPort.NewLine);
retOk = false;
answer = "";
int timeout = (command == "AT") ? 10 : 20;
// Waiting for response 1-2 sec
for (int i = 0; i < timeout; i++)
{
Thread.Sleep(100);
answer += serialPort.ReadExisting();
if (answer.IndexOf("OK") >= 0)
{
retOk = true;
break;
}
}
}
// If got responses, we found a modem
if (retOk)
return true;
// Trying to execute the commands without RTS
serialPort.RtsEnable = false;
}
return false;
}
On the next stage we can collect some data from the modem.
I used the following commands:
ATQ0 - switch on confirmations (receive OK on each request)
ATE0 - switch on echo
ATI - get modem details
ATI3 - get extended modem details (not all modems supports this command)
// Check each Availble COM port
foreach (string l_sport in l_available_ports)
{
GlobalVars.g_serialport = GlobalFunc.OpenPort(l_sport, Convert.ToInt32(this.cboBaudRate.Text), Convert.ToInt32(this.cboDataBits.Text), Convert.ToInt32(this.txtReadTimeOut.Text), Convert.ToInt32(this.txtWriteTimeOut.Text));
if (GlobalVars.g_serialport.IsOpen)
{
GlobalVars.g_serialport.WriteLine("AT\r");
Thread.Sleep(500);
string l_response = GlobalVars.g_serialport.ReadExisting();
if (l_response.IndexOf("OK") >= 0)
{
GlobalVars.g_serialport.WriteLine("AT+CMGF=1\r");
Thread.Sleep(500);
string l_response1 = GlobalVars.g_serialport.ReadExisting();
if (l_response1.IndexOf("OK") >= 0)
{
GlobalVars.g_PhoneNo = txt_PhNum.Text;
MessageBox.Show("Connected Successfully", "Connection", MessageBoxButtons.OK, MessageBoxIcon.Information);
lblConnectionStatus.Text = "Phone Connected Successfully.";
btnOK.Enabled = false;
btnDisconnect.Enabled = true;
GlobalVars.g_serialport.WriteLine("AT+CGSN\r");
Thread.Sleep(500);
string l_imei = GlobalVars.g_serialport.ReadExisting();
Console.WriteLine("Modem IMEI:" + l_imei);
if (l_imei.IndexOf("OK", 1) > 0)
{
l_imei = l_imei.Replace("AT+CGSN\r\r\n", null);
l_imei = l_imei.Replace("\r\n\r\nOK\r\n", null);
lbl_ModemIMEI.Text = l_imei;
}
else
{
lblConnectionStatus.Text = "Phone Connected Successfully. Error reading IMEI.";
}
EnableSMSNotification(GlobalVars.g_serialport);
break;
}
else
{
Console.WriteLine("No AT+CMGF cmd response");
}
}
else
{
Console.WriteLine("No AT cmd response");
}
}
else
{
Console.WriteLine("No Phone At:" + l_sport);
}
}
Related
I am currently developing a one-to-many relationship between one server and many clients.
Everytime a client connects I append to the client list: clientList.Add(client);
I wrote the following code to check the "pulse" of the client connection as to see if the client is still connected and currently updating the toolStripStatusLabel1
This seems to work well when checking one connection and in addition, I added the exception cleanup() when trying to send data so that it should check at all scenarios(Feel free to give your opinion).
My question now is, how do I check the connection from multiple clients?
Please find below the reference code:
private void StartListen()
{
//Creating a TCP Connection and listening to the port
tcpListener = new TcpListener(System.Net.IPAddress.Any, 6666);
tcpListener.Start();
toolStripStatusLabel1.Text = "Listening on port 6666 ...";
int counter = 0;
appStatus = 0;
while (true)
{
try
{
client = tcpListener.AcceptTcpClient();
counter++;
clientList.Add(client);
IPEndPoint ipend = (IPEndPoint)client.Client.RemoteEndPoint;
//Updating status of connection
toolStripStatusLabel1.Text = "Connected from " + IPAddress.Parse(ipend.Address.ToString());
appStatus = 1;
th_outPutStream = new Thread(delegate () { outPutStream(client); });
th_outPutStream.Start();
th_inPutStream = new Thread(delegate () { inPutStream(client); });
th_inPutStream.Start();
th_checkConnection = new Thread(checkConnection);
th_checkConnection.Start();
}
catch (Exception err)
{
Cleanup();
}
}
}
private void checkConnection()
{
bool status = true;
while (status == true)
{
status = IsConnected();
if (status == true)
{
System.Threading.Thread.Sleep(3000); //Wait 3 seconds then try again
}
else
{
Cleanup();
}
}
}
private bool IsConnected()
{
try
{
return !(client.Client.Poll(1, SelectMode.SelectRead) && client.Client.Available == 0);
}
catch (SocketException) { Cleanup(); return false; }
}
I did this by simply creating a forloop for each client in my client list:
private void checkConnection()
{
bool status = true;
while (true)
{
for (int i = 0; i < clientList.Count; i++)
{
Debug.WriteLine(clientList.Count);
status = IsConnected(i);
if (status == true)
{
}
else
{
Cleanup(i);
}
}
System.Threading.Thread.Sleep(3000); //Wait 3 seconds then try again
}
}
private bool IsConnected(int i)
{
try
{
return !(clientList[i].Client.Poll(1, SelectMode.SelectRead) && clientList[i].Client.Available == 0);
}
catch (SocketException) { Cleanup_dep(); return false; }
}
I'm trying to search for a modbus that is connected to a serial port on my device and run some commands against it. However it seems to be that it is rather inconsistent at reading the holding registers. I'm using the NModbus4 library.
I have a thread running every second that checks for available serial ports and tries to get a connection:
// === Check if port is open, start connecting procedure if closed
if (!(serialPort.IsOpen))
{
List<string> portnames = new List<string>();
foreach (string s in SerialPort.GetPortNames())
{
portnames.Add(s); // COM3
}
// === Loop through the listed ports and try to connect
foreach (string portname in portnames)
{
if (!(serialPort.IsOpen))
{
try
{
serialPort.PortName = portname;
serialPort.BaudRate = 57600;
serialPort.DataBits = 8;
serialPort.Parity = Parity.None;
serialPort.StopBits = StopBits.Two;
serialPort.Open();
}
catch (Exception e)
{
Console.WriteLine(e.Message);
}
}
}
}
// === Check again after connecting procedure if the port is open
if (serialPort.IsOpen)
{
// === Check number of open ports
if (SerialPort.GetPortNames().Count() != 0)
{
// === Check if master is defined
if (master == null)
{
// === Define master
master = ModbusSerialMaster.CreateRtu(serialPort);
}
// === If master is already defined
if (master != null)
{
int parameterID = this.readParameterSetID();
if (parameterID != 0)
{
if (!desk_devices.Contains(parameterID))
{
desk_devices.Add(parameterID);
newDevice = true;
}
}
}
} else
{
// === No serial ports available, close the opened serial port
serialPort.Close();
}
}
The readParameterSetID function is as following:
private int readParameterSetID()
{
int parameterSetID = 0;
if (mutex)
{
Console.WriteLine("---Poll overrun----");
}
mutex = true;
if (serialPort.IsOpen)
{
if (master != null)
{
try
{
ushort[] holding_register = master.ReadHoldingRegisters(1, 107, 1); // Fails here
for (int i = 0; i < 1; i++)
{
int tmpStart = Convert.ToInt32(107 + i);
String tempStart = Convert.ToString(tmpStart, 16);
int tmpReg = Convert.ToInt32(holding_register[i]);
String tempReg = Convert.ToString(tmpReg, 16);
parameterSetID = holding_register[i];
}
} catch (Exception e)
{
Console.WriteLine(e.Message);
}
}
}
mutex = false;
return parameterSetID;
}
Now the weird thing happening here is that the readParameterSetID function should return a 7 or a 0 when executed correctly. However sometimes it just stops after reading the holding registers. mutex will stay true and nothing gets returned. When I reboot the application it either works or the same thing happens again.
I don't know why it's working in 50% of the situations and the other 50% returns nothing. I've tried to redefine the master if the function readParameterSetID fails, however I noticed that once every couple second the master will be reset resulting in commands further down the line not being send.
I'd love to know why this is happening or a way to fix this and read the holding registers without the communication failing.
I am planning to send sms using a modem in C# from an asp.net application.As the project will be
integrated to another project it wont be having any field for user input to enter the com port.How can i get the port number where my modem in connected from C#.
Thanks,
Sagar.
To check that a modem is connected to particular port you can send AT command into this port.
This function below returns true if we found a modem on the current COM port:
private bool CheckExistingModemOnComPort(SerialPort serialPort)
{
if ((serialPort == null) || !serialPort.IsOpen)
return false;
// Commands for modem checking
string[] modemCommands = new string[] { "AT", // Check connected modem. After 'AT' command some modems autobaud their speed.
"ATQ0" }; // Switch on confirmations
serialPort.DtrEnable = true; // Set Data Terminal Ready (DTR) signal
serialPort.RtsEnable = true; // Set Request to Send (RTS) signal
string answer = "";
bool retOk = false;
for (int rtsInd = 0; rtsInd < 2; rtsInd++)
{
foreach (string command in modemCommands)
{
serialPort.Write(command + serialPort.NewLine);
retOk = false;
answer = "";
int timeout = (command == "AT") ? 10 : 20;
// Waiting for response 1-2 sec
for (int i = 0; i < timeout; i++)
{
Thread.Sleep(100);
answer += serialPort.ReadExisting();
if (answer.IndexOf("OK") >= 0)
{
retOk = true;
break;
}
}
}
// If got responses, we found a modem
if (retOk)
return true;
// Trying to execute the commands without RTS
serialPort.RtsEnable = false;
}
return false;
}
On the next stage we can collect some data from the modem.
ATQ0 - switch on confirmations (receive OK on each request)
ATE0 - switch on echo
ATI - get modem details
ATI3 - get extended modem details (not all modems supports this command)
I cannot reconnect to COM port after device on the other end abruptly drops connection.
I can connect again only if I close and re-open the application.
Here is my connection function:
public bool connectTurboPump()
{
try
{
if (TPumpSerialPort != null && TPumpSerialPort.IsOpen == true)
return true;
DataRow dr = tblTPump.Rows[0];
Types.Connection TPumpConnection = new Types.Connection();
TPumpConnection.PORT = dr["port"].ToString();
TPumpConnection.BAUD_RATE = Convert.ToInt32(dr["baud"]);
TPumpConnection.PARITY = (Parity)Enum.Parse(typeof(Parity), dr["parity"].ToString(), true);
TPumpConnection.DATA_BITS = Convert.ToInt32(dr["dataBits"]);
TPumpConnection.STOP_BITS = (StopBits)Enum.Parse(typeof(StopBits), dr["stopBits"].ToString(), true);
TPumpConnection.HANDSHAKE = (Handshake)Enum.Parse(typeof(Handshake), dr["handshake"].ToString(), true);
TPumpSerialPort = new SerialPort(TPumpConnection.PORT, TPumpConnection.BAUD_RATE, TPumpConnection.PARITY, TPumpConnection.DATA_BITS, TPumpConnection.STOP_BITS);
TPumpSerialPort.Handshake = TPumpConnection.HANDSHAKE;
TPumpSerialPort.Open();
TPumpSerialPort.NewLine = "\r";
TPumpSerialPort.ReadTimeout = 10000;
TPumpSerialPort.WriteTimeout = 10000;
if (TPumpSerialPort.IsOpen != true)
return false;
return true;
}
catch { return false; }
}
And here is my re-connection function:
public bool reconnectTurboPump(int attempts = 3)
{
try
{
if (TPumpSerialPort != null && TPumpSerialPort.IsOpen == true)
{
TPumpSerialPort.Close();
TPumpSerialPort.Dispose();
}
int i = 1;
while (true)
{
Log(string.Format("Reconnecting Turbo Pump attempt {0}", i));
if (connectTurboPump())
break;
if (i == attempts)
return false;
i++;
}
return true;
}
catch (Exception ex)
{
Log(string.Format("Could not reconnect to Turbo Pump: {0}", ex.Message));
return false;
}
}
Would really appreciate if someone could help.
Thank you.
This doesn't make much sense if this is a true serial port connection. There is no "connected" state, serial ports are very simple devices that have no underlying protocol that establishes a connection.
If this is actually a USB device that emulates a serial port then you'll indeed have this kind of problem. The driver that emulates the serial port invariably gets very sulky when you unplug the USB connector while the port is in use. There actually is a connection protocol for USB devices, the negotiation is done by the driver. They most typically make the port just disappear, this tends to give user code a heart-attack from which it can't recover. Behavior is very unpredictable and varies from one driver to another. There is no cure for this, glue the connector to the port and never assume that unplugging it will solve any problems in your code, even though that's the only thing you can do with USB.
Following Thomas' advice I've changed reconnection script to the following. Now in testing.
public bool reconnectTurboPump(int attempts = 3)
{
try
{
//if (TPumpSerialPort != null && TPumpSerialPort.IsOpen == true)
if (TPumpSerialPort != null)
{
TPumpSerialPort.Close();
TPumpSerialPort.Dispose();
}
int i = 1;
while (true)
{
Log(string.Format("Reconnecting Turbo Pump attempt {0}", i));
Thread.Sleep(2000);
if (connectTurboPump())
break;
if (i == attempts)
return false;
i++;
}
return true;
}
catch (Exception ex)
{
Log(string.Format("Could not reconnect to Turbo Pump: {0}", ex.Message));
return false;
}
}
I have a command-line process I would like to automate and capture in C#.
At the command line, I type:
nslookup
This launches a shell which gives me a > prompt. At the prompt, I then type:
ls -a mydomain.local
This returns a list of local CNAMEs from my primary DNS server and the physical machines they are attached to.
What I would like to do is automate this process from C#. If this were a simple command, I would just use Process.StartInfo.RedirectStandardOutput = true, but the requirement of a second step is tripping me up.
ProcessStartInfo si = new ProcessStartInfo("nslookup");
si.RedirectStandardInput = true;
si.RedirectStandardOutput = true;
Process nslookup = new Process(si);
nslookup.Start();
nslookup.StandardInput.WriteLine("ls -a mydomain.local");
nslookup.StandardInput.Flush();
// use nslookup.StandardOutput stream to read the result.
Not what you asked, but I once wrote an app that did what you're doing. I eventually moved to using a .NET library to do the DNS lookups, which turned out to be a lot faster.
I'm pretty sure I used this library from the CodeProject site.
I know this is an old one, but still like to contribute.
I used the shell output from "NsLookup Hostname Server" to get the IPv4 addresses from a computername in our domain and strip out any other information like DNS server / ipv6 addresses..
This is kinda quickly done but it works, there is also a failover added if the shell fails that you would use the built in nslookup method from C#.
it is rather long but it gave me the possibility to read the ipv4 from the shell without using an external library or without using the built in nslookup function as it does allow to choose the dns server.
If you are wondering about the if loops in the middle, there might be more elegant solutions but for my personal use, this worked out quite well, most hosts in our domain returned 2 ipv6 and 2 ipv4, therefore, it test up to 4 times.
Hope this can help..
private void button1_Click(object sender, EventArgs e)
{
IPAddress[] ips = NsLookup(computername, dnsserver);
txtResult.Text = string.Empty;
if (ips != null)
{
txtResult.Text = ips[0].ToString();
txtResult.Text += Environment.NewLine;
if (ips[1] != null)
{
txtResult.Text += ips[1].ToString();
}
else
{
}
}
else
{
txtResult.Text = "No IP found";
}
}
public IPAddress[] NsLookup(string computername, string domaincontroller)
{
IPAddress[] ips = new IPAddress[2];
try
{
// Creating streamreaders to read the output and the errors
StreamReader outputReader = null;
StreamReader errorReader = null;
string nslookup = #"C:\Windows\System32\Nslookup.exe";
try
{
// Setting process startupinfo
ProcessStartInfo processStartInfo = new ProcessStartInfo(nslookup, computername + " " + domaincontroller);
processStartInfo.ErrorDialog = false;
processStartInfo.UseShellExecute = false;
processStartInfo.RedirectStandardError = true;
processStartInfo.RedirectStandardInput = true;
processStartInfo.RedirectStandardOutput = true;
processStartInfo.WindowStyle = ProcessWindowStyle.Minimized;
// Starting Process
Process process = new Process();
process.StartInfo = processStartInfo;
bool processStarted = process.Start();
if (processStarted)
{
// Catching the output streams
outputReader = process.StandardOutput;
errorReader = process.StandardError;
string errorresult = errorReader.ReadLine();
errorReader.Close();
if (errorresult != null)
{
// Failure got thrown in NsLookup Streamreading, try build-in Method
try
{
ips = Dns.GetHostAddresses(computername);
return ips;
}
catch
{
return null;
}
}
else
{
// Clearing out all the values before the addresses.
outputReader.ReadLine();
outputReader.ReadLine();
outputReader.ReadLine();
outputReader.ReadLine();
// Reading and Verifying the first outputline (the address is found after "Addresses: ") - 2 part of the array is taken (after second space)
string outputline = outputReader.ReadLine();
string[] outputlineaftersplit = outputline.Split(' ');
string ipfortesting = outputlineaftersplit[2].Trim();
if (verifyIP(ipfortesting) != null) // First entry is ipv4
{
ips[0] = verifyIP(ipfortesting);
outputline = outputReader.ReadLine();
ipfortesting = outputline.Trim();
if (verifyIP(ipfortesting) != null) // First and second entry are ipv4
{
ips[1] = verifyIP(ipfortesting);
return ips;
}
else
{
return ips;
}
}
else
{
outputline = outputReader.ReadLine();
ipfortesting = outputline.Trim();
if (verifyIP(ipfortesting) != null)
{
ips[0] = verifyIP(ipfortesting);
outputline = outputReader.ReadLine();
ipfortesting = outputline.Trim();
if (verifyIP(ipfortesting) != null)
{
ips[0] = verifyIP(ipfortesting);
outputline = outputReader.ReadLine();
ipfortesting = outputline.Trim();
if (verifyIP(ipfortesting) != null)
{
ips[1] = verifyIP(ipfortesting);
return ips;
}
else
{
return ips;
}
}
else
{
return ips;
}
}
else
{
outputline = outputReader.ReadLine();
ipfortesting = outputline.Trim();
if (verifyIP(ipfortesting) != null)
{
ips[0] = verifyIP(ipfortesting);
outputline = outputReader.ReadToEnd();
ipfortesting = outputline.Trim();
if (verifyIP(ipfortesting) != null)
{
ips[1] = verifyIP(ipfortesting);
return ips;
}
else
{
return ips;
}
}
else
{
ips = null;
return ips;
}
}
}
}
}
else
{
// Failure got thrown in NsLookup Streamreading, try build-in Method
try
{
ips = Dns.GetHostAddresses(computername);
return ips;
}
catch
{
return null;
}
}
}
catch
{
System.Windows.Forms.MessageBox.Show("ERROR 1");
// Failure got thrown in NsLookup Streamreading, try build-in Method
try
{
ips = Dns.GetHostAddresses(computername);
return ips;
}
catch
{
return null;
}
}
finally
{
if (outputReader != null)
{
outputReader.Close();
}
}
}
catch
{
System.Windows.Forms.MessageBox.Show("ERROR 2");
// Failure got thrown in NsLookup Streamreading, try build-in Method
try
{
ips = Dns.GetHostAddresses(computername);
return ips;
}
catch
{
return null;
}
}
}
public IPAddress verifyIP(string ipfromreader)
{
IPAddress ipresult = null;
bool isIP = IPAddress.TryParse(ipfromreader, out ipresult);
if (isIP && (ipresult.AddressFamily != AddressFamily.InterNetworkV6))
{
return ipresult;
}
else
{
return null;
}
}
}
}