Sniffing TCP packets of an android device on local network - c#

I am writing a packet sniffer using C# and PcapDotNet, I've successfully implemented the feature and I was able to capture all the TCP packets from my laptop, the problem is if I target my android device I get no packets at all,
I am a beginner at networking, so I think I am probably missing something.
This is my code for the packet handler, I am using an ObjectListView with a model object that contains all the information I want to list, also I have the network adapter in Promiscuous mode with a Berkeley filter to get only TCP packets with port numbers 443 and 80 that contains data (No SYN, FIN, ACK-only packets) from a specific Mac address
Code:
private void PacketHandler(PcapDotNet.Packets.Packet packet)
{
if (packet == null) { return; }
if (packet.Ethernet == null) { return; }
if (packet.Ethernet.IpV4 == null) { return; }
if (packet.Ethernet.IpV4.Tcp == null) { return; }
if (packet.Ethernet.IpV4.Tcp.Http == null) { return; }
var acpacket = new AcceptedPacket(); //Model Object
acpacket.Packet = packet;
try
{
HttpDatagram http = packet.Ethernet.IpV4.Tcp.Http;
if (packet.Ethernet.Source.ToString() == targetmac)
{
if (http.IsRequest && http.IsValid)
{
if (materialListView1.InvokeRequired)
{
materialListView1.BeginInvoke(new Action(() => {
materialListView1.AddObject(acpacket); }));
}
else
{
materialListView1.AddObject(acpacket);
}
ListofAcceptedPackets.Add(acpacket);
}
}
}
catch (Exception ex)
{
MetroMessageBox.Show(this, ex.Message, "Error",
MessageBoxButtons.OK,
MessageBoxIcon.Error);
}
}
And this how I opened the adapter :
using (communicator =
selectedDevice.Open(65536,PacketDeviceOpenAttributes.Promiscuous,
1000))
{
if (communicator.DataLink.Kind !=
DataLinkKind.Ethernet)
{
if (MetroMessageBox.Show(this, "Only Ethernet is supported in this operation!","Error", MessageBoxButtons.OK,MessageBoxIcon.Error) == DialogResult.OK)
{
return;
}
}
using (BerkeleyPacketFilter filter = communicator.CreateFilter($"tcp port 80 and (((ip[2:2] - ((ip[0]&0xf)<<2)) - ((tcp[12]&0xf0)>>2)) != 0) and ether src {targetmac.ToLower()} or tcp port 443 and (((ip[2:2] - ((ip[0]&0xf)<<2)) - ((tcp[12]&0xf0)>>2)) != 0) and ether src {targetmac.ToLower()}"))
{
communicator.SetFilter(filter);
}
flag = true;
Packet packet;
do
{
PacketCommunicatorReceiveResult result =
communicator.ReceivePacket(out packet);
switch (result)
{
case
PacketCommunicatorReceiveResult.Timeout:
continue;
case
PacketCommunicatorReceiveResult.Ok:
{
PacketHandler(packet);
}
break;
default:
break;
}
} while (flag);
}
I also tried without any filter and couldn't reach the android device packets.
so is it possible to capture TCP packets from other devices on the network besides my own device? or maybe there's something wrong with my implementation?
Edit: after trying a bit more I was able to successfully get the TCP packets from the android device but only while implementing ARP Cache Poisoning at the same time because the device thinks that I am the gateway. so my question stands, can this be done without ARP Cache Poisoning because I think it's a bit aggressive for a packet sniffer.

