//--------------------------------------------------------------------------- Result INetworkFunctions.ReadHoldingRegisters(Message.Message request) { Message.Result result; Message.Message answer; Message.PDU pdu; String message; if (request.Address == 0) { // Ошибка. Данная команда не может быть широковещательная message = "Широковещательный запрос на выполнение функции 0x03 невозможен"; result = new Message.Result(Error.RequestError, message, request, null); } else { // Проверяем длину PDU (должна равнятся 5 байтам) if (request.PDUFrame.ToArray().Length != 5) { // Длина сообщения не верная String mes = String.Format( "Длина PDU-фрайма равна в запросе 0x3 равна {0} байт. Должна быть 5 байт", request.PDUFrame.ToArray().Length); result = new Message.Result(Error.DataFormatError, mes, request, null); } else { // Разбираем сообщение Byte[] array = new Byte[2]; // Получаем адрес первого регистра входа Array.Copy(request.PDUFrame.Data, 0, array, 0, 2); UInt16 address = Modbus.Convert.ConvertToUInt16(array); // Получаем количесво регистров для чтения Array.Copy(request.PDUFrame.Data, 2, array, 0, 2); UInt16 quantity = Modbus.Convert.ConvertToUInt16(array); if ((quantity == 0) || (quantity > 125)) { message = String.Format("Количество регистров для чтения в запросе {0}, а должно быть 1...125", quantity); pdu = new Message.PDU(0x83, new Byte[] { 0x03 }); answer = new Message.Message(_Address, pdu); // Отправляем сообщение SendResponse(answer); result = new Message.Result(Error.IllegalDataValue, message, request, answer); } else { // Выполняем запрос. Проверяем доступность в // системе регистров в указанном диапазоне адресов for (int i = 0; i < quantity; i++) { // Если регистр не существует в системе формируем ответ // c исключение if (HoldingRegisters.Contains(System.Convert.ToUInt16(address + i)) == false) { // Формируем ответ с исключение 2 pdu = new Message.PDU(0x83, new Byte[] { 0x02 }); answer = new Message.Message(_Address, pdu); message = String.Format("Регистр с адресом {0} не существует", (address + i)); result = new Message.Result(Error.IllegalDataAddress, message, request, answer); // Отправляем ответ мастеру SendResponse(answer); return result; } } // Все регистры найдены формируем ответное сообщение Byte[] temp; List<Byte> data = new List<byte>(); data.Add(System.Convert.ToByte((quantity * 2))); for (int i = 0; i < quantity; i++) { temp = Modbus.Convert.ConvertToBytes(HoldingRegisters[i].Value); data.AddRange(temp); } pdu = new Message.PDU(); pdu.Function = 0x3; pdu.AddDataBytesRange(data.ToArray()); answer = new Message.Message(_Address, pdu); result = new Message.Result(Error.NoError, String.Empty, request, answer); // Отправляем ответ мастеру SendResponse(answer); } } } return result; }
/// <summary> /// Функция 0х3. Читает holding-регистры /// в удалённом устройстве /// </summary> /// <param name="AddressSlave">Адрес подчинённого устройства</param> /// <param name="StartingAddress">Адрес первого регистра в блоке</param> /// <param name="Quantity">Длина блока регистров хранения для чтения</param> /// <param name="values">Значения прочитанных регистров</param> /// <returns>Результат выполения операции</returns> public Message.Result ReadHoldingRegisters( byte AddressSlave, ushort StartingAddress, ushort Quantity, out ushort[] values) { Message.PDU frame = new Message.PDU(); frame.Function = 0x3; frame.AddDataBytesRange(Convert.ConvertToBytes(StartingAddress)); frame.AddDataBytesRange(Convert.ConvertToBytes(Quantity)); Message.Message request = new Message.Message(AddressSlave, frame); return ReadHoldingRegisters(request, out values); }
//--------------------------------------------------------------------------- #endregion // !!! Необоходимо сделать статическим методами, для того что бы уменьшить // размер устройтва в ОЗУ. #region INetworkFunctions Members //--------------------------------------------------------------------------- Result INetworkFunctions.ReadCoils(Modbus.OSIModel.Message.Message request) { Message.Result result; Message.Message answer; PDU pdu; String message; if (request.Address == 0) { // Ошибка. Данная команда не может быть широковещательная message = "Широковещательный запрос на выполнение функции 0x01 невозможен"; result = new Message.Result(Error.RequestError, message, request, null); } else { // Проверяем длину PDU (должна равнятся 5 байтам) if (request.PDUFrame.ToArray().Length != 5) { // Длина сообщения не верная message = String.Format( "Длина PDU-фрайма в запросе {0}. Должна быть 5 байт", request.PDUFrame.ToArray()); // Ответное сообщение не отсылается result = new Message.Result(Error.DataFormatError, message, request, null); } else { // Разбираем сообщение Byte[] array = new Byte[2]; // Получаем адрес первого реле Array.Copy(request.PDUFrame.Data, 0, array, 0, 2); UInt16 address = Modbus.Convert.ConvertToUInt16(array); // Получаем количесво реле для чтения Array.Copy(request.PDUFrame.Data, 2, array, 0, 2); UInt16 quantity = Modbus.Convert.ConvertToUInt16(array); if ((quantity == 0) || (quantity > 2000)) { message = String.Format( "Количество реле для чтения в запросе {0}, а должно быть 1...2000", quantity); pdu = new Message.PDU(0x81, new Byte[] { 0x03 }); answer = new Modbus.OSIModel.Message.Message(_Address, pdu); // Отправляем сообщение SendResponse(answer); result = new Message.Result(Error.IllegalDataValue, message, request, answer); } else { // Выполняем запрос. Проверяем доступность в // системе реле в указанном диапазоне адресов for (int i = 0; i < quantity; i++) { // Проверяем существует ли реле с указанным адресом. // Если реле не существует в системе формируем ответ // c исключение if (Coils.Contains(System.Convert.ToUInt16(address + i)) == false) { // Формируем ответ с исключение 2 answer = new Modbus.OSIModel.Message.Message(Address, new PDU(0x81, new Byte[] { 0x2 })); // Отправляем ответ мастеру SendResponse(answer); result = new Message.Result(Error.IllegalDataAddress, String.Format("Реле с адресом {0} не существует", System.Convert.ToUInt16(address + i)), request, answer); return result; } } // Все реле найдены формируем ответное сообщение int totalBytes = quantity % 8; if (totalBytes == 0) { totalBytes = quantity / 8; } else { totalBytes = 1 + (quantity / 8); } Byte[] data = new Byte[totalBytes]; int number = 0; int index = 0; for (int i = 0; i < quantity; i++) { data[index] = (Byte)(data[index] | (Byte)(Modbus.Convert.BooleanToBit( Coils[System.Convert.ToUInt16(address + i)].Value) << number)); if (++number > 7) { number = 0; ++index; } } pdu = new Message.PDU(); pdu.Function = 0x01; pdu.AddDataByte((byte)totalBytes); // Добавляем количество байт с состояниями реле pdu.AddDataBytesRange(data); // Добавляем байты с состояниями реле answer = new Modbus.OSIModel.Message.Message(Address, pdu); // Отправляем ответ мастеру SendResponse(answer); result = new Message.Result(Error.NoError, String.Empty, request, answer); } } } return result; }
//--------------------------------------------------------------------------- Result INetworkFunctions.ReadDiscreteInputs(Message.Message request) { Message.Result result; Message.Message answer; Message.PDU pdu; String message; if (request.Address == 0) { // Ошибка. Данная команда не может быть широковещательная message = "Широковещательный запрос на выполнение функции 0x02 невозможен"; result = new Message.Result(Error.RequestError, message, request, null); } else { // Проверяем длину PDU (должна равнятся 5 байтам) if (request.PDUFrame.ToArray().Length != 5) { // Длина сообщения не верная String mes = String.Format( "Длина PDU-фрайма равна в запросе 0x2 равна {0} байт. Должна быть 5 байт", request.PDUFrame.ToArray().Length); result = new Message.Result(Error.DataFormatError, mes, request, null); Debug.WriteLine(mes); } else { // Разбираем сообщение Byte[] array = new Byte[2]; // Получаем адрес первого дискретного входа Array.Copy(request.PDUFrame.Data, 0, array, 0, 2); UInt16 address = Modbus.Convert.ConvertToUInt16(array); // Получаем количесво дискретных входов для чтения Array.Copy(request.PDUFrame.Data, 2, array, 0, 2); UInt16 quantity = Modbus.Convert.ConvertToUInt16(array); if ((quantity == 0) || (quantity > 2000)) { message = String.Format("Количество дискретных входов для чтения в запросе {0}, а должно быть 1...2000", quantity); pdu = new Message.PDU(0x82, new Byte[] { 0x03 }); answer = new Modbus.OSIModel.Message.Message(_Address, pdu); // Отправляем сообщение SendResponse(answer); result = new Message.Result(Error.IllegalDataValue, message, request, answer); } else { // Выполняем запрос. Проверяем доступность в // системе дискретных входов в указанном диапазоне адресов //DiscreteInput[] inputs = new DiscreteInput[quantity]; for (int i = 0; i < quantity; i++) { //inputs[i] = _discretesInputs.Find((UInt16)(address + i)); if (DiscretesInputs.Contains(System.Convert.ToUInt16(address + i)) == false) { // Если дискретный вход не существует в системе формируем ответ // c исключением 2 pdu = new Message.PDU(0x82, new Byte[] { 0x02 }); answer = new Message.Message(_Address, pdu); message = String.Format("Дискретный вход с адресом {0} не существует", (address + i)); result = new Message.Result(Error.IllegalDataAddress, message, request, answer); // Отправляем ответ мастеру SendResponse(answer); return result; } } // Все дискретные входы найдены формируем ответное сообщение int totalBytes = quantity % 8; if (totalBytes == 0) { totalBytes = quantity / 8; if (totalBytes == 0) { totalBytes++; } } else { totalBytes = 1 + (quantity / 8); } Byte[] data = new Byte[totalBytes]; int number = 0; int index = 0; for (int i = 0; i < quantity; i++) { data[index] = (Byte)(data[index] | (Byte)(Modbus.Convert.BooleanToBit(DiscretesInputs[address + i].Value) << number)); if (++number > 7) { number = 0; ++index; } } pdu = new Message.PDU(); pdu.Function = request.PDUFrame.Function; pdu.AddDataByte((Byte)totalBytes); pdu.AddDataBytesRange(data); answer = new Message.Message(_Address, pdu); result = new Message.Result(Error.NoError, String.Empty, request, answer); // Отправляем ответ мастеру SendResponse(answer); } } } return result; }
//--------------------------------------------------------------------------- Result INetworkFunctions.WriteMultipleCoils(Message.Message request) { Message.Result result; Message.Message answer; Message.PDU pdu; String message; // Проверяем длину PDU (должна быть не менее 7 байтам) if (request.PDUFrame.ToArray().Length < 7) { // Длина сообщения не верная String mes = String.Format( "Длина PDU-фрайма равна в запросе 0x0F равна {0} байт. Должна быть не менее 7 байт", request.PDUFrame.ToArray().Length); result = new Message.Result(Error.DataFormatError, mes, request, null); } else { // Разбираем сообщение Byte[] array = new Byte[2]; // Получаем адрес первого реле Array.Copy(request.PDUFrame.Data, 0, array, 0, 2); UInt16 address = Modbus.Convert.ConvertToUInt16(array); // Получаем количесво реле для записи Array.Copy(request.PDUFrame.Data, 2, array, 0, 2); UInt16 quantity = Modbus.Convert.ConvertToUInt16(array); // Получаем количество байт в пасылке Byte count = request.PDUFrame.Data[4]; int totalBytes = quantity % 8; if (totalBytes == 0) { totalBytes = quantity / 8; } else { totalBytes = 1 + (quantity / 8); } if ((quantity == 0) || (quantity > 0x7B0) || (totalBytes != count)) { message = String.Format("Количество реле для записи в запросе равно {0}, а должно быть 1...0x7B0", quantity); pdu = new Message.PDU((Byte)(0xF | 0x80), new Byte[] { 0x03 }); answer = new Message.Message(_Address, pdu); // Отправляем сообщение SendResponse(answer); result = new Message.Result(Error.IllegalDataValue, message, request, answer); } else { // Выполняем запрос. Проверяем доступность в // системе регистров в указанном диапазоне адресов for (int i = 0; i < quantity; i++) { // Если регистр не существует в системе формируем ответ // c исключение if (Coils.Contains(System.Convert.ToUInt16(address + i)) == false) { // Формируем ответ с исключение 2 pdu = new Message.PDU((Byte)(0x80 | 0x0F), new Byte[] { 0x02 }); answer = new Message.Message(Address, pdu); message = String.Format("Реле с адресом {0} не существует", (address + i)); result = new Message.Result(Error.IllegalDataAddress, message, request, answer); // Отправляем ответ мастеру SendResponse(answer); return result; } } // Все реле найдены, устанавливаем новые значения и // формируем ответное сообщение Byte status; // Устанавливаем новые значения в реле for (int i = 0; i < count; i++) { status = request.PDUFrame.Data[5 + i]; for (int y = 0; y < 8; y++) { totalBytes = i * 8 + y; if (totalBytes < quantity) { if (((status >> y) & 0x01) == 0) { Coils[System.Convert.ToUInt16(address + totalBytes)].Value = Modbus.Convert.ToBoolean(State.Off); //rows[totalBytes]["Value"] = Modbus.Convert.ToBoolean(State.Off); } else { Coils[System.Convert.ToUInt16(address + totalBytes)].Value = Modbus.Convert.ToBoolean(State.On); //rows[totalBytes]["Value"] = Modbus.Convert.ToBoolean(State.On); } } } } // Формируем ответ. List<Byte> data_ = new List<byte>(); data_.AddRange(Modbus.Convert.ConvertToBytes(address)); data_.AddRange(Modbus.Convert.ConvertToBytes(quantity)); pdu = new Message.PDU(); pdu.Function = 0x0F; pdu.AddDataBytesRange(data_.ToArray()); answer = new Message.Message(_Address, pdu); result = new Message.Result(Error.NoError, String.Empty, request, answer); // Отправляем ответ мастеру SendResponse(answer); // Формируем событие OnMasterChangedCoils(); } } return result; }
//--------------------------------------------------------------------------- Result INetworkFunctions.WriteMultipleRegisters(Message.Message request) { Message.Result result; Message.Message answer; Message.PDU pdu; String message; // Проверяем длину PDU (должна быть не менее 8 байтам) if (request.PDUFrame.ToArray().Length < 8) { // Длина сообщения не верная String mes = String.Format( "Длина PDU-фрайма равна в запросе 0x10 равна {0} байт. Должна быть не менее 8 байт", request.PDUFrame.ToArray().Length); result = new Message.Result(Error.DataFormatError, mes, request, null); } else { // Разбираем сообщение Byte[] array = new Byte[2]; // Получаем адрес первого регистра Array.Copy(request.PDUFrame.Data, 0, array, 0, 2); UInt16 address = Modbus.Convert.ConvertToUInt16(array); // Получаем количесво регистров для записи Array.Copy(request.PDUFrame.Data, 2, array, 0, 2); UInt16 quantity = Modbus.Convert.ConvertToUInt16(array); // Получаем количество байт в пасылке Byte count = request.PDUFrame.Data[4]; if ((quantity == 0) || (quantity > 123) || ((quantity * 2) != count)) { message = String.Format("Количество регистров для записи в запросе равно {0}, а должно быть 1...123", quantity); pdu = new Message.PDU((Byte)(0x10 | 0x80), new Byte[] { 0x03 }); answer = new Modbus.OSIModel.Message.Message(_Address, pdu); // Отправляем сообщение SendResponse(answer); result = new Message.Result(Error.IllegalDataValue, message, request, answer); } else { // Выполняем запрос. Проверяем доступность в // системе регистров в указанном диапазоне адресов for (int i = 0; i < quantity; i++) { // Если регистр не существует в системе формируем ответ // c исключение if (HoldingRegisters.Contains(System.Convert.ToUInt16(address + i)) == false) { // Формируем ответ с исключение 2 pdu = new Message.PDU((Byte)(0x10 | 0x80), new Byte[] { 0x02 }); answer = new Message.Message(_Address, pdu); message = String.Format("Регистр с адресом {0} не существует", (address + i)); result = new Message.Result(Error.IllegalDataAddress, message, request, answer); // Отправляем ответ мастеру SendResponse(answer); return result; } } // Все регистры найдены, устанавливаем новые значения и // формируем ответное сообщение Byte[] temp = new Byte[2]; List<Byte> data = new List<byte>(); // Устанавливаем новые значения в регистры for (int i = 0; i < quantity; i++) { Array.Copy(request.PDUFrame.Data, (5 + (i * 2)), temp, 0, 2); _HoldingRegisters[System.Convert.ToUInt16(address + i)].Value = Modbus.Convert.ConvertToUInt16(temp); } // Формируем ответ. temp = Modbus.Convert.ConvertToBytes(address); data.AddRange(temp); temp = Modbus.Convert.ConvertToBytes(quantity); data.AddRange(temp); pdu = new Message.PDU(); pdu.Function = 0x10; pdu.AddDataBytesRange(data.ToArray()); answer = new Message.Message(_Address, pdu); result = new Message.Result(Error.NoError, String.Empty, request, answer); // Отправляем ответ мастеру SendResponse(answer); // Формируем событие OnMasterChangedHoldingRegisters(); } } return result; }
//--------------------------------------------------------------------------- Result INetworkFunctions.WriteSingleCoil(Message.Message request) { Message.Result result; Message.Message answer; Message.PDU pdu; String message; // Проверяем длину PDU (должна быть 5 байт) if (request.PDUFrame.ToArray().Length != 5) { // Длина сообщения не верная String mes = String.Format( "Длина PDU-фрайма равна в запросе 0x05 равна {0} байт. Должна быть 5 байт", request.PDUFrame.ToArray().Length); result = new Message.Result(Error.DataFormatError, mes, request, null); } else { // Разбираем сообщение Byte[] array = new Byte[2]; // Получаем адрес реле Array.Copy(request.PDUFrame.Data, 0, array, 0, 2); UInt16 address = Modbus.Convert.ConvertToUInt16(array); // Получаем значение реле для записи Array.Copy(request.PDUFrame.Data, 2, array, 0, 2); UInt16 status = Modbus.Convert.ConvertToUInt16(array); State coilValue; // Получаем количество байт в пасылке switch (status) { case 0x0000: { coilValue = State.Off; break; } case 0xFF00: { coilValue = State.On; break; } default: { // Ошибка message = String.Format( "Неверный формат данных для кодировки состояния реле {0}, а должно быть 0x0000 или 0xFF00", status.ToString("X4")); pdu = new Message.PDU((Byte)(0x05 | 0x80), new Byte[] { 0x03 }); answer = new Modbus.OSIModel.Message.Message(_Address, pdu); // Отправляем сообщение SendResponse(answer); result = new Message.Result(Error.IllegalDataValue, message, request, answer); return result; } } // Выполняем запрос. Проверяем доступность в // системе регистров в указанном диапазоне адресов // Если регистр не существует в системе формируем ответ // c исключение if (Coils.Contains(address) == false) { // Формируем ответ с исключение 2 pdu = new Message.PDU((Byte)(0x80 | 0x05), new Byte[] { 0x02 }); answer = new Modbus.OSIModel.Message.Message(_Address, pdu); message = String.Format("Реле с адресом {0} не существует", address); result = new Message.Result(Error.IllegalDataAddress, message, request, answer); // Отправляем ответ мастеру SendResponse(answer); return result; } else { // Реле найдено, устанавливаем новое значение и // формируем ответное сообщение Coils[address].Value = Modbus.Convert.ToBoolean(coilValue); // Формируем ответ. List<Byte> data_ = new List<byte>(); data_.AddRange(Modbus.Convert.ConvertToBytes(address)); data_.AddRange(Modbus.Convert.StateToArray(coilValue)); pdu = new Message.PDU(); pdu.Function = 0x05; pdu.AddDataBytesRange(data_.ToArray()); answer = new Message.Message(_Address, pdu); result = new Message.Result(Error.NoError, String.Empty, request, answer); // Отправляем ответ мастеру SendResponse(answer); // Формируем событие OnMasterChangedCoils(); } } return result; }
//--------------------------------------------------------------------------- Result INetworkFunctions.WriteSingleRegister(Message.Message request) { Message.Result result; Message.Message answer; Message.PDU pdu; String message; // Проверяем длину PDU (должна быть 5 байт) if (request.PDUFrame.ToArray().Length != 5) { // Длина сообщения не верная String mes = String.Format( "Длина PDU-фрайма равна в запросе 0x06 равна {0} байт. Должна быть 5 байт", request.PDUFrame.ToArray().Length); result = new Message.Result(Error.DataFormatError, mes, request, null); } else { // Разбираем сообщение Byte[] array = new Byte[2]; // Получаем адрес регистра Array.Copy(request.PDUFrame.Data, 0, array, 0, 2); UInt16 address = Modbus.Convert.ConvertToUInt16(array); // Получаем значение регистра Array.Copy(request.PDUFrame.Data, 2, array, 0, 2); UInt16 value = Modbus.Convert.ConvertToUInt16(array); // Выполняем запрос. Проверяем доступность в // регистра if (_HoldingRegisters.Contains(address) == false) { // Если регистр не существует в системе формируем ответ // c исключение // Формируем ответ с исключение 2 pdu = new Message.PDU((Byte)(0x06 | 0x80), new Byte[] { 0x02 }); answer = new Message.Message(_Address, pdu); message = String.Format("Регистр с адресом {0} не существует", address); result = new Message.Result(Error.IllegalDataAddress, message, request, answer); // Отправляем ответ мастеру SendResponse(answer); return result; } else { // Все регистры найдены, устанавливаем новые значения и // формируем ответное сообщение _HoldingRegisters[address].Value = value; // Формируем ответ. pdu = new Message.PDU(); pdu.Function = 0x06; pdu.AddDataBytesRange(Modbus.Convert.ConvertToBytes(address)); pdu.AddDataBytesRange(Modbus.Convert.ConvertToBytes(value)); answer = new Modbus.OSIModel.Message.Message(_Address, pdu); result = new Message.Result(Error.NoError, String.Empty, request, answer); // Отправляем ответ мастеру SendResponse(answer); // Формируем событие OnMasterChangedHoldingRegisters(); } } return result; }
//--------------------------------------------------------------------------- Message.Result IModbusFunctions.ReadInputRegisters(Message.Message request) { Message.Result result; String message; if (request.Address == 0) { // Ошибка. Данная команда не может быть широковещательная message = "Широковещательный запрос на выполнение функции 0x04 невозможен"; Debug.WriteLine(message); result = new Message.Result(Error.RequestError, message, request, null); } else { // Проверяем длину PDU (должна равнятся байтам) if (request.PDUFrame.ToArray().Length != 5) { // Длина сообщения не верная String mes = String.Format( "Длина PDU-фрайма равна в запросе 0x4 равна {0} байт. Должна быть 5 байт", request.PDUFrame.ToArray().Length); result = new Message.Result(Error.DataFormatError, mes, request, null); Debug.WriteLine(mes); } else { // Разбираем сообщение Byte[] array = new Byte[2]; // Получаем адрес первого регистра входа Array.Copy(request.PDUFrame.Data, 0, array, 0, 2); UInt16 address = Modbus.Convert.ConvertToUInt16(array); // Получаем количесво регистров для чтения Array.Copy(request.PDUFrame.Data, 2, array, 0, 2); UInt16 quantity = Modbus.Convert.ConvertToUInt16(array); if ((quantity == 0) || (quantity > 125)) { message = String.Format("Количество регистров для чтения в запросе {0}, а должно быть 1...125", quantity); Message.PDU pdu = new Message.PDU(0x84, new Byte[] { 0x03 }); // Отправляем сообщение _connection.SendReply(pdu); result = new Message.Result(Error.IllegalDataValue, message, request, pdu); Debug.WriteLine(message); } else { // Выполняем запрос. Проверяем доступность в // системе регистров в указанном диапазоне адресов //InputRegister[] registers = new InputRegister[quantity]; DataRow[] rows = new DataRow[quantity]; Message.PDU pdu; for (int i = 0; i < quantity; i++) { //registers[i] = _inputRegisters.Find((UInt16)(address + i)); rows[i] = _dataMap.Tables["InputRegisters"].Rows.Find(address + i); // Если регистр не существует в системе формируем ответ // c исключение if (rows[i] == null) { // Формируем ответ с исключение 2 pdu = new Message.PDU(0x84, new Byte[] { 0x02 }); message = String.Format("Регистр с адресом {0} не существует", (address + i)); result = new Message.Result(Error.IllegalDataAddress, message, request, pdu); // Отправляем ответ мастеру this._connection.SendReply(pdu); Debug.WriteLine(message); return result; } } // Все регистры найдены формируем ответное сообщение Byte[] temp; List<Byte> data = new List<byte>(); for (int i = 0; i < quantity; i++) { temp = Modbus.Convert.ConvertToBytes((UInt16)rows[i]["Value"]); data.AddRange(temp); } pdu = new Message.PDU(); pdu.Function = 0x04; pdu.AddDataByte((Byte)(data.Count)); pdu.AddDataBytesRange(data.ToArray()); result = new Message.Result(Error.NoError, String.Empty, request, pdu); // Отправляем ответ мастеру this._connection.SendReply(pdu); } } } return result; }
//--------------------------------------------------------------------------- #endregion //--------------------------------------------------------------------------- #region Члены IApi //--------------------------------------------------------------------------- Message.Result IModbusFunctions.ReadCoils(Message.Message request) { Message.Result result; String message; if (request.Address == 0) { // Ошибка. Данная команда не может быть широковещательная message = "Широковещательный запрос на выполнение функции 0x01 невозможен"; result = new Message.Result(Error.RequestError, message, request, null); Debug.WriteLine(message); } else { // Проверяем длину PDU (должна равнятся 5 байтам) if (request.PDUFrame.ToArray().Length != 5) { // Длина сообщения не верная message = String.Format( "Длина PDU-фрайма в запросе {0}. Должна быть 5 байт", request.PDUFrame.ToArray()); result = new Message.Result(Error.DataFormatError, message, request, null); } else { // Разбираем сообщение Byte[] array = new Byte[2]; // Получаем адрес первого реле Array.Copy(request.PDUFrame.Data, 0, array, 0, 2); UInt16 address = Modbus.Convert.ConvertToUInt16(array); // Получаем количесво реле для чтения Array.Copy(request.PDUFrame.Data, 2, array, 0, 2); UInt16 quantity = Modbus.Convert.ConvertToUInt16(array); if ((quantity == 0) || (quantity > 2000)) { message = String.Format( "Количество реле для чтения в запросе {0}, а должно быть 1...2000", quantity); Message.PDU pdu = new Message.PDU(0x81, new Byte[] { 0x03 }); // Отправляем сообщение _connection.SendReply(pdu); Debug.WriteLine(message); result = new Message.Result(Error.IllegalDataValue, message, request, pdu); } else { // Выполняем запрос. Проверяем доступность в // системе реле в указанном диапазоне адресов DataRow[] row = new DataRow[quantity]; Message.PDU pdu; for (int i = 0; i < quantity; i++) { row[i] = _dataMap.Tables["Coils"].Rows.Find(i + address); // Если реле не существует в системе формируем ответ // c исключение if (row[i] == null) { // Формируем ответ с исключение 2 pdu = new Message.PDU(); pdu.Function = 0x01; pdu.SetErrorBit(); pdu.AddDataByte(0x02); result = new Message.Result(Error.IllegalDataAddress, String.Format("Реле с адресом {0} не существует", (address + i)), request, pdu); // Отправляем ответ мастеру this._connection.SendReply(pdu); return result; } } // Все реле найдены формируем ответное сообщение int totalBytes = quantity % 8; if (totalBytes == 0) { totalBytes = quantity / 8; } else { totalBytes = 1 + (quantity / 8); } Byte[] data = new Byte[totalBytes]; int number = 0; int index = 0; for (int i = 0; i < quantity; i++) { data[index] = (Byte)(data[index] | (Byte)(Modbus.Convert.BooleanToBit((Boolean)row[i]["Value"]) << number)); if (++number > 7) { number = 0; ++index; } } pdu = new Message.PDU(); pdu.Function = 0x01; pdu.AddDataByte((byte)totalBytes); // Добавляем количество байт с состояниями реле pdu.AddDataBytesRange(data); // Добавляем байты с состояниями реле result = new Message.Result(Error.NoError, String.Empty, request, pdu); // Отправляем ответ мастеру this._connection.SendReply(pdu); } } } return result; }
//--------------------------------------------------------------------------- Message.Result IModbusFunctions.WriteMultipleRegisters(Message.Message request) { Message.Result result; String message; // Проверяем длину PDU (должна быть не менее 8 байтам) if (request.PDUFrame.ToArray().Length < 8) { // Длина сообщения не верная String mes = String.Format( "Длина PDU-фрайма равна в запросе 0x10 равна {0} байт. Должна быть не менее 8 байт", request.PDUFrame.ToArray().Length); result = new Message.Result(Error.DataFormatError, mes, request, null); Debug.WriteLine(mes); } else { // Разбираем сообщение Byte[] array = new Byte[2]; // Получаем адрес первого регистра Array.Copy(request.PDUFrame.Data, 0, array, 0, 2); UInt16 address = Modbus.Convert.ConvertToUInt16(array); // Получаем количесво регистров для записи Array.Copy(request.PDUFrame.Data, 2, array, 0, 2); UInt16 quantity = Modbus.Convert.ConvertToUInt16(array); // Получаем количество байт в пасылке Byte count = request.PDUFrame.Data[4]; if ((quantity == 0) || (quantity > 123) || ((quantity * 2) != count)) { message = String.Format("Количество регистров для записи в запросе равно {0}, а должно быть 1...123", quantity); Message.PDU pdu = new Message.PDU((Byte)(0x10 | 0x80), new Byte[] { 0x03 }); // Отправляем сообщение _connection.SendReply(pdu); result = new Message.Result(Error.IllegalDataValue, message, request, pdu); Debug.WriteLine(message); } else { // Выполняем запрос. Проверяем доступность в // системе регистров в указанном диапазоне адресов //HoldingRegister[] registers = new HoldingRegister[quantity]; DataRow[] rows = new DataRow[quantity]; Message.PDU pdu; for (int i = 0; i < quantity; i++) { //registers[i] = _holdingRegisters.Find((UInt16)(address + i)); rows[i] = _dataMap.Tables["HoldingRegisters"].Rows.Find((UInt16)(address + i)); // Если регистр не существует в системе формируем ответ // c исключение if (rows[i] == null) { // Формируем ответ с исключение 2 pdu = new Message.PDU((Byte)(0x10 | 0x80), new Byte[] { 0x02 }); message = String.Format("Регистр с адресом {0} не существует", (address + i)); result = new Message.Result(Error.IllegalDataAddress, message, request, pdu); // Отправляем ответ мастеру this._connection.SendReply(pdu); Debug.WriteLine(message); return result; } } // Все регистры найдены, устанавливаем новые значения и // формируем ответное сообщение Byte[] temp = new Byte[2]; List<Byte> data = new List<byte>(); // Устанавливаем новые значения в регистры for (int i = 0; i < quantity; i++) { Array.Copy(request.PDUFrame.Data, (5 + (i * 2)), temp, 0, 2); rows[i]["Value"] = Modbus.Convert.ConvertToUInt16(temp); } // Формируем ответ. temp = Modbus.Convert.ConvertToBytes(address); data.AddRange(temp); temp = Modbus.Convert.ConvertToBytes(quantity); data.AddRange(temp); pdu = new Message.PDU(); pdu.Function = 0x10; pdu.AddDataBytesRange(data.ToArray()); result = new Message.Result(Error.NoError, String.Empty, request, pdu); // Отправляем ответ мастеру this._connection.SendReply(pdu); // Формируем событие this.OnWriteHoldingRegisters(); } } return result; }
//--------------------------------------------------------------------------- Message.Result IModbusFunctions.WriteSingleRegister(Message.Message request) { Message.Result result; String message; // Проверяем длину PDU (должна быть 5 байт) if (request.PDUFrame.ToArray().Length != 5) { // Длина сообщения не верная String mes = String.Format( "Длина PDU-фрайма равна в запросе 0x06 равна {0} байт. Должна быть 5 байт", request.PDUFrame.ToArray().Length); result = new Message.Result(Error.DataFormatError, mes, request, null); Debug.WriteLine(mes); } else { // Разбираем сообщение Byte[] array = new Byte[2]; // Получаем адрес регистра Array.Copy(request.PDUFrame.Data, 0, array, 0, 2); UInt16 address = Modbus.Convert.ConvertToUInt16(array); // Получаем значение регистра Array.Copy(request.PDUFrame.Data, 2, array, 0, 2); UInt16 value = Modbus.Convert.ConvertToUInt16(array); // Выполняем запрос. Проверяем доступность в // регистра //HoldingRegister register; Message.PDU pdu; //register = _holdingRegisters.Find(address); DataRow row = _dataMap.Tables["HoldingRegisters"].Rows.Find(address); // Если регистр не существует в системе формируем ответ // c исключение if (row == null) { // Формируем ответ с исключение 2 pdu = new Message.PDU((Byte)(0x06 | 0x80), new Byte[] { 0x02 }); message = String.Format("Регистр с адресом {0} не существует", address); result = new Message.Result(Error.IllegalDataAddress, message, request, pdu); // Отправляем ответ мастеру this._connection.SendReply(pdu); Debug.WriteLine(message); return result; } else { // Все регистры найдены, устанавливаем новые значения и // формируем ответное сообщение row["Value"] = value; // Формируем ответ. pdu = new Message.PDU(); pdu.Function = 0x06; pdu.AddDataBytesRange(Modbus.Convert.ConvertToBytes(address)); pdu.AddDataBytesRange(Modbus.Convert.ConvertToBytes(value)); result = new Message.Result(Error.NoError, String.Empty, request, pdu); // Отправляем ответ мастеру this._connection.SendReply(pdu); // Формируем событие this.OnWriteHoldingRegisters(); } } return result; }
//--------------------------------------------------------------------------- Message.Result IModbusFunctions.WriteSingleCoil(Message.Message request) { Message.Result result; String message; // Проверяем длину PDU (должна быть 5 байт) if (request.PDUFrame.ToArray().Length != 5) { // Длина сообщения не верная String mes = String.Format( "Длина PDU-фрайма равна в запросе 0x05 равна {0} байт. Должна быть 5 байт", request.PDUFrame.ToArray().Length); result = new Message.Result(Error.DataFormatError, mes, request, null); Debug.WriteLine(mes); } else { Message.PDU pdu; // Разбираем сообщение Byte[] array = new Byte[2]; // Получаем адрес реле Array.Copy(request.PDUFrame.Data, 0, array, 0, 2); UInt16 address = Modbus.Convert.ConvertToUInt16(array); // Получаем значение реле для записи Array.Copy(request.PDUFrame.Data, 2, array, 0, 2); UInt16 status = Modbus.Convert.ConvertToUInt16(array); State statusOutput; // Получаем количество байт в пасылке switch (status) { case 0x0000: { statusOutput = State.Off; break; } case 0xFF00: { statusOutput = State.On; break; } default: { // Ошибка message = String.Format( "Неверный формат данных для кодировки состояния реле {0}, а должно быть 0x0000 или 0xFF00", status.ToString("X4")); pdu = new Message.PDU((Byte)(0x05 | 0x80), new Byte[] { 0x03 }); // Отправляем сообщение _connection.SendReply(pdu); result = new Message.Result(Error.IllegalDataValue, message, request, pdu); Debug.WriteLine(message); return result; } } // Выполняем запрос. Проверяем доступность в // системе регистров в указанном диапазоне адресов //Coil coil = _coils.Find((UInt16)(address)); DataRow row = _dataMap.Tables["Coils"].Rows.Find((UInt16)(address)); // Если регистр не существует в системе формируем ответ // c исключение if (row == null) { // Формируем ответ с исключение 2 pdu = new Message.PDU((Byte)(0x80 | 0x05), new Byte[] { 0x02 }); message = String.Format("Реле с адресом {0} не существует", address); result = new Message.Result(Error.IllegalDataAddress, message, request, pdu); // Отправляем ответ мастеру this._connection.SendReply(pdu); Debug.WriteLine(message); return result; } else { // Реле найдено, устанавливаем новое значение и // формируем ответное сообщение row["Value"] = Modbus.Convert.ToBoolean(statusOutput); // Формируем ответ. List<Byte> data_ = new List<byte>(); data_.AddRange(Modbus.Convert.ConvertToBytes(address)); data_.AddRange(Modbus.Convert.StateToArray(statusOutput)); pdu = new Message.PDU(); pdu.Function = 0x05; pdu.AddDataBytesRange(data_.ToArray()); result = new Message.Result(Error.NoError, String.Empty, request, pdu); // Отправляем ответ мастеру this._connection.SendReply(pdu); // Формируем событие this.OnWriteCoils(); } } return result; }