//--------------------------------------------------------------------------- #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.FunctionNotSupported(Message.Message request) { Message.Message answer; Message.PDU pdu = new Message.PDU(); pdu.Function = (Byte)(request.PDUFrame.Function | 0x80); pdu.AddDataByte(0x01); //Error.IllegalFunction answer = new Modbus.OSIModel.Message.Message(Address, pdu); // Отправляем ответ SendResponse(answer); Message.Result result = new Message.Result(Error.IllegalFunction, "Функция не поддерживается данным устройством", request, answer); return result; }
//--------------------------------------------------------------------------- Result INetworkFunctions.ReadInputRegisters(Message.Message request) { Message.Result result; Message.Message answer; Message.PDU pdu; String message; if (request.Address == 0) { // Ошибка. Данная команда не может быть широковещательная message = "Широковещательный запрос на выполнение функции 0x04 невозможен"; 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); } 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(0x84, 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 исключением 2 if (InputRegisters.Contains(System.Convert.ToUInt16(address + i)) == false) { pdu = new Message.PDU(0x84, 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>(); for (int i = 0; i < quantity; i++) { temp = Modbus.Convert.ConvertToBytes( InputRegisters[System.Convert.ToUInt16(address + i)].Value); data.AddRange(temp); } pdu = new Message.PDU(); pdu.Function = 0x04; pdu.AddDataByte((Byte)(data.Count)); pdu.AddDataBytesRange(data.ToArray()); answer = new Message.Message(_Address, pdu); result = new Result(Error.NoError, String.Empty, request, answer); // Отправляем ответ мастеру SendResponse(answer); } } } 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.FunctionNotSupported(Message.Message request) { Message.PDU pdu = new Message.PDU(); pdu.Function = (Byte)(request.PDUFrame.Function | 0x80); pdu.AddDataByte(0x01); //Error.IllegalFunction Message.Result result = new Message.Result(Error.IllegalFunction, "Функция не поддерживается данным устройством", request, pdu); // Отправляем ответ this._connection.SendReply(pdu); return result; }