I was finally able to make it work by applying ARP cache poisoning while the code below is able to redirect packets for any device to their destination, this way you get to capture packets for any device on the network specifically without losing internet access for this device.
Code:
private void StartSniffer()
{
RawCapture rawCapture;
do
{
if ((rawCapture = capturedevice.GetNextPacket()) != null)
{
EthernetPacket Packet = PacketDotNet.Packet.ParsePacket(rawCapture.LinkLayerType, rawCapture.Data) as EthernetPacket;
if (Packet == null) { return; }
AcceptedPacket acPacket = new AcceptedPacket();
acPacket.Packet = Packet;
if (Packet.SourceHwAddress.Equals(TargetMAC))
{
Packet.SourceHwAddress = capturedevice.MacAddress;
Packet.DestinationHwAddress = GatewayMAC;
capturedevice.SendPacket(Packet);
if (acPacket.TCPPacket != null &&
((acPacket.Type.Equals("HTTPS") && acPacket.TCPPacket.PayloadData != null) ||
(acPacket.Type.Equals("HTTP") && acPacket.TCPPacket.PayloadData != null)))
{
materialListView1.BeginInvoke(new Action(() =>
{
materialListView1.AddObject(acPacket);
if (materialListView1.Items.Count > 15 && !ResizeDone)
{
olvColumn8.MaximumWidth = 65;
olvColumn8.MinimumWidth = 65;
olvColumn8.Width = 65;
ResizeDone = true;
}
ListofAcceptedPackets.Add(acPacket);
}));
}
}
else if (Packet.SourceHwAddress.Equals(GatewayMAC))
{
IPv4Packet IPV4 = Packet.Extract(typeof(IPv4Packet)) as IPv4Packet;
if (IPV4.DestinationAddress.Equals(Target))
{
Packet.SourceHwAddress = capturedevice.MacAddress;
Packet.DestinationHwAddress = TargetMAC;
capturedevice.SendPacket(Packet);
}
if (Properties.Settings.Default.PacketDirection == "Inbound")
{
if (acPacket.TCPPacket != null &&
((acPacket.Type.Equals("HTTPS") && acPacket.TCPPacket.PayloadData != null) ||
(acPacket.Type.Equals("HTTP") && acPacket.TCPPacket.PayloadData != null)))
{
materialListView1.BeginInvoke(new Action(() =>
{
materialListView1.AddObject(acPacket);
if (materialListView1.Items.Count > 15 && !ResizeDone)
{
olvColumn8.MaximumWidth = 65;
olvColumn8.MinimumWidth = 65;
olvColumn8.Width = 65;
ResizeDone = true;
}
ListofAcceptedPackets.Add(acPacket);
}));
}
}
}
}
} while (snifferStarted);
And this is the capture device setup:
try
{
snifferStarted = true;
if (capturedevice != null)
{
capturedevice.Open(DeviceMode.Promiscuous, 1000);
capturedevice.Filter = $"(ip and ether src {targetmac.ToLower()}) or (ip and ether src {gatewayMAC.ToLower()} and dst net {Target})";
new Thread(() => { StartSniffer(); }).Start();
}
else
{
MetroMessageBox.Show(this, "No Capture Device is selected!", "Error", MessageBoxButtons.OK,
MessageBoxIcon.Error);
}
}
catch (Exception exception)
{
MetroMessageBox.Show(this, exception.Message, "Error", MessageBoxButtons.OK,
MessageBoxIcon.Error);
}
Note: this has been done using Packet.Net NOT PcapDotNet.

Related

TCP connections stuck with CLOSE_WAIT state

I need your help guys in order to fix issue with non closing TCP connection.
Basically it works fine but after a few minutes it stucks with connection in CLOSE_WAIT state.
The logic of the code:
The code accepts first packet and parse it and after that it sends the CRC back to the client. If the CRC valid then client sends the main packet to the server and repeat it. Once if there are no packets then client close connection but sometimes it does not. In this case server (code below) close connection after 1 minute of the communications.
I assume it should correspond to https://www.googlecloudcommunity.com/gc/Cloud-Product-Articles/TCP-states-explained/ta-p/78462 as well
Here is C# code
void TCPListenerServer(object obj) {
CancellationToken token = (CancellationToken) obj;
if (token.IsCancellationRequested) {
isDisposed = true;
if (listener != null) {
listener.Stop();
}
return;
} else {
try {
isDisposed = false;
try {
var validIP = IPAddress.Parse(Properties.Settings.Default.ServerIP);
listener = new TcpListener(validIP, Properties.Settings.Default.ServerPort);
listener.Start();
while (isDisposed == false || token.IsCancellationRequested == false) {
if (token.IsCancellationRequested || isDisposed) {
break;
} else {
if (!listener.Pending()) {
Thread.Sleep(50);
continue;
}
listener.Server.ReceiveTimeout = 10000;
listener.Server.LingerState = new LingerOption(true, 0);
var client = listener.AcceptTcpClient();
var arrThread = new ThreadParams() {
Client = client, Token = m_Cts.Token
};
var t = new Thread(ProcessClientRequests) {
IsBackground = true,
Name = "ClientConnectionThread",
};
clientThreads.Add(t);
t.Start((object) arrThread);
}
}
} catch (SocketException ex) {
if (ex.SocketErrorCode == SocketError.Interrupted) {}
} catch (Exception ex) {} finally {
if (listener != null) {
listener.Server.Close();
listener.Stop();
}
}
} catch (Exception ex) {
}
}
}
private void ProcessClientRequests(object argument) {
TcpClient client = ((ThreadParams) argument).Client;
CancellationToken token = ((ThreadParams) argument).Token;
client.SendTimeout = 10000;
client.ReceiveTimeout = 10000;
client.LingerState = new LingerOption(true, 0);
var bufferSize = 1024;
byte[] buffer = new byte[bufferSize];
var isFirstPacket = true;
var startTime = DateTime.Now;
DateTime endTime = DateTime.Now;
try {
using(NetworkStream stream = client.GetStream()) {
do {
Thread.Sleep(20);
} while (!stream.DataAvailable);
while ((client != null && client.Connected) && stream != null && stream.CanRead && (endTime - startTime).TotalMinutes < 1) {
if (client == null) {
break;
}
do {
if (token.IsCancellationRequested) {
return;
}
if (client == null) {
break;
}
endTime = DateTime.Now;
int streamReadBytes = 0;
streamReadBytes = stream.Read(buffer, 0, buffer.Length);
if (streamReadBytes == 0) {
if (client != null) {
client.Close();
}
break;
}
if (buffer[0] == (byte) GalileoskyPacketHeaderEnums.FirstPacket || buffer[0] == (byte) GalileoskyPacketHeaderEnums.MainPacket) {
var parserGalileosky = new Galileosky();
var packetResult = parserGalileosky.ParsePacket(buffer, isFirstPacket);
if (packetResult == null) {
if (client != null) {
client.Close();
client = null;
}
break;
}
if (packetResult.Errors.Any()) {
if (client != null) {
client.Close();
client = null;
}
} else {
var imei = packetResult.Packet.IMEI;
if (isFirstPacket) {
isFirstPacket = false;
if (stream.CanWrite == true && packetResult.Packet.IsCrc) {
var answerPacket = packetResult.Packet.GetConfirmPacket();
stream.Write(answerPacket.Ready);
} else {
if (client != null) {
client.Close();
client = null;
}
}
} else // The Main Packet processing
{
// ... Some code to send the main packet to the app queue
if (stream.CanWrite == true && !packetResult.Errors.Any() && packetResult.Packet.IsCrc) {
var answerPacket = packetResult.Packet.GetConfirmPacket();
stream.Write(answerPacket.Ready);
}
if (packetResult.Packet.IsExtraData == false) {
if (client != null) {
client.Close();
client = null;
break;
}
}
}
}
} else {
if (client != null) {
client.Close();
client = null;
}
}
if ((endTime - startTime).TotalMinutes > 1) {
if (client != null) {
client.Close();
client = null;
break;
}
}
}
while ((client != null && client.Connected) && stream != null && stream.CanRead && stream.DataAvailable && (endTime - startTime).TotalMinutes < 1);
}
}
if (client != null) {
client.Close();
client = null;
}
} catch (Exception ex) {} finally {
if (client != null) {
client.Close();
client = null;
}
}
}
Even if your code is correct, you can hit the "2 generals" problem. There is no perfect algorithm for two parties to agree that a connection is closed, when there may be packet loss.
Gracefully closing a TCP stream requires both parties to shutdown sending, read data up to EOF, then close. I believe that you'll see a socket in CLOSE_WAIT, if one party has shutdown the connection, but the other has not. It looks like you have set your sockets to linger. In which case the operating system will take over the lifetime of the socket for you.
If your socket is not set to linger, then closing the socket early will cause data that you think you've sent to be lost.
I should also point out that your code is drastically over complicated, with error handling repeated everywhere. It looks like it was probably written before C# introduced async / await.
It also seems that you are assuming that one read operation equates to one data packet. But this is a TCP stream. The OS is allowed to fragment and recombine data that was written from one end, into any number of data reads at the other.
I'd suggest you search the internet for an example that uses .AcceptTcpClientAsync, .ReadAsync, .WriteAsync etc.
Finally I could'n find a way to solve problem to close connection within my code.
But I added a timer that close connection and it works just awesome!
private void ProcessClientRequests(object argument)
// ... The same code of my quetion
Timer timerCloseConn = new(new TimerCallback((e) =>
{
if (stream != null)
{
stream.Close();
stream.Dispose();
}
if (client != null)
{
if (client.Client.Connected)
{
client.Client.Shutdown(SocketShutdown.Both);
}
client.Close();
client.Dispose();
client = null;
}
Logger.Info("The connection has been closed by
timer's rule!");
}), null, 60000, Timeout.Infinite);
// ... The same code of my quetion
}

Image from Camera Preview using Customer Renderer is not clear

I've followed this article and implemented a Customer Renderer that's used to display a preview video stream from the device's camera.
I intend to capture a frame from the live stream and feed it into Tesseract OCR in order to read a number printed on a ticket.
My problem is that the image from camera preview is almost always not focused. So it is useless for its intended purpose.
An identical question has been asked years ago here in SO, but the accepted answer is not at all helpful for me.
This is the code of OnElementChanged event of CameraPreviewRenderer:
void OnElementChanged(ElementChangedEventArgs<CameraPreview> e)
{
CameraFragment newFragment = null;
if (e.OldElement != null)
{
e.OldElement.PropertyChanged -= OnElementPropertyChanged;
cameraFragment.Dispose();
}
if (e.NewElement != null)
{
this.EnsureId();
e.NewElement.PropertyChanged += OnElementPropertyChanged;
ElevationHelper.SetElevation(this, e.NewElement);
newFragment = new CameraFragment { Element = element };
}
FragmentManager.BeginTransaction()
.Replace(Id, cameraFragment = newFragment, "camera")
.Commit();
ElementChanged?.Invoke(this, new VisualElementChangedEventArgs(e.OldElement, e.NewElement));
}
This is a piece from class CameraFragment. Method RetrieveCameraDevice is the one that opens the camera (I think).
class CameraFragment : Fragment, TextureView.ISurfaceTextureListener
{
CameraDevice device;
CaptureRequest.Builder sessionBuilder;
CameraCaptureSession session;
CameraTemplate cameraTemplate;
CameraManager manager;
....
public async Task RetrieveCameraDevice(bool force = false)
{
if (Context == null || (!force && initTaskSource != null))
{
return;
}
if (device != null)
{
CloseDevice();
}
await RequestCameraPermissions();
if (!cameraPermissionsGranted)
{
return;
}
if (!captureSessionOpenCloseLock.TryAcquire(2500, TimeUnit.Milliseconds))
{
throw new RuntimeException("Timeout waiting to lock camera opening.");
}
IsBusy = true;
cameraId = GetCameraId();
if (string.IsNullOrEmpty(cameraId))
{
IsBusy = false;
captureSessionOpenCloseLock.Release();
Console.WriteLine("No camera found");
}
else
{
try
{
CameraCharacteristics characteristics = Manager.GetCameraCharacteristics(cameraId);
StreamConfigurationMap map = (StreamConfigurationMap)characteristics.Get(CameraCharacteristics.ScalerStreamConfigurationMap);
previewSize = ChooseOptimalSize(map.GetOutputSizes(Class.FromType(typeof(SurfaceTexture))),
texture.Width, texture.Height, GetMaxSize(map.GetOutputSizes((int)ImageFormatType.Jpeg)));
sensorOrientation = (int)characteristics.Get(CameraCharacteristics.SensorOrientation);
cameraType = (LensFacing)(int)characteristics.Get(CameraCharacteristics.LensFacing);
if (Resources.Configuration.Orientation == Android.Content.Res.Orientation.Landscape)
{
texture.SetAspectRatio(previewSize.Width, previewSize.Height);
}
else
{
texture.SetAspectRatio(previewSize.Height, previewSize.Width);
}
initTaskSource = new TaskCompletionSource<CameraDevice>();
Manager.OpenCamera(cameraId, new CameraStateListener
{
OnOpenedAction = device => initTaskSource?.TrySetResult(device),
OnDisconnectedAction = device =>
{
initTaskSource?.TrySetResult(null);
CloseDevice(device);
},
OnErrorAction = (device, error) =>
{
initTaskSource?.TrySetResult(device);
Console.WriteLine($"Camera device error: {error}");
CloseDevice(device);
},
OnClosedAction = device =>
{
initTaskSource?.TrySetResult(null);
CloseDevice(device);
}
}, backgroundHandler);
captureSessionOpenCloseLock.Release();
device = await initTaskSource.Task;
initTaskSource = null;
if (device != null)
{
await PrepareSession();
}
}
catch (Java.Lang.Exception ex)
{
Console.WriteLine("Failed to open camera.", ex);
Available = false;
}
finally
{
IsBusy = false;
}
}
}
I'm supposed to setup the "Focus Mode" in the Camera properties somewhere in this code. But I can't figure out a way to do this.

Task ends when getting GattService [C# UWP]

Using: Windows 10, C# .NET 2015 Community, UWP
Im trying to build a windows-universal-app that pairs my PC with a BLE device.
Whats already working is enumerating nearby devices, pair with a selected one and getting information like battery-level and firmware-revision.
The problem now is that when I try to get a custom service, my task ends because of an "System.Exception" at .GetGattService
System.Exception.Message: "Element not found. (Exception from HRESULT: 0x80070490)"
System.Exception.Stack : "at Windows.Devices.Bluetooth.BluetoothLEDevice.GetGattService(Guid serviceUuid)\r\n at SettingsCs.Settings.d__23.MoveNext()"
This is the code that's not working:
private async Task<SettingsReturn> writeSettingTransition(BluetoothLEDevice device, byte[] byteSettings)
{
//Check if device is available
if (device != null)
{
Guid SERVICE_CUSTOM = new Guid("7e0bc6be-8271-4f5a-a126-c24220e6250c");
GattDeviceService service = device.GetGattService(SERVICE_CUSTOM);
//Check if service is available
if (service == null)
{
return SettingsReturn.INIT_ERROR;
}
GattCharacteristic characteristic = service.GetCharacteristics(BLETestApp.CHAR_SETTINGS)[0];
//Check if characteristic is available
if (characteristic == null)
{
return SettingsReturn.INIT_ERROR;
}
var writer = new DataWriter();
writer.WriteBytes(byteSettings);
var buffer = writer.DetachBuffer();
await characteristic.WriteValueAsync(buffer);//********
bool success = characteristic.CharacteristicProperties.HasFlag(GattCharacteristicProperties.Write);
if (success == true)
{
// Take care of the 8 bit byte for the counter (max = 255 (unsigned))
if (TRANSACTION_ID > 250)
{
TRANSACTION_ID = 0;
}
else
{
// Count TANSACTION_ID one up
TRANSACTION_ID++;
}
return SettingsReturn.OK;
}
else
{
return SettingsReturn.WRITE_ERROR;
}
}
else
{
return SettingsReturn.INIT_ERROR;
}
}
I hope somenone can help me or tell me what I'm doing wrong.
I can't pinpoint the error you get, use the debugger to check if your characteristic has write permission.
I have changed your code in a way I write to my device successfully.
Also added a try catch block.
Here it is:
private async Task<SettingsReturn> writeSettingTransition(BluetoothLEDevice device, byte[] byteSettings)
{
bool success = false;
//Check if device is available
if (device != null)
{
Guid SERVICE_CUSTOM = new Guid("7e0bc6be-8271-4f5a-a126-c24220e6250c");
GattDeviceService service = device.GetGattService(SERVICE_CUSTOM);
//Check if service is available
if (service == null)
{
return SettingsReturn.INIT_ERROR;
}
GattCharacteristic characteristic = service.GetCharacteristics(BLETestApp.CHAR_SETTINGS)[0];
//Check if characteristic is available
if (characteristic == null)
{
return SettingsReturn.INIT_ERROR;
}
IBuffer writeBuffer = byteSettings.AsBuffer();// using Windows.Storage.Streams
try
{
// BT_Code: Writes the value from the buffer to the characteristic.
var result = await characteristic.WriteValueAsync(writeBuffer);
if (result == GattCommunicationStatus.Success)
{
// NotifyUser("Successfully wrote value to device" );
success = true;
}
else
{
// NotifyUser($"Write failed: {result}");
success = false;
}
}
catch (Exception ex) when ((uint)ex.HResult == 0x80650003 || (uint)ex.HResult == 0x80070005)
{
// E_BLUETOOTH_ATT_WRITE_NOT_PERMITTED or E_ACCESSDENIED
// This usually happens when a device reports that it support writing, but it actually doesn't.
// NotifyUser(ex.Message, NotifyType.ErrorMessage);
}
if (success)
{
// Take care of the 8 bit byte for the counter (max = 255 (unsigned))
if (TRANSACTION_ID > 250)
{
TRANSACTION_ID = 0;
}
else
{
// Count TANSACTION_ID one up
TRANSACTION_ID++;
}
return SettingsReturn.OK;
}
else
{
return SettingsReturn.WRITE_ERROR;
}
}
else
{
return SettingsReturn.INIT_ERROR;
}
}
There can be typos and other mishaps, hope it helps.

Issue with opening and closing serial port

I am currently working on C# application which requires to read serial port. In UI, there is a ON/OFF button which enables user click on it to start and stop reading data from serial port. If I continuously click on the button on and off. It threw an exception - Access to COM3 is denied or even said "The device is not connected". Can anyone suggest a better way to implement the serial port function which is able to resolve the situation as described above? Here is the code I use:
**// Start reading data from serial port**
public override void StartReading(string portname)
{
try
{
int k = int.Parse(portname.Replace("COM", ""));
if (startThread != null)
{
startThread.Abort();
startThread = null;
}
startThread = new Thread(new ThreadStart(delegate
{
isActive = true;
try
{
using (SerialPort sp = new SerialPort(portname))
{
if (!isActive)
{
DisposeBT(sp);
return;
}
sp.DataReceived += new SerialDataReceivedEventHandler(sp_DataReceived);
if (!isActive)
{
DisposeBT(sp);
return;
}
if (!isActive)
{
DisposeBT(sp);
return;
}
else
{
Thread.Sleep(6500);
try
{
if (sp != null && !sp.IsOpen)
{
sp.Open();
}
}
catch (Exception ex)
{
Logger.Warn("Failed to open the serial port for HRM once. Try it again.");
Logger.Error(ex);
////////////////////// new added below
if(sp !=null && sp.IsOpen)
{
sp.Dispose();
}
Thread.Sleep(6500);
if (IsPortAvailable(k))
{
try
{
if (sp != null && !sp.IsOpen)
{
sp.Open();
}
}
catch (Exception ex1)
{
////////////////////// new added below
if (sp != null && sp.IsOpen)
{
sp.Dispose();
}
Logger.Warn("Failed to open the serial for HRM twice.");
Logger.Error(ex1);
// return;
}
}
}
}
while (true)
{
if (!isActive)
{
DisposeBT(sp);
break;
}
}
if (!isActive)
{
DisposeBT(sp);
return;
}
DisposeBT(sp);
}
}
catch (Exception ex)
{
Logger.Warn("Exception thrown for HRM.");
Logger.Error(ex);
}
}));
startThread.IsBackground = true;
startThread.Priority = ThreadPriority.Highest;
startThread.Start();
}
catch (Exception ex)
{
Logger.Warn("Failed to start reading for HRM02I3A1 bluetooth device.");
Logger.Error(ex);
}
}
// Stop reading data from serial port
public override void StopReading()
{
try
{
isActive = false;
}
catch { }
}
// event handler for the serial port to read data from sp.
void sp_DataReceived(object sender, SerialDataReceivedEventArgs e)
{
if (isActive)// && startThread.IsAlive
{
SerialPort sp1 = (SerialPort)sender;
try
{
sp1.Read(data, 0, 8);
decoder.Decode(data);
}
catch(Exception ex)
{
Logger.Warn("------data received from Serial Port error for HRM-------");
Logger.Error(ex);
};
}
}
first make background worker thread that accept the cancel event.
in the DoWork method you can write something like that
void DoWork{
// init com port
while(no body cancelled the background worker){
// if there any waiting data receive and process it. do not use event handlers
}
// close the serial port so you can open it again later.
}
Also if you want to cancel the background work it would be a piece of cake
// send cancel command.
// wait till it is canceled.
Try adding startThread.Join() directly after the call to startThread.Abort().
Take a look at the msdn documentation on Thread.Abort and perhaps you also should check what join does.

Reconnecting to COM after lost connection

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;
}
}

Categories