Пример #1
0
        /// <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);
        }
Пример #2
0
        //---------------------------------------------------------------------------
        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;
        }
Пример #3
0
        //---------------------------------------------------------------------------
        /// <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;
            }           
        }
Пример #4
0
        //---------------------------------------------------------------------------
        #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;

        }
Пример #5
0
        //---------------------------------------------------------------------------
        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;
        }
Пример #6
0
        //---------------------------------------------------------------------------
        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;
        }
Пример #7
0
        //---------------------------------------------------------------------------
        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;
        }
Пример #8
0
        //---------------------------------------------------------------------------
        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;
        }
Пример #9
0
        //---------------------------------------------------------------------------
        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;
        }
Пример #10
0
        //---------------------------------------------------------------------------
        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;
        }
Пример #11
0
        //---------------------------------------------------------------------------
        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;
        }
Пример #12
0
        //---------------------------------------------------------------------------
        #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;
        }
Пример #13
0
        //---------------------------------------------------------------------------
        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;
        }
Пример #14
0
        //---------------------------------------------------------------------------
        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;
        }
Пример #15
0
        //---------------------------------------------------------------------------
        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;
        }
Пример #16
0
        //---------------------------------------------------------------------------
        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;
        }