/// <summary> /// /// </summary> /// <param name="messages"></param> public override void HandleIncomingMessages(Frame[] messages) { String msg; IncomingMessageStuctureServicePdoTransmit msghelper; DeviceBase device; //ObjectInfo objInfo; if (_Status != Status.Running) { return; } foreach(Frame message in messages) { msghelper = IncomingMessageStuctureServicePdoTransmit.Parse(message); if (!msghelper.IsForService) { return; } if (msghelper.HasIncorrectStructure) { // Формат сообщения неверен. msg = String.Format( "Network {0}: Принято сообщение с неверным форматом данных {1}", _NetworkController.Description, message.ToString()); //_Logger.Error(msg); return; } if (!_NetworkController.Devices.Contains(msghelper.NodeId)) { // Устройство не найдено msg = String.Format( "Network {0}: Пришло сообщение от устройства с NodeId {1}, " + "данное устройство не зарегистрировано в сети. Message - {2}", this.NetworkController.Description, msghelper.NodeId, message.ToString()); //Logger.Error(msg); continue; } device = _NetworkController.Devices[msghelper.NodeId]; switch (msghelper.Pdo) { case PdoType.PDO1: { // Data A (polarisation_pot) device.ObjectDictionary[(UInt16)0x2008].Value = ToUInt16(message.Data[0], message.Data[1]); // Data B (protection_pot) device.ObjectDictionary[(UInt16)0x2009].Value = ToUInt16(message.Data[2], message.Data[3]); // Data C (induced_ac) device.ObjectDictionary[(UInt16)0x200A].Value = ToUInt16(message.Data[4], message.Data[5]); // Data D (protection_cur) device.ObjectDictionary[(UInt16)0x200B].Value = ToUInt16(message.Data[6], message.Data[7]); break; } case PdoType.PDO2: { // Data A (polarisation_cur) device.ObjectDictionary[(UInt16)0x200C].Value = ToUInt16(message.Data[0], message.Data[1]); // Data B (aux_cur1) device.ObjectDictionary[(UInt16)0x200D].Value = ToUInt16(message.Data[2], message.Data[3]); // Data C (induced_ac) device.ObjectDictionary[(UInt16)0x200E].Value = ToUInt16(message.Data[4], message.Data[5]); // Data D (Биты состояния датчиков) // 0bxxxxxD3D2D1: byte // D1 - бит, состояние датчика вскрытия tamper // D2 - бит, состояние supply_voltage_low // D3 - бит, состояние battary_volatage_low device.ObjectDictionary[(UInt16)0x2015].Value = (UInt16)(message.Data[6] & 0x01); device.ObjectDictionary[(UInt16)0x2016].Value = (UInt16)(message.Data[6] & 0x02); device.ObjectDictionary[(UInt16)0x2017].Value = (UInt16)(message.Data[6] & 0x04); break; } case PdoType.PDO3: { // Data A (corrosion_depth) device.ObjectDictionary[(UInt16)0x200F].Value = ToUInt16(message.Data[0], message.Data[1]); // Data B (corrosion_speed) device.ObjectDictionary[(UInt16)0x2010].Value = ToUInt16(message.Data[2], message.Data[3]); // Data C (usipk_state) device.ObjectDictionary[(UInt16)0x2011].Value = message.Data[4]; // Data D (Биты состояния датчиков коррозии) // 0bxxxxxD3D2D1: byte // D1 - бит, состояние датчика коррозии 1 // D2 - бит, состояние датчика коррозии 2 // D3 - бит, состояние датчика коррозии 3 device.ObjectDictionary[(UInt16)0x2018].Value = (UInt16)(message.Data[5] & 0x01); device.ObjectDictionary[(UInt16)0x2019].Value = (UInt16)(message.Data[5] & 0x02); device.ObjectDictionary[(UInt16)0x201A].Value = (UInt16)(message.Data[5] & 0x04); break; } case PdoType.PDO4: { // Data A (polarisation_cur_dc) device.ObjectDictionary[(UInt16)0x201B].Value = ToUInt16(message.Data[0], message.Data[1]); // Data B (aux_cur1) device.ObjectDictionary[(UInt16)0x201C].Value = ToUInt16(message.Data[2], message.Data[2]); break; } } } }
public abstract void Write(Frame message);
public object Clone() { Frame frm = new Frame(); frm._FrameFormat = this._FrameFormat; frm._FrameType = this._FrameType; frm._Identifier = this._Identifier; frm._Data = new byte[this._Data.Length]; for (int i = 0; i < this._Data.Length; i++) { frm._Data[i] = this._Data[i]; } return frm; }
/// <summary> /// Обработчик события срабатываения таймера. /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void EventHandler_TimerSyncMessage_Elapsed(object sender, ElapsedEventArgs e) { //String msg; Frame message; // Формируем сообщение SYNC и посылаем его в сеть message = new Frame(); message.Identifier = 0x80; message.FrameFormat = FrameFormat.StandardFrame; message.FrameType = FrameType.DATAFRAME; message.Data = new Byte[0]; lock (_SyncRoot) { _NetworkController.SendMessageToCanPort(message); } // Записываем в лог... }
/// <summary> /// Заканчивает текущую транзакцию (удачное завершение) /// </summary> /// <param name="answer">Ответ slave-устройства</param> public void Stop(Frame? answer) { string msg; if (!this.IsRunning) { throw new InvalidOperationException( String.Format("Transaction ID: {0}; Попытка завершить не начатую транзакцию", _Identifier)); } else { switch (_TransactionType) { case TransactionType.UnicastMode: { if (answer.HasValue) { _Answer = answer; } else { msg = String.Format( "Transaction ID: {0}; Попытка установить в null ответное сообщение для завершения " + "транзакции адресованного запроса", _Identifier); Abort(answer, msg); throw new NullReferenceException(msg); } break; } case TransactionType.BroadcastMode: { if (answer != null) { msg = String.Format( "Transaction ID: {0}; Попытка установить ответное сообщение для завершения транзакции " + "широковещательного запроса", _Identifier); Abort(answer, msg); throw new InvalidOperationException(msg); } break; } default: { msg = String.Format("Transaction ID: {0}; Попытка остановить сетевую транзакцию " + "тип которой не поддерживается - {1}", _Identifier, _TransactionType); Abort(answer ,msg); throw new NotImplementedException(msg); } } this._TimeOfEnd = DateTime.Now; this._Status = TransactionStatus.Completed; // Генерируем событие окончания транзакции. OnTransactionWasEnded(); //Debug.WriteLine(String.Format( // "Transaction ID: {0} - Конец транзакции: {1}; Время транзакции: {2}", // this.Identifier, this._TimeOfEnd, this.TimeOfTransaction)); } return; }
/// <summary> /// Выполняет запрос к удалённому устройству /// (переберая устройства и объекты словаря) /// </summary> public override void HandleOutcomingMessages() { DeviceContext device; //ObjectInfo objInfo; // Сервис не работает if (_Status != Status.Running) { return; } if (_Context.Count == 0) { return; } // Устанавливаем следующее по списку устройство для обработки _Context.Next(); // Получаем устройство для обработки device = _Context.CurrentDevice; // Если устройство активно, выполняем запрос lock (_SyncRoot) { if ((device.Device.Status == DeviceStatus.Operational) || (device.Device.Status == DeviceStatus.Preoperational) || (device.Device.Status == DeviceStatus.Stopped)) { if (device.CurrentTransaction == null) { device.CurrentTransaction = new Transaction(); } // Проверяем, что последнй запрос (транзакция) к устройству выполнена // Если это так, начинаем новую, в противном случае ничего неделаем (ждём окончания транзакции) if (device.CurrentTransaction.IsRunning) { // Транзакция активна проверяем длительность транзакции if (device.CurrentTransaction.TimeOfStart.AddSeconds( device.Device.PollingInterval) <= DateTime.Now) { // Таймаут на запрос device.CurrentTransaction.Abort(null, "Request timeout"); // Пишем в лог... } return; } else { // Если запрос был успешным или неудачным, выжадаем требуемое время // для нового запроса if ((device.CurrentTransaction.Status == TransactionStatus.Aborted) || (device.CurrentTransaction.Status == TransactionStatus.Completed)) { if (device.CurrentTransaction.TimeOfStart.AddSeconds( device.Device.PollingInterval) > DateTime.Now) { return; } } if (device.CurrentTransaction.Status == TransactionStatus.Aborted) { if (device.ErrorCount < TotalAttempts) { // Повторяем запрос device.CurrentTransaction.Repeat(); // Отправляем сообщение к устройству _NetworkController.SendMessageToCanPort( device.CurrentTransaction.Request.Value); return; } else { device.CurrentTransaction = null; } } //Получаем следующий объект словаря для обработки device.Next(); if (!device.CurrentObject.SdoCanRead) { // Данный объект не обрабатывается сервисом SDO return; } Transaction trans = new Transaction(); Frame message = new Frame(); message.Identifier = System.Convert.ToUInt32(0x600 + device.Device.NodeId); message.FrameFormat = FrameFormat.StandardFrame; message.FrameType = FrameType.DATAFRAME; message.Data = new Byte[8]; message.Data[0] = 0x40; message.Data[1] = (byte)device.CurrentObject.Index; message.Data[2] = (byte)(device.CurrentObject.Index >> 8); device.CurrentTransaction = trans; trans.Start(TransactionType.UnicastMode, message); } // Отправляем сообщение к устройству _NetworkController.SendMessageToCanPort( device.CurrentTransaction.Request.Value); } } }
/// <summary> /// Разбирает ответное сообщение /// </summary> /// <param name="message">Ответное сообщение</param> /// <returns>Структура данных ответа</returns> internal static IncomingMessageStuctureBootUp Parse(Frame message) { const Byte MASK_COBEID = 0x7F; // Выделяет 7 бит содержащих CodeId из поля Id IncomingMessageStuctureBootUp frame = new IncomingMessageStuctureBootUp(); frame.Answer = message; frame.CobeId = (Byte)(((Byte)message.Identifier) & MASK_COBEID); frame.DL = message.Data.Length; return frame; }
/// <summary> /// Записывает сообщение в порт /// </summary> /// <param name="identifier"></param> /// <param name="frameType"></param> /// <param name="frameFormat"></param> /// <param name="data"></param> public override void WriteMessage(uint identifier, FrameType frameType, FrameFormat frameFormat, byte[] data) { Frame frame = new Frame(); frame.Identifier = identifier; frame.FrameType = frameType; frame.FrameFormat = FrameFormat; if (data != null) { frame.Data = data; } else { frame.Data = new byte[0]; } this.Write(frame); return; }
/// <summary> /// Записывает сообщение в порт /// </summary> /// <param name="message">Сообщение для оправки</param> public override void Write(Frame message) { String msg; F_CAN_RESULT result; F_CAN_TX buffer; F_CAN_STATE status; uint count = 0; // Если прот закрыт, отсылка сообщения не возможна if (!this.IsOpen) { msg = "Невозможно отправить сообщение, CAN-порт закрыт"; throw new InvalidOperationException(msg); } status = this.GetPortStatus(); if (this.PortStatus != CanPortStatus.IsActive) { msg = "Невозможно отправить сообщение, CAN-порт отключён от физической сети"; throw new InvalidOperationException(msg); } // Разбираем сообщение и подготавливаем его для отправки buffer.msg = ConvertNim351.ConvertToF_CAN_MSG(message); result = Api.fw_can_send(this._DeviceHandle, ref buffer, 1, ref count); //result = Api.fw_can_post_message(this._DeviceHandle, ref buffer); if (!Api.f_can_success(result)) { // При отправке сообщения возникла ошибка msg = String.Format("Не удалось отправить сообщение. Error: ", result); throw new InvalidOperationException(msg); } return; }
/// <summary> /// Принять сообщения от контроллера сети /// </summary> /// <param name="messages"></param> public virtual void HandleIncomingMessages(Frame[] messages) { return; }
/// <summary> /// /// </summary> public override void HandleOutcomingMessages() { DeviceContext device; DateTime time; Frame message; // Сервис не работает if (_Status != Status.Running) { return; } if (_Context.Count == 0) { return; } // Получаем следующее устройство в спике _Context.Next(); device = _Context.CurrentDevice; if (device.Device.Status == DeviceStatus.CommunicationError) { // Если устройство не доступно, пропускаем его return; } // Проверяем статус запроса if (device.CurrentTransaction == null) { device.CurrentTransaction = new Transaction(); } switch (device.CurrentTransaction.Status) { case TransactionStatus.Running: { time = device.CurrentTransaction.TimeOfStart.AddSeconds( device.Device.PollingInterval); if (time < DateTime.Now) { // Устройство не ответилo за заданное время. // Устанавливаем статус неудачной попытки device.CurrentTransaction.Abort(null, "Request timeout"); } break; } case TransactionStatus.Aborted: { // Проверяем количество попыток доступа к устройству. // Если оно достигло предела. Устанавливаем статус ошибки if (device.ErrorCount < TotalAttempts) { // Повторяем запрос device.CurrentTransaction.Repeat(); _NetworkController.SendMessageToCanPort( device.CurrentTransaction.Request.Value); } else { // Устанавливаем новый статус устройству device.CurrentTransaction = null; device.Device.Status = DeviceStatus.CommunicationError; } break; } case TransactionStatus.NotInitialized: { message = new Frame(); message.Identifier = System.Convert.ToUInt32(0x700 + device.Device.NodeId); message.FrameFormat = FrameFormat.StandardFrame; message.FrameType = FrameType.REMOTEFRAME; message.Data = new Byte[0]; device.CurrentTransaction = new Transaction(); device.CurrentTransaction.Start(TransactionType.UnicastMode, message); // Отправляем запрос _NetworkController.SendMessageToCanPort( device.CurrentTransaction.Request.Value); break; } case TransactionStatus.Completed: { // Получаем время последнего опроса устройства. // Прибавляем к нему время прериода опроса устройства // и сравниваем с текущим временем. Если полученное время меньше текущего, // то выполняем запрос к устройству. time = device.CurrentTransaction.TimeOfStart.AddSeconds( device.Device.PollingInterval); if (time < DateTime.Now) { message = new Frame(); message.Identifier = System.Convert.ToUInt32(0x700 + device.Device.NodeId); message.FrameFormat = FrameFormat.StandardFrame; message.FrameType = FrameType.REMOTEFRAME; message.Data = new Byte[0]; device.CurrentTransaction = new Transaction(); device.CurrentTransaction.Start(TransactionType.UnicastMode, message); // Отправляем запрос _NetworkController.SendMessageToCanPort( device.CurrentTransaction.Request.Value); } break; } default: { throw new Exception(); } } }
/// <summary> /// /// </summary> public override void HandleOutcomingMessages() { DeviceContext device; String msg; DateTime time; Frame request; Transaction transaction; // 1. Проверяем статус устройства: // 1.1 Если устройство находится в состоянии Operational, ничего не делаем // 1.2 Если устройство находится в состоянии CommunicationError, ничего не делаем // 1.3 Если устройство находится в состоянии ConfigurationError, ничего не делаем // 1.4 Если устройства находится в состоянии Stopped, ничего не делаем // 1.5 Если устройство находится в состоянии Pre-operational, отправляем команду // перевода устройства в состояние Operational // 1.5.1 Проверяем // Сервис не работает if (_Status != Status.Running) { return; } // Получаем устройство _Context.Next(); device = _Context.CurrentDevice; // Проверяем статус if (device.Device.Status == DeviceStatus.Preoperational) { if (device.CurrentTransaction != null) { switch (device.CurrentTransaction.Status) { case TransactionStatus.Running: { // Запрос был уже отправлен. Проверяем таймаут time = device.CurrentTransaction.TimeOfStart; time = time.AddSeconds(device.Device.PollingInterval); if (time < DateTime.Now) { msg = String.Format("Service NMT: Timeout - устройство" + "не перешло в режим Operational за заданное время"); // Устройство не перешло из состояние Pre-Operational // за заданное время. Устанавливаем статус неудачной попытки device.CurrentTransaction.Abort(null, msg); } break; } case TransactionStatus.NotInitialized: case TransactionStatus.Completed: { // Устройство перешло в состояние Operational - транзакция выполнена // Однако, по какой-то причине устройство перешло в состояние Pre-Operational // Переводим устройство в состояние Operational request = new Frame(); request.Identifier = 0; request.FrameFormat = FrameFormat.StandardFrame; request.FrameType = FrameType.DATAFRAME; request.Data = new Byte[] { (Byte)StatusCode.Operational, // Поле комадны device.Device.NodeId // Поле Node ID }; transaction = new Transaction(); transaction.Start(TransactionType.BroadcastMode, request); lock (_SyncRoot) { _NetworkController.SendMessageToCanPort( transaction.Request.Value); } break; } case TransactionStatus.Aborted: { // Проверяем количество неудачных попыток и если оно // достигло предела не отсылаем устройству больше запросов if (device.ErrorCount < TotalAttempts) { // Повторяем запрос device.CurrentTransaction.Repeat(); lock (_SyncRoot) { _NetworkController.SendMessageToCanPort( device.CurrentTransaction.Request.Value); } } break; } default: { msg = String.Format( "Network {0}: ServiceNmt - Обнаружен статус запроса {1} не поддерживаемый " + "в данной версии ПО", _NetworkController.Description, device.CurrentTransaction.Status); throw new Exception(msg); } } } else { // Отправляем команду для перевода устройства в состояние Operational request = new Frame(); request.Identifier = 0; request.FrameFormat = FrameFormat.StandardFrame; request.FrameType = FrameType.DATAFRAME; request.Data = new Byte[] { (Byte)StatusCode.Operational, // Поле комадны device.Device.NodeId // Поле Node ID }; device.CurrentTransaction = new Transaction(); device.CurrentTransaction.Start(TransactionType.UnicastMode, request); lock (_SyncRoot) { _NetworkController.SendMessageToCanPort( device.CurrentTransaction.Request.Value); } } } else { // Oбратная связь возникает через сервис NodeGuard, // который отслеживает состояние устройства. И только он может установить, что // устройство перешло режим Operational и устанавливает статус устройству. // По этому, проверяем состояние транзакции и если транзакция активна // и устройство изменило статус, то считаем что команда дошла до устройства // и завершаем транзакцию. if ((device.CurrentTransaction != null) && (device.CurrentTransaction.IsRunning)) { // Т.к сервис не получает ответа, останавливаем транзакцию // при помощи пустого фрайма (псевноответа) device.CurrentTransaction.Stop(new Frame()); } } }
/// <summary> /// /// </summary> /// <param name="messages"></param> public override void HandleIncomingMessages(Frame[] messages) { // Данный сервис не обрабатывает входящие сообщения return; }
/// <summary> /// Разбирает ответное сообщение /// </summary> /// <param name="message">Ответное сообщение</param> /// <returns>Структура данных ответа</returns> internal static IncomingMessageStuctureServicePdoTransmit Parse(Frame message) { // Маска для отделения (Fct code: 4 старших бита) от адреса устройства (7 младших бит) // переданных в CobId сообщения const UInt16 MASK_FCT_CODE = 0x780; // 11110000000; // Идентификатор CodId, по которому определяется что входящее сообщение // предназначено для данного сервиса const UInt16 MASK_PDO1 = 0x180; const UInt16 MASK_PDO2 = 0x280; const UInt16 MASK_PDO3 = 0x380; const UInt16 MASK_PDO4 = 0x480; const Byte MASK_COBEID = 0x7F; // Выделяет 7 бит содержащих CodeId из поля Id IncomingMessageStuctureServicePdoTransmit frame = new IncomingMessageStuctureServicePdoTransmit(); frame.Answer = message; // Выделяет 7 бит содержащих CodeId из поля Id // Работаем только с данным типом сообщений другие игнорируем. if (frame.Answer.Value.FrameType == FrameType.DATAFRAME) { UInt16 cobId = (UInt16)(frame.Answer.Value.Identifier & MASK_FCT_CODE); switch (cobId) { case MASK_PDO1: { frame.Pdo = PdoType.PDO1; frame._IsForService = true; // Проверяем корректность данных frame._IsCorrectStructure = frame.Answer.Value.Data.Length == 8 ? true : false; break; } case MASK_PDO2: { frame.Pdo = PdoType.PDO2; frame._IsForService = true; // Проверяем корректность данных frame._IsCorrectStructure = frame.Answer.Value.Data.Length == 7 ? true : false; break; } case MASK_PDO3: { frame.Pdo = PdoType.PDO3; frame._IsForService = true; // Проверяем корректность данных frame._IsCorrectStructure = frame.Answer.Value.Data.Length == 6 ? true : false; break; } case MASK_PDO4: { frame.Pdo = PdoType.PDO4; frame._IsForService = true; // Проверяем корректность данных frame._IsCorrectStructure = frame.Answer.Value.Data.Length == 4 ? true : false; break; } default: { frame.Pdo = PdoType.Unknown; frame._IsForService = false; // Проверяем корректность данных frame._IsCorrectStructure = false; break; } } } else { frame.Pdo = PdoType.Unknown; frame._IsForService = false; } frame.NodeId = (Byte)(((Byte)message.Identifier) & MASK_COBEID); frame.DL = message.Data.Length; return frame; }
/// <summary> /// Возвращает индекс объекта в запросе /// </summary> /// <param name="request"></param> /// <returns></returns> private UInt16 GetIndex(Frame request) { UInt16 index = 0; unchecked { index = Convert.ToUInt16(request.Data[ANSWER_STUCTURE.INDEXLOW] | (request.Data[ANSWER_STUCTURE.INDEXHIGH] << 8)); } return index; }
public override bool Read(out Frame message) { lock (_SyncRoot) { if (this._InputBufferMessages.Count > 0) { message = this._InputBufferMessages.Dequeue(); return true; } else { message = new Frame(); return false; } } }
/// <summary> /// Обработать принятые сообщения /// </summary> /// <param name="messages">Входящие сообщения из сети</param> public override void HandleIncomingMessages(Frame[] messages) { String msg; IncomingMessageStuctureSdo msghelper; DeviceContext deviceContex; DataObject obj; // Индексы объектов которые не обрабатываем!!! List<UInt16> notHandledIndexes = new List<ushort>(); notHandledIndexes.AddRange(new UInt16[] { 0x2001, 0x2002 }); if (Status != Status.Running) { return; } foreach(Frame message in messages) { // Сообщение для этого сервиса. Получаем структуру сообщения msghelper = IncomingMessageStuctureSdo.Parse(message); if (!msghelper.IsForService) { // Сообещение не для этого сервиса continue; } // Ищем устройство с данным CobId. Если устройство найдено, // то устанавливаем флаг deviceContex = _Context.FindDevice(msghelper.CobeId); if (deviceContex == null) { // Устройство не найдено. msg = String.Format( "Network {0}: SDO Service: Получено сообщение от незарегистрированного устройства. " + "Message - {1}", _NetworkController.Description, message.ToString()); //Trace.TraceError(msg); continue; } // Устройство найдено. Проверяем его текущий запрос, т.е index if ((deviceContex.CurrentTransaction != null) && (deviceContex.CurrentTransaction.Status == TransactionStatus.Running)) { if (msghelper.HasExсeption) { if (GetIndex(deviceContex.CurrentTransaction.Request.Value) == msghelper.Index) { msg = String.Format( "Network {0}: SDO Service: Устройсво вернуло исключение {1}", _NetworkController.NetworkId, msghelper.ExceptionCode); deviceContex.CurrentTransaction.Abort(msghelper.Answer, msg); } else { msg = String.Format("Network {0}: SDO Service: " + "Индекс в ответе не соответствует запрошенному. Запрос - {1}, Ответ - {2}", NetworkController.NetworkId,deviceContex.CurrentTransaction.Request.Value.ToString(), message.ToString()); } continue; } // Проверяем индекс запроса и ответа if (GetIndex(deviceContex.CurrentTransaction.Request.Value) != msghelper.Index) { // Прищёл ответ на несуществующий запрос msg = String.Format("Network {0}: SDO Service: " + "Индекс в ответе не соответствует запрошенному. Запрос - {1}, Ответ - {2}", NetworkController.NetworkId, deviceContex.CurrentTransaction.Request.Value.ToString(), message.ToString()); //Trace.TraceError(msg); continue; } else { // Устанавливаем ответ на запрос //deviceContex.CurrentTransaction.Answer = frmSdo.Answer; // Проверяем контекст if (deviceContex.CurrentObject.Index != msghelper.Index) { msg = String.Format( "Network {0}: SDO Service: Индекс в ответе соответствует запрошенному {1}, " + "но не соотвествует индексу в контексте {2}", _NetworkController.NetworkId, msghelper.Index, deviceContex.CurrentObject); deviceContex.CurrentTransaction.Abort(msghelper.Answer, msg); throw new Exception(msg); } } // Всё нормально, subindex-ы не проверяем они всегда равны 0; // Исключений нет, устанавливаем новое полученное значение для объекта // с указанным индексом // Получаем тип данных соответствующего идекса для соотвествующего профиля устройства ObjectInfo objInfo; if (!deviceContex.Device.Profile.ObjectInfoList.Contains(msghelper.Index)) { msg = String.Format("Network {0}: SDO Service: " + "Ненайдено описание объекта c индексом {1} в профиле устройства {2}", _NetworkController.Description, msghelper.Index, deviceContex.Device.Profile.DeviceType); deviceContex.CurrentTransaction.Abort(msghelper.Answer, msg); throw new InvalidOperationException(msg); } else { objInfo = deviceContex.Device.Profile.ObjectInfoList[msghelper.Index]; } if (!deviceContex.Device.ObjectDictionary.Contains(msghelper.Index)) { msg = String.Format("Network {0}: SDO Service: " + "Ненайден объект c индексом {1} в словаре устройства {2}", _NetworkController.Description, msghelper.Index, deviceContex.Device.NodeId); deviceContex.CurrentTransaction.Abort(msghelper.Answer, msg); throw new InvalidOperationException(msg); } else { obj = deviceContex.Device.ObjectDictionary[msghelper.Index]; } // Проверяем модификатор доступа к значению. Если "только для чтения" // и тип: System или Configuration, то параметр конфигурационный. // В этом случае сравниваем прочитанное значение со значением объета словаря. // Если они не совпадают, устанавливаем статус "Ошибка конфигурации" // Если тип Measured, то читаем и устанавливаем данное значение из устройства if ((objInfo.ReadOnly) && (objInfo.Category == Category.Configuration || objInfo.Category == Category.System)) { if (notHandledIndexes.Contains(obj.Index)) { // Обновляем время последнего прочтения obj.Value = obj.Value; // Закрываем транзакцию deviceContex.CurrentTransaction.Stop(msghelper.Answer); continue; } if (msghelper.Value != obj.Value) { // Ошбика конфигурации msg = String.Format( "Ошбика конфигурации устройства: Устройство NodeId={0}, Индекс объекта={1}. " + "Значение в словаре={2}, прочитнное значение={3}", deviceContex.Device.NodeId, msghelper.Index, obj.Value, msghelper.Value); // Обновляем дату последнего обновления параметра obj.Value = obj.Value; // Устанавливаем код состояния объекта словаря obj.Status = ObjectStatus.ConfigurationError; // Записываем ошибку в лог // ... deviceContex.CurrentTransaction.Abort(msghelper.Answer, msg); } else { // Ошибки нет. // Обновляем дату последнего обновления параметра obj.Value = obj.Value; // Устанавливаем код состояния объекта словаря obj.Status = ObjectStatus.NoError; deviceContex.CurrentTransaction.Stop(msghelper.Answer); } } else { // Записываем новое значение в БД // TODO: реализовать проверку на допустимые значение объекта obj.Value = msghelper.Value; obj.Status = ObjectStatus.NoError; deviceContex.CurrentTransaction.Stop(msghelper.Answer); } } } }
/// <summary> /// Метод для чтения порта. Запускается во вторичном потоке. Поток на чтение запускается при открытии порта /// и завершается при закрытии. /// </summary> private void HandleQueueIncomingMessages() { String msg; F_CAN_RESULT result; F_CAN_RX buffer; F_CAN_WAIT wait; UInt32 timeout = 500; // мсек Frame message; //uint count; // Если прот закрыт, чтение его буфера не возможно //if (this.IsOpen == false) //{ // msg = "Невозможно прочитать очередь сообщений, CAN-порт закрыт"; // throw new InvalidOperationException(msg); //} // Читаем порт всё время пока открыт while (this._FlagMustQuit > 0) { wait.waitMask = F_CAN_STATUS.CAN_STATUS_EMPTY | F_CAN_STATUS.CAN_STATUS_TXBUF; wait.status = F_CAN_STATUS.CAN_STATUS_EMPTY; result = Api.fw_can_wait(this._DeviceHandle, ref wait, timeout); if ((result == F_CAN_RESULT.CAN_RES_OK) || (result == F_CAN_RESULT.CAN_RES_TIMEOUT)) { if (result == F_CAN_RESULT.CAN_RES_TIMEOUT) { //Console.WriteLine("Сработал таймаут ожидания"); // Произошло что-то нехорошее, нужно анализировать и что-то делать // Проверяем текущий статус //if (wait.status == wait.waitMask) //{ } // Останавливаем порт this.Stop(); // Генерируем событие OnErrorReceived(ERROR.Other); // Закрываем порт this.Close(); // Завершаем работу потока Interlocked.Exchange(ref this._FlagMustQuit, 0); continue; } // Если флаг установлен, то есть принятые сообщения. Читаем их // и помещаем в буфер исходящих сообщений if (F_CAN_STATUS.CAN_STATUS_RXBUF == (wait.status & F_CAN_STATUS.CAN_STATUS_RXBUF)) { // Читаем буфер адаптера result = Api.fw_can_peek_message(_DeviceHandle, out buffer); // Разбираем принятое сообщение и формируем событие message = new Frame(); message = ConvertNim351.ConvertToFrame(buffer.msg); // Помещает принятое сообщение в буфер входных сообщений и генерируем событие приёма lock (_SyncRoot) { this._InputBufferMessages.Enqueue(message); } this.OnMessageReceived(); } // Произошла ошибка читаем её и сбрасываем if (F_CAN_STATUS.CAN_STATUS_ERR == (wait.status & F_CAN_STATUS.CAN_STATUS_ERR)) { F_CAN_ERRORS errors; result = Api.fw_can_get_clear_errors(this._DeviceHandle, out errors); if (Api.f_can_success(result)) { // Анализируем счётчики и генерируем событие this.OnErrorReceived(ERROR.Other); } else { msg = String.Format( "При чтении и сбросе счётчика ошибок CAN-адаптера возникла ошибка: {0}", result); throw new InvalidOperationException(msg); } } } else { msg = String.Format("При выполнении функции fw_can_wait произошла ошибка: {0}", Enum.GetName(typeof(F_CAN_RESULT), result)); throw new InvalidOperationException(msg); } } return; }
/// <summary> /// Обработчик входящих сообщений из сети /// </summary> /// <param name="message">Входящее сообщение для обработки</param> //private void HandleIncomingMessages(Frame message) public override void HandleIncomingMessages(Frame[] messages) { String msg; IncomingMessageStuctureBootUp msghelper; DeviceBase device; if (Status != Status.Running) { return; } foreach (Frame message in messages) { msghelper = IncomingMessageStuctureBootUp.Parse(message); if (!msghelper.IsForService) { continue; } if (msghelper.HasIncorrectStructure) { //!!!Warning: Длина данных в поле данных корректна, но содержание неверно // (message.Data[0] == 0x84) || (message.Data[0] == 0x04) || // (message.Data[0] == 0x85) || (message.Data[0] == 0x05) || // (message.Data[0] == 0xFF) || (message.Data[0] == 0x7F)) // Эти коды используются в протоколе NodeGuard. continue; } // Сообщение для этого сервиса. //msg = String.Format("Network {0}: Сервис {1}: Service BootUp принял сообщение: {2}", // base.NetworkController.NetworkName(), this.ServiceName, message.ToString()); //_Logger.Trace(msg); //Ищем устройство которое прислало сообщение if (!_NetworkController.Devices.Contains(msghelper.CobeId)) { // Устройство не найдено msg = String.Format( "Network {0}: Пришло сообщение от устройства с NodeId {1}, " + "данное устройство не зарегистрировано в сети. Message - {2}", this.NetworkController.Description, msghelper.CobeId, message.ToString()); //Logger.Error(msg); continue; } // Устройство найдено. // Устанавливаем новый статус устройству device = _NetworkController.Devices[msghelper.CobeId]; lock (_SyncRoot) { device.Status = DeviceStatus.Preoperational; } // Пишем в журнал... Не реализовано } }
/// <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; }
public override void HandleIncomingMessages(Frame[] messages) { //Данный сервис не имеет входящих сообщений return; }
/// <summary> /// Читает из входного буфера сообщение. /// </summary> /// <returns>Если буфер пуст возвращается false</returns> public Boolean ReadMessage(out Frame message) { Boolean result; lock (_SyncRoot) { if (_InputBufferMessages.Count != 0) { message = (Frame)_InputBufferMessages.Dequeue(); result = true; } else { message = new Frame(); result = false; } } return result; }
/// <summary> /// Начинает новую транзакцию /// </summary> public void Start(TransactionType type, Frame request) { string msg; if (this.IsRunning) { msg = String.Format( "Transaction ID: {0}; Попытка запустить уже запущенную (активную) транзакцию", _Identifier); throw new InvalidOperationException(msg); } else { _Request = request; _Status = TransactionStatus.Running; switch (type) { case TransactionType.BroadcastMode: case TransactionType.UnicastMode: { _TimeOfStart = DateTime.Now; this._TransactionType = type; break; } case TransactionType.Undefined: { msg = String.Format( "Transaction ID: {0}; Попытка начать сетевую транзакцию неопределённого типа", _Identifier); Abort(null, msg); throw new InvalidOperationException(msg); } default: { msg = String.Format("Transaction ID: {0}; Попытка начать сетевую транзакцию " + "тип которой не поддерживается - {1}", _Identifier, _TransactionType); Abort(null, msg); throw new NotImplementedException(msg); } } //Debug.WriteLine(String.Format( // "Transaction ID: {0} - Начало транзакции: {1} мсек", // this.Identifier.ToString(), this._TimeOfStart)); } return; }
public override void Write(Frame message) { String msg; // Проверяем корректность данных. Можно отправить только фреймы двух типов // FRAMETYPE.DATAFRAME и FRAMETYPE.REMOTEFRAME остальные не допустимы (служебные) // !!! FRAMETYPE.OVERLOADFRAME не разобрался if (!((message.FrameType == FrameType.DATAFRAME) || (message.FrameType == FrameType.REMOTEFRAME))) { msg = String.Format( "{0}: class CanPort.ICanPort.Write(Frame message): Недопустимый тип фрайма, подустимы только FRAMETYPE.DATAFRAME и FRAMETYPE.REMOTEFRAME", DateTime.Now.ToString(new System.Globalization.CultureInfo("ru-Ru", false))); Trace.TraceError(msg); throw new ArgumentException(msg, "message.FrameType"); } else if (!((message.FrameFormat == FrameFormat.ExtendedFrame) || (message.FrameFormat == FrameFormat.StandardFrame))) { msg = String.Format( "{0}: class CanPort.ICanPort.Write(Frame message): Недопустимый формат фрайма, допустимы только FRAMEFORMAT.ExtendedFrame и FRAMEFORMAT.StandardFrame", DateTime.Now.ToString(new System.Globalization.CultureInfo("ru-Ru", false))); throw new ArgumentException(msg, "message.FrameFormat"); } else { if (message.Data != null) { if (message.Data.Length > 8) { msg = String.Format( "{0}: class CanPort.ICanPort.Write(Frame message): Попытка передать сообещение, содержащее поле данных более 8 байт", DateTime.Now.ToString(new System.Globalization.CultureInfo("ru-Ru", false))); throw new ArgumentException(msg, "message.Data.Length"); } else { this.WriteMessage(message.Identifier, message.FrameType, message.FrameFormat, message.Data); } } else { message.Data = new Byte[0]; this.WriteMessage(message.Identifier, message.FrameType, message.FrameFormat, message.Data); } } return; }
/// <summary> /// Прерывает текущую транзакцию, произошла ошибка /// </summary> /// <param name="answer">Ответ, если он есть</param> /// <param name="description">Описывает ситуацию отмены текущей транзакции</param> public void Abort(Frame? answer, String description) { string msg; if (!IsRunning) { msg = String.Format("Transaction ID: {0}; Попытка отменить не начатую транзакцию", this.Identifier); throw new InvalidOperationException(msg); } else { _Answer = answer; _TimeOfEnd = DateTime.Now; _Status = TransactionStatus.Aborted; _DescriptionError = String.IsNullOrEmpty(description) ? String.Empty : description; } // Генерируем событие OnTransactionWasEnded(); return; }
public override bool Read(out Frame message) { return this.ReadMessage(out message); }
public abstract bool Read(out Frame message);
/// <summary> /// Разбирает ответное сообщение /// </summary> /// <param name="message">Ответное сообщение</param> /// <returns>Структура данных ответа</returns> internal static IncomingMessageStuctureSdo Parse(Frame message) { const Byte MASK_COBEID = 0x7F; // Выделяет 7 бит содержащих CodeId из поля Id IncomingMessageStuctureSdo frame = new IncomingMessageStuctureSdo(); frame.Answer = message; frame.CobeId = (Byte)(((Byte)message.Identifier) & MASK_COBEID); // Длина данных ответа в SDO всегда 8 if (message.Data.Length == 8) { frame.DL = (DataLenght)message.Data[ANSWER_STUCTURE.DL]; switch (frame.DL) { case DataLenght.OneByte: { frame.Value = message.Data[ANSWER_STUCTURE.D0]; break; } case DataLenght.TwoBytes: { frame.Value = System.Convert.ToUInt32( (message.Data[ANSWER_STUCTURE.D0] | ((UInt32)message.Data[ANSWER_STUCTURE.D1] << 8))); break; } case DataLenght.ThreeBytes: { frame.Value = System.Convert.ToUInt32( (message.Data[ANSWER_STUCTURE.D0] | ((UInt32)message.Data[ANSWER_STUCTURE.D1] << 8) | ((UInt32)message.Data[ANSWER_STUCTURE.D2] << 16))); break; } case DataLenght.FourBytes: case DataLenght.Ecxeption: { frame.Value = System.Convert.ToUInt32( (message.Data[ANSWER_STUCTURE.D0] | ((UInt32)message.Data[ANSWER_STUCTURE.D1] << 8) | ((UInt32)message.Data[ANSWER_STUCTURE.D2] << 16) | ((UInt32)message.Data[ANSWER_STUCTURE.D3] << 32))); break; } case DataLenght.NotDefined: default: { frame._HasIncorrectStructure = true; frame.Value = 0; break; } } } else { frame._HasIncorrectStructure = true; frame.Value = 0; } if (!frame._HasIncorrectStructure) { frame.Index = message.Data[ANSWER_STUCTURE.INDEXLOW]; frame.Index = System.Convert.ToUInt16((frame.Index | (message.Data[ANSWER_STUCTURE.INDEXHIGH] << 8))); frame.SubIndex = message.Data[ANSWER_STUCTURE.SUBINDEX]; } else { frame.Index = 0; frame.SubIndex = 0; } return frame; }
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ /// <summary> /// Обработчик клика по ячейкам грида исходящих сообщений /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void EventHandler_DataGridViewOutcomingMessages_CellClick(object sender, DataGridViewCellEventArgs e) { DataGridView dgv; DataGridViewRow row; Message.Frame message; dgv = (DataGridView)sender; // Определяем от какой ячейки, какого столбца пришло событие // Если от столбца "Отправить", то отправляем сообщение if ((dgv.Columns[e.ColumnIndex] is DataGridViewButtonColumn) && (e.RowIndex >= 0)) { row = dgv.Rows[e.RowIndex]; message = new Frame(); message.Identifier = (UInt32)row.Cells[1].Value; message.FrameFormat = (Message.FrameFormat)row.Cells[2].Value; message.FrameType = (Message.FrameType)row.Cells[3].Value; message.Data = (Byte[])row.Cells[4].Value; //MessageBox.Show(String.Format("Сообщение отправлено: {0}", message.ToString())); if (this._CanPort.IsOpen) { this._CanPort.Write(message); } } return; }
/// <summary> /// Обработчик входящих сообщений из сети /// </summary> /// <param name="message">Входящее сообщение для обработки</param> //private void HandleIncomingMessages(Frame message) public override void HandleIncomingMessages(Frame[] messages) { String msg; IncomingMessageStuctureEmcy msghelper; DeviceBase device; UInt16 index; if (Status != Status.Running) { return; } foreach (Frame message in messages) { msghelper = IncomingMessageStuctureEmcy.Parse(message); if (!msghelper.IsForService) { continue; } if (msghelper.HasIncorrectStructure) { continue; } // Сообщение для этого сервиса. //msg = String.Format("Network {0}: Сервис {1}: Service Emcy принял сообщение: {2}", // base.NetworkController.NetworkName(), this.ServiceName, message.ToString()); //_Logger.Trace(msg); //Ищем устройство которое прислало сообщение if (!_NetworkController.Devices.Contains(msghelper.CobeId)) { // Устройство не найдено msg = String.Format( "Network {0}: Пришло сообщение от устройства с NodeId {1}, " + "данное устройство не найдено конфигурации в сети. Message - {2}", this.NetworkController.Description, msghelper.CobeId, message.ToString()); //Logger.Error(msg); continue; } // Устройство найдено. // Устанавливаем новый статус устройству device = _NetworkController.Devices[msghelper.CobeId]; //Анализируем код ошибки (источник или причина возникновения ошибки) switch (msghelper.ErrorCode) { case IncomingMessageStuctureEmcy.ErrCode.NoError: { // Все ошибки исправлены if (msghelper.ErrorRegister.FlagsByte != 0) { msg = String.Format( "Неверное состояние - передан ErrCode=0 и ожидается err_reg=0, a получено err_reg = {0}", msghelper.ErrorRegister); throw new Exception(msg); } // Сбрасываем ошибки в устройстве если были IEmcyErrors err = (IEmcyErrors)device; lock (_SyncRoot) { err.BatteryError = false; err.ConnectedServiceConnector = false; err.DuplicateAddressError = false; err.MainSupplyPowerError = false; err.RegistrationError = false; err.Tamper = false; } break; } case IncomingMessageStuctureEmcy.ErrCode.Tamper: case IncomingMessageStuctureEmcy.ErrCode.BatteryError: case IncomingMessageStuctureEmcy.ErrCode.MainSupplyPowerError: case IncomingMessageStuctureEmcy.ErrCode.ConnectedServiceConnector: case IncomingMessageStuctureEmcy.ErrCode.DuplicateAddressError: // TODO: обработать поле Х - номер канала шлюза case IncomingMessageStuctureEmcy.ErrCode.RegistrationError: // TODO: обработать поле Х - номер канала шлюза { IEmcyErrors err = (IEmcyErrors)device; lock (_SyncRoot) { err.BatteryError = msghelper.ErrorRegister.BatteryError; err.ConnectedServiceConnector = msghelper.ErrorRegister.ConnectedServiceConnector; err.DuplicateAddressError = msghelper.ErrorRegister.DuplicateAddressError; err.MainSupplyPowerError = msghelper.ErrorRegister.MainSupplyPowerError; err.RegistrationError = msghelper.ErrorRegister.RegistrationError; err.Tamper = msghelper.ErrorRegister.Tamper; } break; } default: { throw new NotImplementedException(); } } //TODO: Пишем в журнал... Не реализовано } }