/// <summary> /// Генерирует событие по изменению статуса порта /// </summary> /// <param name="status">Новое состояние CAN-порта</param> private void OnPortChangesStatus(CanPortStatus status) { EventArgsPortChangesStatus args = new EventArgsPortChangesStatus(status); EventHandlerPortChangesStatus handler = this.PortChangedStatus; if (handler != null) { foreach (EventHandlerPortChangesStatus SingleCast in handler.GetInvocationList()) { ISynchronizeInvoke syncInvoke = SingleCast.Target as ISynchronizeInvoke; if ((syncInvoke != null) && (syncInvoke.InvokeRequired)) { syncInvoke.Invoke(SingleCast, new Object[] { this, args }); } else { SingleCast(this, args); } } } return; }
//-------------------------------------------------------------------------------- /// <summary> /// Конструктор /// </summary> /// <param name="newStatus">Новое состояние CAN-порта</param> public EventArgsPortChangesStatus(CanPortStatus newStatus) { this.Status = newStatus; }
/// <summary> /// Закрывает CAN порт /// </summary> public override void Close() { String msg; // Закрываем поток на чтение Interlocked.Exchange(ref _FlagMustQuit, 0); lock (_SyncRoot) { this._RxEvent.Set(); } for (int i = 0; i < 1; i++) { if (this._ThreadForInput.IsAlive == true) { // Ждём завершение потока Thread.Sleep(500); } else { // Поток завершён break; } } // Если поток не завершился в течнии 10 секунд, значит дело плохо. // Выводим об этом трассировочную информацию if (this._ThreadForInput.IsAlive == true) { this._ThreadForInput.Abort(); msg = String.Format( "{0}: class CanPort.Close(): Рабочий поток не завершился за 0,5 секунду и находится в состоянии {1}", DateTime.Now.ToString(new System.Globalization.CultureInfo("ru-Ru", false)), this._ThreadForInput.ThreadState.ToString()); Trace.TraceError(msg); } //SetMode(CANPORTSTATUS.IsPassive); _CanController.StopLine(); //_CanChannel.Deactivate(); _RxEvent.Close(); _RxEvent = null; // Освобождаем ресурсы DisposeVciObject(_CanBusLayer); DisposeVciObject(_CanChannel); DisposeVciObject(_CanController); DisposeVciObject(_CanDevice); DisposeVciObject(_Reader); DisposeVciObject(_Writer); _CanBusLayer = null; _CanChannel = null; _CanController = null; _CanDevice = null; _Reader = null; _Writer = null; // Устанавливаем флаг признак "порт закрыт" this._PortStatus = CanPortStatus.IsClosed; // Формирум событие OnPortChangesStatus(CanPortStatus.IsClosed); Trace.TraceInformation("{0}: class CanPort.Close(): Порт закрыт", DateTime.Now.ToString(new System.Globalization.CultureInfo("ru-Ru"))); return; }
//-------------------------------------------------------------------------------- #endregion //-------------------------------------------------------------------------------- #region Constructors //-------------------------------------------------------------------------------- /// <summary> /// Конструктор /// </summary> public EventArgsPortChangesStatus() { this.Status = CanPortStatus.Unknown; }
/// <summary> /// Открывает порт /// </summary> public override void Open() { String msg; IVciDeviceList deviceList; String serialNumber; Object pack; if (this._CanDevice == null) { // Получаем список доступных устройств deviceList = GetDeviceList(); // Находим нужное нам устройство и открываем его foreach (IVciDevice item in deviceList) { pack = (Object)item.UniqueHardwareId; serialNumber = GetSerialNumber(ref pack); if (serialNumber == this._SerialNumber) { // Устройство найдено this._CanDevice = item; break; } } } if (this._CanDevice != null) { // Открываем порт Byte numberPort = 0; // Устройство найдено, открываем порт if (this.InitSocket(numberPort, ref this._CanDevice)) { // Порт открыт // Устанавливаем флаг начала опроса порта Interlocked.Exchange(ref _FlagMustQuit, Int32.MaxValue); // start the receive thread _ThreadForInput = new Thread(new ThreadStart(HandleQueueIncomingMessages)); _ThreadForInput.Start(); // Устанавливаем флаг - признак "порт открыт" //_PortStatus = CANPORTSTATUS.IsPassive; // Здесь костыль: Почему-то, инфо-сообщения драйвера о переходе в новый статус при открытии порта не приходят. // Поэтому проверяем в ручную. Если поле _PortStatus не соответсвует текущему состоянию, // то останавливаем принудительно if (this._CanChannel.ChannelStatus.IsActivated) { if (this._PortStatus != CanPortStatus.IsActive) { this._PortStatus = CanPortStatus.IsActive; // Генерируем событие this.OnPortChangesStatus(CanPortStatus.IsActive); } } } else { // Порт не удалось открыть msg = String.Format( "{0}: class CanPort: Невозможно открыть CAN порт. Порт: {1} не удалось открыть.", DateTime.Now.ToString(new System.Globalization.CultureInfo("ru-Ru", false)), this._SerialNumber); Trace.TraceError(msg); throw new InvalidOperationException(msg, null); } } else { // Устройство не найдено msg = String.Format("{0}: class CanPort: Невозможно открыть CAN порт. Порт: {1} не найден", DateTime.Now.ToString(new System.Globalization.CultureInfo("ru-Ru", false)), this._SerialNumber); Trace.TraceError(msg); throw new Exception(msg); //throw new InvalidOperationException(msg, null); } return; }
/// <summary> /// Генерирует событие по изменению статуса порта /// </summary> /// <param name="status">Новое состояние CAN-порта</param> protected virtual void OnPortChangesStatus(CanPortStatus status) { EventArgsPortChangesStatus args = new EventArgsPortChangesStatus(status); EventHandlerPortChangesStatus handler = this.PortChangedStatus; if (handler != null) { foreach (EventHandlerPortChangesStatus SingleCast in handler.GetInvocationList()) { ISynchronizeInvoke syncInvoke = SingleCast.Target as ISynchronizeInvoke; if ((syncInvoke != null) && (syncInvoke.InvokeRequired)) { syncInvoke.Invoke(SingleCast, new Object[] { this, args }); } else { SingleCast(this, args); } } } return; }
/// <summary> /// Функция для приёма данных (запускается в отдельном потоке) /// </summary> private void HandleQueueIncomingMessages() { CanMessage canMessage; Boolean boolResult; Frame message; //Trace.TraceInformation("{0}: class CanPort: Поток на чтение данных запущен", // DateTime.Now.ToString(new System.Globalization.CultureInfo("ru-Ru", false))); //#if DEBUG //WindowsDebugging.WriteLine("Поток на чтение порта запущен", Category.Information); //#endif while(this._FlagMustQuit > 0) { if (_Reader == null) { Trace.WriteLine(""); Trace.TraceError("{0} class CanPort.ReceiveMessages: Невозможно прочитать порт объект _Reader не существует, прекращаю поток чтения", DateTime.Now.ToString(new System.Globalization.CultureInfo("ru-Ru", false))); Interlocked.Exchange(ref this._FlagMustQuit, 0); return; } try { // Ждём пока драйвер can-порта установит сигнальное состоние. // Значит полученны данные в порт boolResult = this._RxEvent.WaitOne(System.Threading.Timeout.Infinite, false); //boolResult = this._RxEvent.WaitOne(100, false); if (boolResult) { // По установке сигнального состояния, проверяем флаг. Возможно // сигнальное состояние было установлено для прекращения работы потока if (this._FlagMustQuit == 0) { continue; } } else { // По таймауту. continue; } // read a CAN message from the receive FIFO //boolResult = true; //while (boolResult) while(this._Reader.ReadMessage(out canMessage)) { //lock (SynckRoot) //{ //if (this._Reader != null) //{ // boolResult = this._Reader.ReadMessage(out canMessage); //} //else //{ // Завершаем поток // this._FlagMustQuit = 0; // this._PortStatus = CANPORTSTATUS.IsClosed; // break; //} //} switch (canMessage.FrameType) { // show data frames case CanMsgFrameType.Data: { //Trace.WriteLine(String.Format("\nTime: {0,10} ID: {1,3:X} DLC: {2,1} Data:", // canMessage.TimeStamp, canMessage.Identifier, canMessage.DataLength)); //Trace.TraceInformation("{0}: class CanPort.ReceiveMessages: TimeStamp: {1,10} ID: {2,3:X} DLC: {3,1} Data:", // DateTime.Now.ToString(new System.Globalization.CultureInfo("ru-Ru", false)), canMessage.TimeStamp, canMessage.Identifier, canMessage.DataLength); message = new Frame(); message.TimeStamp = canMessage.TimeStamp; message.Identifier = canMessage.Identifier; if (canMessage.ExtendedFrameFormat) { message.FrameFormat = FrameFormat.ExtendedFrame; } else { message.FrameFormat = FrameFormat.StandardFrame; } if (canMessage.RemoteTransmissionRequest) { message.FrameType = FrameType.REMOTEFRAME; } else { message.FrameType = FrameType.DATAFRAME; } message.Data = new Byte[canMessage.DataLength]; for (int index = 0; index < canMessage.DataLength; index++) { message.Data[index] = canMessage[index]; } //#if DEBUG //WindowsDebugging.WriteLine("IN: " + message.ToString(), Category.Information); //#endif // Добавляем сообщение во входной буфер и lock (_SyncRoot) { this._InputBufferMessages.Enqueue(message); } // Генерируем событие this.OnDataReceive(); break; } // show informational frames case CanMsgFrameType.Info: { //message = new Frame(); //message.Data = null; //message.FrameType = FRAMETYPE.INFOFRAME; switch ((CanMsgInfoValue)canMessage[0]) { case CanMsgInfoValue.Start: //Trace.TraceInformation("{0}: calss CanPort.ReceiveMessages: Принято сообщение от драйвера - CanPort was started", // DateTime.Now.ToString(new System.Globalization.CultureInfo("ru-Ru", false))); //#if DEBUG //WindowsDebugging.WriteLine("Принято сообщение от драйвера - CanPort was started", Category.Information); //#endif this._PortStatus = CanPortStatus.IsActive; // Генерируем событие this.OnPortChangesStatus(CanPortStatus.IsActive); break; case CanMsgInfoValue.Stop: //Trace.TraceInformation("{0}: calss CanPort.ReceiveMessages: Принято сообщение от драйвера - CanPort was stopped", // DateTime.Now.ToString(new System.Globalization.CultureInfo("ru-Ru", false))); //#if DEBUG //WindowsDebugging.WriteLine("Принято сообщение от драйвера - CanPort was stopped", Category.Information); //#endif this._PortStatus = CanPortStatus.IsPassive; this.OnPortChangesStatus(CanPortStatus.IsPassive); // Генерируем событие break; case CanMsgInfoValue.Reset: //Trace.TraceInformation("{0}: calss CanPort.ReceiveMessages: Принято сообщение от драйвера - CanPort was reseted", // DateTime.Now.ToString(new System.Globalization.CultureInfo("ru-Ru", false))); //#if DEBUG //WindowsDebugging.WriteLine("Принято сообщение от драйвера - CanPort was reseted", Category.Information); //#endif this._PortStatus = CanPortStatus.IsPassiveAfterReset; // Генерируем событие this.OnPortChangesStatus(CanPortStatus.IsPassiveAfterReset); break; default: { Trace.TraceWarning("{0}: calss CanPort.ReceiveMessages: Получено нейзвестное сообщение от драйвера типа CanMsgFrameType.Info...", DateTime.Now.ToString(new System.Globalization.CultureInfo("ru-Ru", false))); throw new Exception(); //this.OnPortChangesStatus(CANPORTSTATUS.Unknown); //break; } } break; } // show error frames case CanMsgFrameType.Error: { // Генерируем событие об ошибке switch ((CanMsgError)canMessage[0]) { // Bit stuffing - когда узел передает последовательно в шину 5 бит с одинаковым значением, // то он добавляет шестой бит с противоположным значением. Принимающие узлы этот // дополнительный бит удаляют. Если узел обнаруживает на шине больше 5 последовательных // бит с одинаковым значением, то он генерирует ошибку Stuff Error. case CanMsgError.Stuff: //Trace.TraceError("{0}: class CanPort.ReceiveMessages: stuff error...", // DateTime.Now.ToString(new System.Globalization.CultureInfo("ru-Ru", false))); //#if DEBUG //WindowsDebugging.WriteLine("stuff error", Category.Error); //#endif OnErrorRecive(ERROR.BitStuff); break; // Frame Check - некоторые части CAN-сообщения имеют одинаковое значение во всех // типах сообщений. Т.е. протокол CAN точно определяет какие уровни напряжения и // когда должны появляться на шине. Если формат сообщений нарушается, то узлы // генерируют ошибку Form Error. case CanMsgError.Form: //Trace.TraceError("{0}: class CanPort.ReceiveMessages: format of frame error...", // DateTime.Now.ToString(new System.Globalization.CultureInfo("ru-Ru", false))); //#if DEBUG //WindowsDebugging.WriteLine("format of frame error", Category.Error); //#endif OnErrorRecive(ERROR.FormatFrame); break; // ACKnowledgement Check - каждый узел получив правильное сообщение по сети посылает // в сеть доминантный (0) бит. Если же этого не происходит, то передающий узел // регистрирует ошибку Acknowledgement Error. case CanMsgError.Acknowledge: //Trace.TraceError("{0}: class CanPort.ReceiveMessages: acknowledgment error...", // DateTime.Now.ToString(new System.Globalization.CultureInfo("ru-Ru", false))); //#if DEBUG //WindowsDebugging.WriteLine("acknowledgment error", Category.Error); //#endif OnErrorRecive(ERROR.Acknowledge); break; // Check Bit monitoring - каждый узел во время передачи битов в сеть сравнивает значение // передаваемого им бита со значением бита которое появляется на шине. Если эти значения // не совпадают, то узел генерирует ошибку Bit Error. Естественно, что во время арбитража // на шине (передача поля арбитража в шину) этот механизм проверки ошибок отключается. case CanMsgError.Bit: //Trace.TraceError("{0}: class CanPort.ReceiveMessages: bit error...", // DateTime.Now.ToString(new System.Globalization.CultureInfo("ru-Ru", false))); //#if DEBUG //WindowsDebugging.WriteLine("bit error", Category.Error); //#endif OnErrorRecive(ERROR.Bit); break; // CRC Check - каждое сообщение CAN содержит CRC сумму, и каждый принимающий узел // подсчитывает значение CRC для каждого полученного сообщения. Если подсчитанное // значение CRC суммы, не совпадает со значением CRC в теле сообщения, принимающий // узел генерирует ошибку CRC Error. case CanMsgError.Crc: Trace.TraceError("{0}: class CanPort.ReceiveMessages: CRC error...", DateTime.Now.ToString(new System.Globalization.CultureInfo("ru-Ru", false))); OnErrorRecive(ERROR.CRC); break; case CanMsgError.Other: //Trace.TraceError("{0}: class CanPort.ReceiveMessages: other error...", // DateTime.Now.ToString(new System.Globalization.CultureInfo("ru-Ru", false))); //#if DEBUG //WindowsDebugging.WriteLine("other error", Category.Error); //#endif OnErrorRecive(ERROR.Other); break; } break; } } } } catch (Exception ex) { String msg; Interlocked.Exchange(ref _FlagMustQuit, 0); msg = String.Format("{0}: class CanPort.ReceiveMessages: Чтение сообщения из буфера CanPort вызвало исключение {1}, поток завершён, стек: {2}", DateTime.Now.ToString(new System.Globalization.CultureInfo("ru-Ru", false)), ex.Message, ex.StackTrace); Trace.TraceError(msg); throw; } } //Trace.TraceInformation("{0}: class CanPort.ReceiveMessages(): Поток на чтение данных завершён", // DateTime.Now.ToString(new System.Globalization.CultureInfo("ru-Ru"))); //#if DEBUG //WindowsDebugging.WriteLine("Поток на чтение порта зaвершен", Category.Information); //#endif return; }