Я создал приложение С#, которое считывает и записывает данные из последовательного порта. Устройство, подключенное к последовательному порту, представляет собой преобразователь FTDI USB в последовательный преобразователь, который передает аппаратное обеспечение через беспроводной модуль XBee. Аппарат проверяет аккумуляторные модули на мощность и постоянное напряжение и т.д. Эти испытания занимают несколько дней.
Кажется, что последовательный порт перестает отвечать на запросы и выдает System.IO.IOException: устройство, подключенное к системе, не работает.
Вот трассировка стека:
at system.IO.Ports.InternalResources.WinIOError
at system.IO.Ports.SerialStream.EndWrite
at system.IO.Ports.SerialStream.Write
at system.IO.Ports.SerialPort.Write
at BatteryCharger.CommunicationClass.ApiTransmission
после возникновения этой ошибки возникает ошибка System.UnauthorizedAccessException: Access to the port is denied
, и эта ошибка возникает каждый раз, когда программное обеспечение пытается записать в порт, и оно никогда не восстанавливается, пока я не прекращу отладку и не перезагружу программное обеспечение только для того, дней спустя.
Как предотвратить эту ошибку или существует способ успешно восстановить эти ошибки в выводе ошибки ошибки?
Я постоянно читаю последовательный порт в фоновом рабочем потоке и пишу из другого потока.
Я также уже пробовал все предыдущие биты обработки ошибок, которые были предложены на этом форуме, но ни один из них, похоже, не имеет никакого значения. Ошибка возникает на Windows XP Pro SP3 32bit и Windows7 Pro 32bit.
Здесь приведен код обмена данными CommunicationClass.cs.
public static bool ApiTransmission(TXpacket transmission)
{
//clear all previous data that may have been in the buffer before doing a transmission
Variables.dataParserPacket_buff.Clear();
//TXpacket xbeetransmision = new TXpacket();
byte[] packet = transmission.GeneratePacket();
try
{
if (_serialPort.IsOpen)
{
#if Console
Log.write("TX-Packet: " + StringHandler.listToString(packet.ToList<byte>()));
#endif
_serialPort.Write(packet, 0, packet.Length);
Thread.Sleep(100);
}
else
{
#if Console
Log.write("serial port is closed");
#endif
return false;
}
}
catch (UnauthorizedAccessException ex)
{
MessageBox.Show(ex.ToString());
Log.write("UnauthorizedAccessException");
}
catch (IOException ex)
{
MessageBox.Show(ex.ToString());
Log.write("IOexception");
//_serialPort.Close();
//Thread.Sleep(100);
//_serialPort.Open();
}
catch (Exception ex)
{
MessageBox.Show(ex.ToString());
#if Console
Log.write(ex.ToString());
#endif
}
return true;
}
Вот как я инициализирую свой последовательный порт
public CommunicationClass(string portName, int baudRate, Parity parity, int dataBits, StopBits stopBits)
{
_analysePacketBGW.DoWork += new DoWorkEventHandler(_analysePacketBGW_DoWork);
_analysePacketBGW.WorkerReportsProgress = true;
_analysePacketBGW.WorkerSupportsCancellation = true;
_readBGW.DoWork += new DoWorkEventHandler(_readThread_DoWork);
_readBGW.WorkerSupportsCancellation = true;
_readBGW.WorkerReportsProgress = true;
_parserStarterBGW.DoWork += new DoWorkEventHandler(_parserStarterThread_DoWork);
_parserStarterBGW.WorkerSupportsCancellation = true;
_parserStarterBGW.WorkerReportsProgress = true;
if (_readBGW != null)
{
_readBGW.CancelAsync();
}
_serialPort = new SerialPort(portName, baudRate, parity, dataBits, stopBits);
//SerialPortFixer.Execute(portName);
//Thread.Sleep(1000);
//using (_serialPort = new SerialPort(portName, baudRate, parity, dataBits, stopBits))
//{
// //_serialPort.Open();
//}
_serialPort.ErrorReceived += new SerialErrorReceivedEventHandler(_serialPort_ErrorReceived);
_dataqueuepp = new ManualResetEvent(false);
_serialPort.Open();
_readBGW.RunWorkerAsync();
_parserStarterBGW.RunWorkerAsync();
CommunicationClass.PacketReceived += new DataPacketReceived(CommunicationClass_PacketReceived);
}
И фоновый рабочий, который обрабатывает чтение последовательного порта
void _readThread_DoWork(object sender, DoWorkEventArgs e)
{
#if Console
Log.write("Read()");
#endif
while (!_readBGW.CancellationPending)
{
try
{
int message = _serialPort.ReadByte();
try
{
Variables.dataQueue.Enqueue(message);
}
catch (Exception ex)
{
MessageBox.Show(ex.Message + " " + message.ToString());
}
_dataqueuepp.Set();
//Console.Write(String.Format("{0:X2}", message) + " ");
}
catch (TimeoutException) { Log.write("read timeout"); }
catch (IOException) { Log.write("read IOException"); }
catch (ThreadAbortException) { Log.write("read thread aborted"); }
catch (Exception ex) { MessageBox.Show(ex.ToString()); }
finally { }
}
}
Теперь я переписал код для чтения и записи в/из последовательного порта из того же потока, чтобы убедиться, что это имеет значение.
ИЗМЕНИТЬ
Основываясь на комментариях Джима, я добавил следующее в инструкцию IOException Catch:
catch (IOException ex)
{
MessageBox.Show(ex.ToString());
Log.write("IOexception");
_readBGW.CancelAsync();
Thread.Sleep(100);
_serialPort.Close();
Thread.Sleep(100);
_serialPort.Open();
Thread.Sleep(100);
_readBGW.RunWorkerAsync();
_serialPort.Write(packet, 0, packet.Length);
}
Будем надеяться, остановив фонового рабочего _serialPort.Read, закрыв порт, снова открыв порт, снова запустив рабочего фона и попытавшись написать ту же команду снова, чтобы успешно восстановить эту ошибку. MessageBox по-прежнему блокирует код, чтобы я мог видеть, когда возникает ошибка, и может контролировать, как он восстанавливается.
Мне не нравится такое программное обеспечение для исправления, но если оно работает, то оно работает.
РЕДАКТИРОВАТЬ 2
После добавления кода выше мое программное обеспечение снова сработало, но теперь оно выбрасывает "UnauthorizedAccessException - доступ к порту отрицается", когда я вызываю _serialPort.Close();
System.UnauthorizedAccessException was unhandled
Message=Access to the port is denied.
Source=System
StackTrace:
at System.IO.Ports.InternalResources.WinIOError(Int32 errorCode, String str)
at System.IO.Ports.InternalResources.WinIOError()
at System.IO.Ports.SerialStream.Dispose(Boolean disposing)
at System.IO.Stream.Close()
at System.IO.Ports.SerialPort.Dispose(Boolean disposing)
at System.IO.Ports.SerialPort.Close()
at BatteryCharger.CommunicationClass.ApiTransmission(TXpacket transmission) in E:\Mijn Documenten\Research\Copy of BatteryCharger_V12\BatteryCharger\CommunicationClass.cs:line 436
at BatteryCharger.CommunicationClass.tx1(TXpacket packet, String callingMethod) in E:\Mijn Documenten\Research\Copy of BatteryCharger_V12\BatteryCharger\CommunicationClass.cs:line 356
at BatteryCharger.XBee.setPin(String pinID, Byte status, XBee slave) in E:\Mijn Documenten\Research\Copy of BatteryCharger_V12\BatteryCharger\XBee.cs:line 215
at BatteryCharger.XBee.setPins(Int32 pins, XBee slave) in E:\Mijn Documenten\Research\Copy of BatteryCharger_V12\BatteryCharger\XBee.cs:line 177
at BatteryCharger.BatteryCharger.requestVoltage(Int32 block) in E:\Mijn Documenten\Research\Copy of BatteryCharger_V12\BatteryCharger\BatteryCharger.cs:line 595
at BatteryCharger.BatteryCharger.requestVoltages() in E:\Mijn Documenten\Research\Copy of BatteryCharger_V12\BatteryCharger\BatteryCharger.cs:line 612
at BatteryCharger.Form1.RunCommandOn(List`1 battList, Int32 command, Double lowerLimit, Double upperLimit) in E:\Mijn Documenten\Research\Copy of BatteryCharger_V12\BatteryCharger\Form1.cs:line 522
at BatteryCharger.Form1.chargeBlock(Int32 blockNr, Double lowerLimit, Double upperLimit) in E:\Mijn Documenten\Research\Copy of BatteryCharger_V12\BatteryCharger\Form1.cs:line 689
at BatteryCharger.Form1.<btnCheckCapacities_Click>b__13() in E:\Mijn Documenten\Research\Copy of BatteryCharger_V12\BatteryCharger\Form1.cs:line 619
at System.Threading.ThreadHelper.ThreadStart_Context(Object state)
at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean ignoreSyncCtx)
at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state)
at System.Threading.ThreadHelper.ThreadStart()
InnerException:
Что здесь происходит?