//--------------------------------------------------------------------------- /// <summary> /// Отправляет сообщение с запросом /// </summary> /// <param name="requst">Запрос</param> /// <param name="answer">Ответ</param> /// <returns>Результат выполнения операции</returns> public RequestError SendMessage( Modbus.OSIModel.Message.Message requst, out Modbus.OSIModel.Message.Message answer) { RequestError error; Byte[] reply; Byte[] tempArray; error = SendMessage(requst.Address, requst.PDUFrame.Function, requst.PDUFrame.Data, out reply); if (error == RequestError.NoError) { tempArray = new Byte[reply.Length - 1]; Array.Copy(reply, 1, tempArray, 0, (reply.Length - 1)); answer = new Modbus.OSIModel.Message.Message(requst.Address, reply[0], tempArray); } else { answer = null; } return(error); }
//--------------------------------------------------------------------------- /// <summary> /// Отправляет сообщение с запросом /// </summary> /// <param name="requst">Запрос</param> /// <param name="answer">Ответ</param> /// <returns>Результат выполнения операции</returns> public RequestError SendMessage( Modbus.OSIModel.Message.Message requst, out Modbus.OSIModel.Message.Message answer) { RequestError error; Byte[] reply; Byte[] tempArray; error = SendMessage(requst.Address, requst.PDUFrame.Function, requst.PDUFrame.Data, out reply); if (error == RequestError.NoError) { tempArray = new Byte[reply.Length - 1]; Array.Copy(reply, 1, tempArray, 0, (reply.Length - 1)); answer = new Modbus.OSIModel.Message.Message(requst.Address, reply[0], tempArray); } else { answer = null; } return error; }
//--------------------------------------------------------------------------- /// <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> /// Функция 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> /// Функция 0х3. Формирует сообщение для организации запроса чтения /// holding-регистров в физическом устройстве /// </summary> /// <param name="addressSlave">адрес удалённого slave-устройства, /// из которого нужно получить данные</param> /// <param name="startingAddress">Адрес начального holding-регистра</param> /// <param name="quantity">Количество holding-регистров для чтения 1...125</param> /// <returns>Результат выполения операции</returns> public static Message.Message ReadHoldingRegisters(byte addressSlave, UInt16 startingAddress, UInt16 quantity) { string message; Modbus.OSIModel.Message.Message request; // Данный запрос не может быть широковещательным if (addressSlave == 0) { message = "Функция с кодом 0х3, не может быть широковещательным запросом"; 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, 0x3, array.ToArray()); } else { message = String.Format("Количество регистров для чтения {0}, должно быть от 1...125", quantity); throw new ArgumentOutOfRangeException("quantity", message); } } return request; }
/// <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( byte addressSlave, UInt16 startingAddress, UInt16 quantity, out State[] coils) { Modbus.OSIModel.Message.Message request; // Подготавливаем данные 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, 0x1, array.ToArray()); // Выполняем запрос Message.Result result = ReadCoils(request, out coils); 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> /// Функция 0x6. Формирует запрос на запись регистра хранения /// в физическом устройстве /// </summary> /// <param name="addressSlave">адрес удалённого slave-устройства, /// в котором нужно записать регистр хранения</param> /// <param name="addressRegister">адерс регистра хранения</param> /// <param name="value">значение регистра</param> /// <returns>Modus-запрос</returns> public static Message.Message WriteSingleRegister(byte addressSlave, UInt16 addressRegister, UInt16 value) { Modbus.OSIModel.Message.Message request; // Подготавливаем данные List<byte> array = new List<byte>(); array.AddRange(Modbus.Convert.ConvertToBytes(addressRegister)); array.AddRange(Modbus.Convert.ConvertToBytes(value)); // Возвращаем запрос request = new Modbus.OSIModel.Message.Message(addressSlave, 0x6, array.ToArray()); return request; }