/// <summary> /// Функция 0х5. Устанавливает реле в состояние вкл./выкл. /// в удалённом устройстве /// </summary> /// <param name="addressSlave">адрес удалённого slave-устройства, /// в котором нужно установить состояние реле</param> /// <param name="addressCoil">Адрес целевого реле</param> /// <param name="state">Состояние реле: 0х00FF-ON, 0x0000-OFF</param> public Message.Result WriteSingleCoil(byte addressSlave, UInt16 addressCoil, ref State state) { string message; Modbus.OSIModel.Message.Message request, answer; Modbus.OSIModel.Message.Result result; // Проверяем состояние сервера if (_flgBusy == true) { return result = new Message.Result(Error.IllegalReguest, String.Format("Попытка выполнить запрос (код функции 0x5) к серверу {0}, во время выполнения предыдущего", Name), null, null); //throw new Exception(String.Format( // "Попытка выполнить запрос (код функции 0x5) к серверу {0}, во время выполнения предыдущего", // Name)); } else { // Данный запрос не может быть широковещательным if (addressSlave == 0) { message = "Функция с кодом 0х5, не может быть отправлена как широковещательный запрос"; throw new Exception(message); } else { // Устанавливаем начало транзакции StartTransaction(); // Подготавливаем данные List<byte> array = new List<byte>(); array.AddRange(Modbus.Convert.ConvertToBytes(addressCoil)); //Byte[] state; //if (ValueCoil == Modbus.Device.CoilState.ON) //{ // state = new byte[2] { 0xFF, 0x00 }; // array.AddRange(state); //} //else //{ // state = new byte[2] { 0x00, 0x00 }; // array.AddRange(state); //} array.AddRange(Modbus.Convert.StateToArray(state)); // Отправляем запрос request = new Modbus.OSIModel.Message.Message(addressSlave, 0x5, array.ToArray()); // Отправляем запрос Modbus.OSIModel.DataLinkLayer.RequestError error = _dataLinkObject.SendMessage(request, out answer); switch (error) { case Modbus.OSIModel.DataLinkLayer.RequestError.NoError: { // Разбираем сообщение на предмет ошибок if (IsError(request, answer, out result)) { // Ошибка была break; } else { // Ошибки нет возвращаем результат выполнения запроса // Проверяем длину данных if (answer.PDUFrame.Data.Length == 4) { // Длина корректана проверяем // адрес дискретного входа List<Byte> arr = new List<byte>(); arr.Add(answer.PDUFrame.Data[0]); arr.Add(answer.PDUFrame.Data[1]); UInt16 value = Convert.ConvertToUInt16(arr.ToArray()); if (value == addressCoil) { // Адрес верный // получаем новое состояние реле arr.Clear(); arr.Add(answer.PDUFrame.Data[2]); arr.Add(answer.PDUFrame.Data[3]); state = Convert.ValueToState(arr.ToArray()); result = new Modbus.OSIModel.Message.Result(Error.NoError, String.Empty, request, answer); } else { // Адрес дискретного входа отличается от адреса в запросе result = new Modbus.OSIModel.Message.Result(Error.DataFormatError, String.Format( "Адрес реле в запросе {0} не соответствует адерсу реле в ответе {1}", addressCoil, value), request, answer); } } else { // Некорректная длина данных в ответе result = new Modbus.OSIModel.Message.Result(Error.DataFormatError, String.Format( "Неверная длина данных {0} в ответе, а ожидается 4", answer.PDUFrame.Data.Length), request, answer); } break; } } case Modbus.OSIModel.DataLinkLayer.RequestError.TimeOut: { // Таймаут ответа result = new Modbus.OSIModel.Message.Result(Error.TimeOut, "Ответ не был получен в заданное время", request, null); break; } default: { // Ошибка уровня Datalink layer. result = new Modbus.OSIModel.Message.Result(Error.ReciveMessageError, error.ToString(), request, null); break; } } StopTransaction(); return result; } } }
//--------------------------------------------------------------------------- /// <summary> /// Функция 0x6. Записывает значение в одиночный регистр /// хранения в удалённом устройстве /// </summary> /// <param name="request">Запрос на выполнение операции</param> /// <param name="value">Записанное в устройство значение регистра</param> /// <returns>Результат выполнения запроса</returns> public Modbus.OSIModel.Message.Result WriteSingleRegister(Message.Message request, ref UInt16 value) { Modbus.OSIModel.Message.Message answer; Modbus.OSIModel.Message.Result result; // Проверяем состояние сервера if (_flgBusy == true) { value = 0; return result = new Message.Result(Error.IllegalReguest, String.Format("Попытка выполнить запрос (код функции 0x6) к серверу {0}, во время выполнения предыдущего", Name), null, null); //throw new Exception(String.Format( // "Попытка выполнить запрос (код функции 0x6) к серверу {0}, во время выполнения предыдущего", // Name)); } else { // Устанавливаем начало транзакции StartTransaction(); // Отправляем запрос Modbus.OSIModel.DataLinkLayer.RequestError error = _dataLinkObject.SendMessage(request, out answer); switch (error) { case Modbus.OSIModel.DataLinkLayer.RequestError.NoError: { // Разбираем сообщение на предмет ошибок if (IsError(request, answer, out result)) { // Ошибка была value = 0; break; } else { // Ошибки нет возвращаем результат выполнения запроса // Проверяем длину сообщения if (answer.PDUFrame.Data.Length != 4) { value = 0; result = new Message.Result(Error.DataFormatError, String.Format( "Длина ответного сообщения {0} не соответствет ожидаемой 4", answer.PDUFrame.Data.Length), request, answer); } else { // Проверяем адрес регистра в ответном сообщениии Byte[] arr = new Byte[2]; Array.Copy(answer.PDUFrame.Data, 0, arr, 0, 2); value = Modbus.Convert.ConvertToUInt16(arr); Array.Copy(request.PDUFrame.Data, 0, arr, 0, 2); UInt16 var = Modbus.Convert.ConvertToUInt16(arr); if (value != var) { result = new Message.Result(Error.DataFormatError, String.Format( "Адрес регистра {0} в запросе не совпадает с аресом в ответном сообщении {1}", var, value), request, answer); } else { Array.Copy(answer.PDUFrame.Data, 2, arr, 0, 2); value = Modbus.Convert.ConvertToUInt16(arr); result = new Modbus.OSIModel.Message.Result(Error.NoError, String.Empty, request, answer); } } break; } } case Modbus.OSIModel.DataLinkLayer.RequestError.TimeOut: { // Таймаут ответа value = 0; result = new Modbus.OSIModel.Message.Result(Error.TimeOut, "Ответ не был получен в заданное время", request, null); break; } default: { // Ошибка уровня Datalink layer. value = 0; result = new Modbus.OSIModel.Message.Result(Error.ReciveMessageError, error.ToString(), request, null); break; } } StopTransaction(); return result; } }
/// <summary> /// Функция 0х3. Читает holding-регистры /// в удалённом устройстве /// </summary> /// <param name="request">Запрос на чтение регистров</param> /// <param name="values">Прочитанные занчения регистров</param> /// <returns>Результат выполения операции</returns> public Message.Result ReadHoldingRegisters( Message.Message request, out UInt16[] values) { Modbus.OSIModel.Message.Message answer; Modbus.OSIModel.Message.Result result; Byte[] arr = new byte[2]; Array.Copy(request.PDUFrame.Data, 2, arr, 0, 2); UInt16 quantity = Modbus.Convert.ConvertToUInt16(arr); // Проверяем состояние сервера if (_flgBusy == true) { throw new Exception(String.Format( "Попытка выполнить запрос (код функции 0x3) к серверу {0}, во время выполнения предыдущего", Name)); } else { // Устанавливаем начало транзакции StartTransaction(); // Отправляем запрос Modbus.OSIModel.DataLinkLayer.RequestError error = _dataLinkObject.SendMessage(request, out answer); switch (error) { case Modbus.OSIModel.DataLinkLayer.RequestError.NoError: { // Разбираем сообщение на предмет ошибок if (IsError(request, answer, out result)) { // Ошибка была values = null; break; } else { // Ошибки нет возвращаем результат выполнения запроса values = new ushort[quantity]; // Проверяем количество байт принятых в ответном сообщении // Их должно быть в два раза больше чем количество регистров // для чтения if (quantity == (answer.PDUFrame.Data[0] / 2)) { // Количество байт в порядке. Получаем прочитанные значения // holding-регистров for (int i = 0; i < values.Length; i++) { values[i] = answer.PDUFrame.Data[i * 2 + 1]; // старший байт регистра values[i] = (UInt16)(values[i] << 8); // младший байт регистра values[i] = (UInt16)(values[i] | answer.PDUFrame.Data[i * 2 + 2]); } result = new Modbus.OSIModel.Message.Result(Error.NoError, String.Empty, request, answer); } else { values = null; result = new Modbus.OSIModel.Message.Result(Error.DataFormatError, "Поле данных ответа содержит некорректные данные", request, answer); } break; } } case Modbus.OSIModel.DataLinkLayer.RequestError.TimeOut: { // Таймаут ответа values = null; result = new Modbus.OSIModel.Message.Result(Error.TimeOut, "Ответ не был получен в заданное время", request, null); break; } default: { // Ошибка уровня Datalink layer. values = null; result = new Modbus.OSIModel.Message.Result(Error.ReciveMessageError, error.ToString(), request, null); break; } } StopTransaction(); return result; } }
//--------------------------------------------------------------------------- /// <summary> /// Функция 0х4. Читает входные регистры /// </summary> /// <param name="AddressSlave">адрес удалённого slave-устройства, /// из которого нужно получить данные</param> /// <param name="StartingAddress">Адрес начального входного регистра</param> /// <param name="Quantity">Количество регистров для чтения 1...125</param> /// <param name="values">Прочатанные значения регистров</param> /// <returns>Результат выполнения операции</returns> public Message.Result ReadInputRegisters(byte AddressSlave, UInt16 StartingAddress, UInt16 Quantity, out UInt16[] values) { string message; Modbus.OSIModel.Message.Message request; Modbus.OSIModel.Message.Message answer; Modbus.OSIModel.Message.Result result; // Данный запрос не может быть широковещательным if (AddressSlave == 0) { message = "Функция с кодом 0х4, не может быть широковещательным запросом"; throw new ArgumentException(message, "AddressSlave"); } else { if ((Quantity > 0) && (Quantity <= 125)) { // Подготавливаем данные List<byte> array = new List<byte>(); array.AddRange(Modbus.Convert.ConvertToBytes(StartingAddress)); array.AddRange(Modbus.Convert.ConvertToBytes(Quantity)); // Формируем запрос request = new Modbus.OSIModel.Message.Message(AddressSlave, 0x4, array.ToArray()); } else { message = String.Format("Количество регистров для чтения {0}, должно быть от 1...125", Quantity); throw new ArgumentOutOfRangeException("quantity", message); } } // Проверяем состояние сервера if (_flgBusy == true) { throw new Exception(String.Format( "Попытка выполнить запрос (код функции 0x4) к серверу {0}, во время выполнения предыдущего", Name)); } else { // Устанавливаем начало транзакции StartTransaction(); // Отправляем запрос Modbus.OSIModel.DataLinkLayer.RequestError error = _dataLinkObject.SendMessage(request, out answer); switch (error) { case Modbus.OSIModel.DataLinkLayer.RequestError.NoError: { // Разбираем сообщение на предмет ошибок if (IsError(request, answer, out result)) { // Ошибка была values = null; break; } else { // Ошибки нет возвращаем результат выполнения запроса values = new ushort[Quantity]; // Проверяем количество байт принятых в ответном сообщении // Их должно быть в два раза больше чем количество регистров // для чтения if (Quantity == (answer.PDUFrame.Data[0] / 2)) { // Количество байт в порядке. Получаем прочитанные значения // входных регистров for (int i = 0; i < values.Length; i++) { values[i] = answer.PDUFrame.Data[i * 2 + 1]; // старший байт регистра values[i] = (UInt16)(values[i] << 8); // младший байт регистра values[i] = (UInt16)(values[i] | answer.PDUFrame.Data[i * 2 + 2]); } result = new Modbus.OSIModel.Message.Result(Error.NoError, String.Empty, request, answer); } else { values = null; result = new Modbus.OSIModel.Message.Result(Error.DataFormatError, "Поле данных ответа содержит некорректные данные", request, answer); } break; } } case Modbus.OSIModel.DataLinkLayer.RequestError.TimeOut: { // Таймаут ответа values = null; result = new Modbus.OSIModel.Message.Result(Error.TimeOut, "Ответ не был получен в заданное время", request, null); break; } default: { // Ошибка уровня Datalink layer. values = null; result = new Modbus.OSIModel.Message.Result(Error.ReciveMessageError, error.ToString(), request, null); break; } } StopTransaction(); return result; } }
/// <summary> /// Функция 0x2. Читает дискретные входы /// в удалённом устройстве /// </summary> /// <param name="AddressSlave">адрес удалённого slave-устройства, /// из которого нужно получить данные</param> /// <param name="StartingAddress">Адрес начального дискретного входа</param> /// <param name="Quantity">Количество дискретных входов для чтения 1...2000</param> /// <param name="inputs">Состояния прочитанных дискретных входов</param> /// <returns>Результат выполения операции</returns> public Message.Result ReadDiscreteInputs(byte AddressSlave, UInt16 StartingAddress, UInt16 Quantity, out State[] inputs) { Modbus.OSIModel.Message.Message request, answer; Modbus.OSIModel.Message.Result result; inputs = null; String message; // Данный запрос не может быть широковещательным if (AddressSlave == 0) { message = "Функция с кодом 0х2, не может быть широковещательным запросом"; throw new ArgumentException(message, "addressSlave"); } // Подготавливаем данные List<byte> array = new List<byte>(); array.AddRange(Modbus.Convert.ConvertToBytes(StartingAddress)); array.AddRange(Modbus.Convert.ConvertToBytes(Quantity)); request = new Modbus.OSIModel.Message.Message(AddressSlave, 0x2, array.ToArray()); // Выполняем запрос while (_flgBusy) { // Если идёт транзакция ждём окончания } // Устанавливаем начало транзакции StartTransaction(); // Отправляем запрос Modbus.OSIModel.DataLinkLayer.RequestError error = _dataLinkObject.SendMessage(request, out answer); switch (error) { case Modbus.OSIModel.DataLinkLayer.RequestError.NoError: { // Разбираем сообщение на предмет ошибок if (IsError(request, answer, out result)) { // Ошибка была break; } else { // Ошибки нет возвращаем результат выполнения запроса // Проверяем содержимое посылки // Рассчитываем необходимое количество байт для передачи состояний дискретных входов int length = Quantity / 8; if (Quantity % 8 != 0) { ++length; } if ((int)answer.PDUFrame.Data[0] != length) { result = new Message.Result( Error.DataFormatError, String.Format("Количество байт {0} в сообщении не равно требуемому {1} для передачи состояний реле в количестве {2}", answer.PDUFrame.Data[0], length, Quantity), request, answer); } else { Byte data, temp; inputs = new State[Quantity]; for (int i = 0; i < answer.PDUFrame.Data[0]; i++) { data = answer.PDUFrame.Data[i + 1]; for (int y = 0; y < 8; y++) { if (8 * i + y < Quantity) { temp = (Byte)(data >> y); if ((temp & 0x01) == 0x01) { inputs[(8 * i + y)] = State.On; } else { inputs[(8 * i + y)] = State.Off; } } } } } result = new Message.Result(Error.NoError, String.Empty, request, answer); break; } } case Modbus.OSIModel.DataLinkLayer.RequestError.TimeOut: { // Таймаут ответа result = new Modbus.OSIModel.Message.Result(Error.TimeOut, "Ответ не был получен в заданное время", request, null); break; } default: { // Ошибка уровня Datalink layer. result = new Modbus.OSIModel.Message.Result(Error.ReciveMessageError, error.ToString(), request, null); break; } } StopTransaction(); return result; }
//--------------------------------------------------------------------------- /// <summary> /// Функция 0х1. Чтение реле /// </summary> /// <param name="addressSlave">адрес удалённого slave-устройства, /// из которого нужно получить данные</param> /// <param name="startingAddress">Адрес начального реле</param> /// <param name="quantity">Количество реле для чтения 1...2000</param> /// <param name="answer">Ответное сообщение</param> /// <param name="coils">Прочитанные состояния реле</param> /// <returns>Результат выполнения операции</returns> public Modbus.OSIModel.Message.Result ReadCoils( Modbus.OSIModel.Message.Message request, out State[] coils) { Modbus.OSIModel.Message.Message answer; Modbus.OSIModel.Message.Result result; Byte[] arrTemp = new Byte[2]; Array.Copy(request.PDUFrame.Data, 2, arrTemp, 0, 2); UInt16 quantity = Modbus.Convert.ConvertToUInt16(arrTemp); coils = new State[quantity]; while (_flgBusy) { // Если идёт транзакция ждём окончания } // Устанавливаем начало транзакции StartTransaction(); // Отправляем запрос Modbus.OSIModel.DataLinkLayer.RequestError error = _dataLinkObject.SendMessage(request, out answer); switch (error) { case Modbus.OSIModel.DataLinkLayer.RequestError.NoError: { // Разбираем сообщение на предмет ошибок if (IsError(request, answer, out result)) { // Ошибка была break; } else { // Ошибки нет возвращаем результат выполнения запроса // Проверяем содержимое посылки // Рассчитываем необходимое количество байт для передачи состояний реле int length = quantity / 8; if (quantity % 8 != 0) { ++length; } if ((int)answer.PDUFrame.Data[0] != length) { result = new Message.Result(Error.DataFormatError, String.Format( "Количество байт {0} в сообщении не равно требуемому {1} для передачи состояний реле в количестве {2}", answer.PDUFrame.Data[0], length, quantity), request, answer); } else { Byte data, temp; for (int i = 0; i < answer.PDUFrame.Data[0]; i++) { data = answer.PDUFrame.Data[i + 1]; for (int y = 0; y < 8; y++) { if (8 * i + y < quantity) { temp = (Byte)(data >> y); if ((temp & 0x01) == 0x01) { coils[(8 * i + y)] = State.On; } else { coils[(8 * i + y)] = State.Off; } } } } } result = new Message.Result(Error.NoError, String.Empty, request, answer); break; } } case Modbus.OSIModel.DataLinkLayer.RequestError.TimeOut: { // Таймаут ответа result = new Modbus.OSIModel.Message.Result(Error.TimeOut, "Ответ не был получен в заданное время", request, null); break; } default: { // Ошибка уровня Datalink layer. result = new Modbus.OSIModel.Message.Result(Error.ReciveMessageError, error.ToString(), request, null); break; } } StopTransaction(); return result; }
/// <summary> /// Метод отсылает запрос с определённым пользователем /// кодом и данными. /// </summary> /// <param name="address">Адрес slave-устройства</param> /// <param name="code">Код функции</param> /// <param name="data">Данные сообщения</param> /// <param name="Answer">Ответное сообщение</param> /// <returns>Если запрос прошёл успешно возвращается true</returns> public Message.Result SendUserDefinedRequest(Byte address, Byte code, Byte[] data) { Modbus.OSIModel.Message.Message request, answer; Modbus.OSIModel.Message.Result result; // Проверяем состояние сервера if (_flgBusy == true) { throw new Exception(String.Format( "Попытка выполнить запрос User defined к серверу {0}, во время выполнения предыдущего", Name)); } else { StartTransaction(); request = new Modbus.OSIModel.Message.Message(address, code, data); // Отправляем запрос Modbus.OSIModel.DataLinkLayer.RequestError error = _dataLinkObject.SendMessage(request, out answer); switch (error) { case Modbus.OSIModel.DataLinkLayer.RequestError.NoError: { // Разбираем сообщение на предмет ошибок if (IsError(request, answer, out result)) { // Ошибка была break; } else { // Ошибки нет возвращаем результат выполнения запроса result = new Modbus.OSIModel.Message.Result(Error.NoError, String.Empty, request, answer); break; } } case Modbus.OSIModel.DataLinkLayer.RequestError.TimeOut: { // Таймаут ответа result = new Modbus.OSIModel.Message.Result(Error.TimeOut, "Ответ не был получен в заданное время", request, null); break; } default: { // Ошибка уровня Datalink layer. result = new Modbus.OSIModel.Message.Result(Error.ReciveMessageError, error.ToString(), request, null); break; } } StopTransaction(); return result; } }
//--------------------------------------------------------------------------- /// <summary> /// Функция 16 (0х10). Записывает значения массива регистров /// </summary> /// <param name="AddressSlave">Адрес удалённого slave-устройства, /// в котором необходимо установить значения последовательности /// регистров</param> /// <param name="StartingAddress">Адрес первого регистра</param> /// <param name="value">Количество, значения регистров 1...123</param> /// <returns>Результат выполнения операции</returns> public Modbus.OSIModel.Message.Result WriteMultipleRegisters(byte AddressSlave, UInt16 StartingAddress, UInt16[] value) { String message; Message.Message request; Modbus.OSIModel.Message.Message answer; Modbus.OSIModel.Message.Result result; if ((value.Length == 0) && (value.Length > 124)) { message = String.Format( "Длина блока регистров {0} выходит за пределы диапазона 1...124", value.Length); throw new ArgumentOutOfRangeException("Quantity", message); } // Проверяем выход блока данных за граници диапазона допустимых адресов if ((StartingAddress + value.Length) > 0xFFFF) { message = String.Format( "Длина блока регистров {0} больше допустимой величины 0xFFFF", (StartingAddress + value.Length)); throw new ArgumentException(message, "Quantity"); } // Формируем запрос List<Byte> data = new List<byte>(); data.AddRange(Convert.ConvertToBytes(StartingAddress)); // Адрес первого регистра в блоке data.AddRange(Convert.ConvertToBytes((UInt16)value.Length)); // Длина блока регистров data.Add((Byte)(value.Length * 2)); // Количество байт // Значения регистров for (int i = 0; i < value.Length; i++) { data.AddRange(Convert.ConvertToBytes(value[i])); } Message.PDU pdu = new Message.PDU(0x10, data.ToArray()); request = new Message.Message(AddressSlave, pdu); // Проверяем состояние сервера if (_flgBusy == true) { return result = new Message.Result(Error.IllegalReguest, String.Format("Попытка выполнить запрос (код функции 0x10) к серверу {0}, во время выполнения предыдущего", Name), null, null); } else { // Устанавливаем начало транзакции StartTransaction(); // Отправляем запрос Modbus.OSIModel.DataLinkLayer.RequestError error = _dataLinkObject.SendMessage(request, out answer); switch (error) { case Modbus.OSIModel.DataLinkLayer.RequestError.NoError: { // Разбираем сообщение на предмет ошибок if (IsError(request, answer, out result)) { // Ошибка была break; } else { // Ошибки нет возвращаем результат выполнения запроса // Проверяем длину сообщения if (answer.PDUFrame.Data.Length != 4) { result = new Message.Result(Error.DataFormatError, String.Format( "Длина ответного сообщения {0} не соответствет ожидаемой 4", answer.PDUFrame.Data.Length), request, answer); } else { // Проверяем адрес начального регистра в ответном сообщениии Byte[] arr = new Byte[2]; Array.Copy(answer.PDUFrame.Data, 0, arr, 0, 2); UInt16 var = Modbus.Convert.ConvertToUInt16(arr); if (var != StartingAddress) { result = new Message.Result(Error.DataFormatError, String.Format( "Адрес начального регистра {0} в запросе не совпадает с адресом в ответном сообщении {1}", StartingAddress, var), request, answer); } else { // Проверяем длину блока регистров Array.Copy(answer.PDUFrame.Data, 2, arr, 0, 2); var = Modbus.Convert.ConvertToUInt16(arr); if (var != value.Length) { result = new Message.Result(Error.DataFormatError, String.Format( "Длина блока регистров {0} в запросе не совпадает с длиной блока в ответном сообщении {1}", value.Length, var), request, answer); } else { // Ответ корректен result = new Modbus.OSIModel.Message.Result(Error.NoError, String.Empty, request, answer); } } } break; } } case Modbus.OSIModel.DataLinkLayer.RequestError.TimeOut: { // Таймаут ответа result = new Modbus.OSIModel.Message.Result(Error.TimeOut, "Ответ не был получен в заданное время", request, null); break; } default: { // Ошибка уровня Datalink layer. result = new Modbus.OSIModel.Message.Result(Error.ReciveMessageError, error.ToString(), request, null); break; } } StopTransaction(); return result; } }
//--------------------------------------------------------------------------- /// <summary> /// Метод разбирает полученое сообщение и если /// код функции содержит признак ошибки (единица в старшем разряде) /// разбирает сообщение и формирует ответ (результат запроса к устройству) /// Если ошибок не было возвращается false и result == null, если ошибка /// присутствует возвращается true и result != null/ /// </summary> /// <param name="request">Запрос</param> /// <param name="answer">Ответное сообщение</param> /// <param name="result">Результат разбора сообщения</param> /// <returns>Результат выполнения запроса: ошибка - true, /// нет ошибок - false</returns> private Boolean IsError( Modbus.OSIModel.Message.Message request, Modbus.OSIModel.Message.Message answer, out Modbus.OSIModel.Message.Result result) { // Разбираем сообщение if ((answer.PDUFrame.Function & 0x80) == 0x80) { // Устройство не смогло выполнить запрос, определяем причину switch (answer.PDUFrame.Data[0]) { case (Byte)Error.Acknowledge: { result = new Modbus.OSIModel.Message.Result(Error.Acknowledge, "Подчиненный принял запрос и обрабатывает его, но это требует много времени. " + "Этот ответ предохраняет главного от генерации ошибки таймаута. " + "Главный может выдать команду Poll Program Complete для обнаружения" + "завершения обработки команды.", request, answer); break; } case (Byte)Error.IllegalDataAddress: { result = new Modbus.OSIModel.Message.Result(Error.IllegalDataAddress, "Адрес данных указанный в запросе не доступен данному подчиненному.", request, answer); break; } case (Byte)Error.IllegalDataValue: { result = new Modbus.OSIModel.Message.Result(Error.IllegalDataValue, "Величина содержащаяся в поле данных запроса является не допустимой величиной для подчиненного.", request, answer); break; } case (Byte)Error.IllegalFunction: { result = new Modbus.OSIModel.Message.Result(Error.IllegalFunction, "Принятый код функции не может быть обработан на подчиненном.", request, answer); break; } case (Byte)Error.MemoryParityError: { result = new Modbus.OSIModel.Message.Result(Error.MemoryParityError, "Подчиненный пытается читать расширенную память, но обнаружил ошибку паритета. Главный может повторить запрос, но обычно в таких случаях требуется ремонт.", request, answer); break; } case (Byte)Error.NegativeAcknowledge: { result = new Modbus.OSIModel.Message.Result(Error.NegativeAcknowledge, "Подчиненный не может выполнить программную функцию, принятую в запросе. Этот код возвращается для неудачного программного запроса, использующего функции с номерами 13 или 14. Главный должен запросить диагностическую информацию или информацию обошибках с подчиненного.", request, answer); break; } case (Byte)Error.SlaveDeviceBusy: { result = new Modbus.OSIModel.Message.Result(Error.SlaveDeviceBusy, "Подчиненный занят обработкой команды. Главный должен повторить сообщение позже, когда подчиненный освободится.", request, answer); break; } case (Byte)Error.SlaveDeviceFailure: { result = new Modbus.OSIModel.Message.Result(Error.SlaveDeviceFailure, "Невосстанавливаемая ошибка имела место пока подчиненный пытался выполнить затребованное действие.", request, answer); break; } default: { result = new Modbus.OSIModel.Message.Result(Error.UnknownError, "Неизвестная ошибка", request, answer); break; } } return true; } else { // Ошибок нет result = null; return false; } }