Beispiel #1
0
    /// <summary>
    ///		Should be called every frame.
    ///		Continiues execution, depending on what the previous message returned
    ///	</summary>
    public void Update()
    {
        if (!Running)
        {
            return;
        }
        if (!messages.ContainsKey(CurrentState))
        {
            DeveloppmentTools.Log(string.Format("State {0} not an option", CurrentState));
            return;
        }
        if (messages[CurrentState].Length <= messgecycle)
        {
            DeveloppmentTools.Log(string.Format("MessageID {0} not an option", messgecycle));
            return;
        }
        Message curr_message = messages[CurrentState][messgecycle];

        Message.Result res = curr_message.Execute(console.HasInput ? console.ReadLine() : null);
        switch (res)
        {
        default:
        case Message.Result.error:
        case Message.Result.finished:
            if (++messgecycle >= messages [CurrentState].Length)
            {
                if (nextstate == ushort.MaxValue)
                {
                    LogError("State not set");
                }
                CurrentState = nextstate;
                messgecycle  = 0;
                // To be recognized as the error-source
                nextstate = ushort.MaxValue;
            }
            break;

        case Message.Result.running:
            break;

        case Message.Result.break_:
            CurrentState = nextstate;
            break;

        case Message.Result.notimplemented:
            LogError("Function not implemented yet");
            goto case Message.Result.error;

        case Message.Result.exit:
            Exit();
            break;
        }
        return;
    }
Beispiel #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;
        }
Beispiel #3
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;
        }
Beispiel #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;

        }
Beispiel #5
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;
        }
Beispiel #6
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;
        }
Beispiel #7
0
        //---------------------------------------------------------------------------
        /// <summary>
        /// Функция 0x6. Записывает значение в одиночный регистр
        /// хранения в удалённом устройстве
        /// </summary>
        /// <param name="request">Запрос на выполнение операции</param>
        /// <param name="value">Записанное в устройство значение регистра</param>
        /// <returns>Результат выполнения запроса</returns>
        public Modbus.OSIModel.Message.Result WriteSingleRegister(Message.Message request,
            ref UInt16 value)
        {
            Modbus.OSIModel.Message.Message answer;
            Modbus.OSIModel.Message.Result result;

            // Проверяем состояние сервера
            if (_flgBusy == true)
            {
                value = 0;
                return result = new Message.Result(Error.IllegalReguest,
                    String.Format("Попытка выполнить запрос (код функции 0x6) к серверу {0}, во время выполнения предыдущего",
                    Name), null, null);
                //throw new Exception(String.Format(
                //    "Попытка выполнить запрос (код функции 0x6) к серверу {0}, во время выполнения предыдущего",
                //    Name));
            }
            else
            {
                // Устанавливаем начало транзакции
                StartTransaction();

                // Отправляем запрос
                Modbus.OSIModel.DataLinkLayer.RequestError error =
                    _dataLinkObject.SendMessage(request, out answer);

                switch (error)
                {
                    case Modbus.OSIModel.DataLinkLayer.RequestError.NoError:
                        {
                            // Разбираем сообщение на предмет ошибок
                            if (IsError(request, answer, out result))
                            {
                                // Ошибка была
                                value = 0;
                                break;
                            }
                            else
                            {
                                // Ошибки нет возвращаем результат выполнения запроса
                                // Проверяем длину сообщения
                                if (answer.PDUFrame.Data.Length != 4)
                                {
                                    value = 0;
                                    result = new Message.Result(Error.DataFormatError,
                                        String.Format(
                                        "Длина ответного сообщения {0} не соответствет ожидаемой 4",
                                        answer.PDUFrame.Data.Length), request, answer);
                                }
                                else
                                {
                                    // Проверяем адрес регистра в ответном сообщениии
                                    Byte[] arr = new Byte[2];
                                    Array.Copy(answer.PDUFrame.Data, 0, arr, 0, 2);
                                    value = Modbus.Convert.ConvertToUInt16(arr);
                                    
                                    Array.Copy(request.PDUFrame.Data, 0, arr, 0, 2);
                                    UInt16 var = Modbus.Convert.ConvertToUInt16(arr);
                                    
                                    if (value != var)
                                    {
                                        result = new Message.Result(Error.DataFormatError,
                                            String.Format(
                                            "Адрес регистра {0} в запросе не совпадает с аресом в ответном сообщении {1}",
                                            var, value), request, answer);
                                    }
                                    else
                                    {
                                        Array.Copy(answer.PDUFrame.Data, 2, arr, 0, 2);
                                        value = Modbus.Convert.ConvertToUInt16(arr);
                                        result = new Modbus.OSIModel.Message.Result(Error.NoError,
                                            String.Empty, request, answer);
                                    }
                                }
                                break;
                            }
                        }
                    case Modbus.OSIModel.DataLinkLayer.RequestError.TimeOut:
                        {
                            // Таймаут ответа
                            value = 0;
                            result = new Modbus.OSIModel.Message.Result(Error.TimeOut,
                                "Ответ не был получен в заданное время", request, null);
                            break;
                        }
                    default:
                        {
                            // Ошибка уровня Datalink layer.
                            value = 0;
                            result = new Modbus.OSIModel.Message.Result(Error.ReciveMessageError,
                                error.ToString(), request, null);
                            break;
                        }
                }
                StopTransaction();
                return result;
            }
        }
Beispiel #8
0
        /// <summary>
        /// Функция 0x2. Читает дискретные входы
        /// в удалённом устройстве
        /// </summary>
        /// <param name="AddressSlave">адрес удалённого slave-устройства, 
        /// из которого нужно получить данные</param>
        /// <param name="StartingAddress">Адрес начального дискретного входа</param>
        /// <param name="Quantity">Количество дискретных входов для чтения 1...2000</param>
        /// <param name="inputs">Состояния прочитанных дискретных входов</param>
        /// <returns>Результат выполения операции</returns>
        public Message.Result ReadDiscreteInputs(byte AddressSlave,
            UInt16 StartingAddress, UInt16 Quantity, out State[] inputs)
        {
            Modbus.OSIModel.Message.Message request, answer;
            Modbus.OSIModel.Message.Result result;
            inputs = null;
            String message;

            // Данный запрос не может быть широковещательным
            if (AddressSlave == 0)
            {
                message = "Функция с кодом 0х2, не может быть широковещательным запросом";
                throw new ArgumentException(message, "addressSlave");
            }

            // Подготавливаем данные
            List<byte> array = new List<byte>();
            array.AddRange(Modbus.Convert.ConvertToBytes(StartingAddress));
            array.AddRange(Modbus.Convert.ConvertToBytes(Quantity));

            request =
                new Modbus.OSIModel.Message.Message(AddressSlave, 0x2, array.ToArray());

            // Выполняем запрос
            while (_flgBusy)
            {
                // Если идёт транзакция ждём окончания
            }

            // Устанавливаем начало транзакции
            StartTransaction();

            // Отправляем запрос
            Modbus.OSIModel.DataLinkLayer.RequestError error =
                _dataLinkObject.SendMessage(request, out answer);

            switch (error)
            {
                case Modbus.OSIModel.DataLinkLayer.RequestError.NoError:
                    {
                        // Разбираем сообщение на предмет ошибок
                        if (IsError(request, answer, out result))
                        {
                            // Ошибка была
                            break;
                        }
                        else
                        {
                            // Ошибки нет возвращаем результат выполнения запроса
                            // Проверяем содержимое посылки
                            // Рассчитываем необходимое количество байт для передачи состояний дискретных входов
                            int length = Quantity / 8;

                            if (Quantity % 8 != 0)
                            {
                                ++length;
                            }

                            if ((int)answer.PDUFrame.Data[0] != length)
                            {
                                result = new Message.Result(
                                    Error.DataFormatError,
                                    String.Format("Количество байт {0} в сообщении не равно требуемому {1} для передачи состояний реле в количестве {2}",
                                    answer.PDUFrame.Data[0], 
                                    length, 
                                    Quantity),
                                    request, 
                                    answer);
                            }
                            else
                            {
                                Byte data, temp;
                                inputs = new State[Quantity];

                                for (int i = 0; i < answer.PDUFrame.Data[0]; i++)
                                {
                                    data = answer.PDUFrame.Data[i + 1];

                                    for (int y = 0; y < 8; y++)
                                    {
                                        if (8 * i + y < Quantity)
                                        {
                                            temp = (Byte)(data >> y);

                                            if ((temp & 0x01) == 0x01)
                                            {
                                                inputs[(8 * i + y)] = State.On;
                                            }
                                            else
                                            {
                                                inputs[(8 * i + y)] = State.Off;
                                            }
                                        }
                                    }
                                }
                            }

                            result = new Message.Result(Error.NoError, String.Empty,
                                request, answer);

                            break;
                        }
                    }
                case Modbus.OSIModel.DataLinkLayer.RequestError.TimeOut:
                    {
                        // Таймаут ответа
                        result = new Modbus.OSIModel.Message.Result(Error.TimeOut,
                            "Ответ не был получен в заданное время", request, null);
                        break;
                    }
                default:
                    {
                        // Ошибка уровня Datalink layer.
                        result = new Modbus.OSIModel.Message.Result(Error.ReciveMessageError,
                            error.ToString(), request, null);
                        break;
                    }
            }
            StopTransaction();
            return result;
        }
Beispiel #9
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;
        }
Beispiel #10
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;
        }
Beispiel #11
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;
        }
Beispiel #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;
        }
Beispiel #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;
        }
Beispiel #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;
        }
Beispiel #15
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;
            }           
        }
Beispiel #16
0
        //---------------------------------------------------------------------------
        /// <summary>
        /// Функция 0х1. Чтение реле
        /// </summary>
        /// <param name="addressSlave">адрес удалённого slave-устройства, 
        /// из которого нужно получить данные</param>
        /// <param name="startingAddress">Адрес начального реле</param>
        /// <param name="quantity">Количество реле для чтения 1...2000</param>
        /// <param name="answer">Ответное сообщение</param>
        /// <param name="coils">Прочитанные состояния реле</param>
        /// <returns>Результат выполнения операции</returns>
        public Modbus.OSIModel.Message.Result ReadCoils(
            Modbus.OSIModel.Message.Message request,
            out State[] coils)
        {
            Modbus.OSIModel.Message.Message answer;
            Modbus.OSIModel.Message.Result result;
            Byte[] arrTemp = new Byte[2];
            
            Array.Copy(request.PDUFrame.Data, 2, arrTemp, 0, 2);

            UInt16 quantity = Modbus.Convert.ConvertToUInt16(arrTemp);
            coils = new State[quantity];

            while (_flgBusy)
            {
                // Если идёт транзакция ждём окончания
            }

            // Устанавливаем начало транзакции
            StartTransaction();
    
            // Отправляем запрос
            Modbus.OSIModel.DataLinkLayer.RequestError error =
                _dataLinkObject.SendMessage(request, out answer);

            switch (error)
            {
                case Modbus.OSIModel.DataLinkLayer.RequestError.NoError:
                    {
                        // Разбираем сообщение на предмет ошибок
                        if (IsError(request, answer, out result))
                        {
                            // Ошибка была
                            break;
                        }
                        else
                        {
                            // Ошибки нет возвращаем результат выполнения запроса
                            // Проверяем содержимое посылки
                            // Рассчитываем необходимое количество байт для передачи состояний реле
                            int length = quantity / 8;

                            if (quantity % 8 != 0)
                            {
                                ++length;
                            }

                            if ((int)answer.PDUFrame.Data[0] != length)
                            {
                                result = new Message.Result(Error.DataFormatError,
                                    String.Format(
                                    "Количество байт {0} в сообщении не равно требуемому {1} для передачи состояний реле в количестве {2}",
                                    answer.PDUFrame.Data[0], length, quantity),
                                    request, answer);
                            }
                            else
                            {
                                Byte data, temp;
                                
                                for (int i = 0; i < answer.PDUFrame.Data[0]; i++)
                                {
                                    data = answer.PDUFrame.Data[i + 1];

                                    for (int y = 0; y < 8; y++)
                                    {
                                        if (8 * i + y < quantity)
                                        {
                                            temp = (Byte)(data >> y);

                                            if ((temp & 0x01) == 0x01)
                                            {
                                                coils[(8 * i + y)] = State.On;
                                            }
                                            else
                                            {
                                                coils[(8 * i + y)] = State.Off;
                                            }
                                        }
                                    }
                                }
                            }
                            result = new Message.Result(Error.NoError, String.Empty,
                                request, answer);
                            
                            break;
                        }
                    }
                case Modbus.OSIModel.DataLinkLayer.RequestError.TimeOut:
                    {
                        // Таймаут ответа
                        result = new Modbus.OSIModel.Message.Result(Error.TimeOut,
                            "Ответ не был получен в заданное время", request, null);
                        break;
                    }
                default:
                    {
                        // Ошибка уровня Datalink layer.
                        result = new Modbus.OSIModel.Message.Result(Error.ReciveMessageError,
                            error.ToString(), request, null);
                        break;
                    }
            }
            StopTransaction();
            return result;
        }
Beispiel #17
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;
        }
Beispiel #18
0
        /// <summary>
        /// Функция 0х5. Устанавливает реле в состояние вкл./выкл. 
        /// в удалённом устройстве
        /// </summary>
        /// <param name="addressSlave">адрес удалённого slave-устройства, 
        /// в котором нужно установить состояние реле</param>
        /// <param name="addressCoil">Адрес целевого реле</param>
        /// <param name="state">Состояние реле: 0х00FF-ON, 0x0000-OFF</param>
        public Message.Result WriteSingleCoil(byte addressSlave, 
            UInt16 addressCoil, ref State state)
        {
            string message;
            Modbus.OSIModel.Message.Message request, answer;
            Modbus.OSIModel.Message.Result result;

            // Проверяем состояние сервера
            if (_flgBusy == true)
            {
                return result = new Message.Result(Error.IllegalReguest,
                    String.Format("Попытка выполнить запрос (код функции 0x5) к серверу {0}, во время выполнения предыдущего",
                    Name), null, null);
                //throw new Exception(String.Format(
                //    "Попытка выполнить запрос (код функции 0x5) к серверу {0}, во время выполнения предыдущего",
                //    Name));
            }
            else
            {
                // Данный запрос не может быть широковещательным
                if (addressSlave == 0)
                {
                    message = "Функция с кодом 0х5, не может быть отправлена как широковещательный запрос";
                    throw new Exception(message);
                }
                else
                {

                    // Устанавливаем начало транзакции
                    StartTransaction();

                    // Подготавливаем данные
                    List<byte> array = new List<byte>();
                    array.AddRange(Modbus.Convert.ConvertToBytes(addressCoil));
                    //Byte[] state;
                    
                    //if (ValueCoil == Modbus.Device.CoilState.ON)
                    //{
                    //    state = new byte[2] { 0xFF, 0x00 };
                    //    array.AddRange(state);
                    //}
                    //else
                    //{
                    //    state = new byte[2] { 0x00, 0x00 };
                    //    array.AddRange(state);
                    //}
                    array.AddRange(Modbus.Convert.StateToArray(state));

                    // Отправляем запрос
                    request = new Modbus.OSIModel.Message.Message(addressSlave, 0x5, array.ToArray());

                    // Отправляем запрос
                    Modbus.OSIModel.DataLinkLayer.RequestError error =
                        _dataLinkObject.SendMessage(request, out answer);

                    switch (error)
                    {
                        case Modbus.OSIModel.DataLinkLayer.RequestError.NoError:
                            {
                                // Разбираем сообщение на предмет ошибок
                                if (IsError(request, answer, out result))
                                {
                                    // Ошибка была
                                    break;
                                }
                                else
                                {
                                    // Ошибки нет возвращаем результат выполнения запроса
                                    // Проверяем длину данных
                                    if (answer.PDUFrame.Data.Length == 4)
                                    {
                                        // Длина корректана проверяем
                                        // адрес дискретного входа
                                        List<Byte> arr = new List<byte>();
                                        arr.Add(answer.PDUFrame.Data[0]);
                                        arr.Add(answer.PDUFrame.Data[1]);
                                        UInt16 value = Convert.ConvertToUInt16(arr.ToArray());
                                        if (value == addressCoil)
                                        {
                                            // Адрес верный
                                            // получаем новое состояние реле
                                            arr.Clear();
                                            arr.Add(answer.PDUFrame.Data[2]);
                                            arr.Add(answer.PDUFrame.Data[3]);
                                            state = Convert.ValueToState(arr.ToArray());
                                            result = new Modbus.OSIModel.Message.Result(Error.NoError,
                                                String.Empty, request, answer);
                                        }
                                        else
                                        {
                                            // Адрес дискретного входа отличается от адреса в запросе
                                            result = new Modbus.OSIModel.Message.Result(Error.DataFormatError,
                                                String.Format(
                                                "Адрес реле в запросе {0} не соответствует адерсу реле в ответе {1}", 
                                                addressCoil, value), 
                                                request, answer);
                                        }
                                    }
                                    else
                                    {
                                        // Некорректная длина данных в ответе
                                        result = new Modbus.OSIModel.Message.Result(Error.DataFormatError,
                                            String.Format(
                                            "Неверная длина данных {0} в ответе, а ожидается 4",
                                            answer.PDUFrame.Data.Length),
                                            request, answer);
                                    }
                                    break;
                                }
                            }
                        case Modbus.OSIModel.DataLinkLayer.RequestError.TimeOut:
                            {
                                // Таймаут ответа
                                result = new Modbus.OSIModel.Message.Result(Error.TimeOut,
                                    "Ответ не был получен в заданное время", request, null);
                                break;
                            }
                        default:
                            {
                                // Ошибка уровня Datalink layer.
                                result = new Modbus.OSIModel.Message.Result(Error.ReciveMessageError,
                                    error.ToString(), request, null);
                                break;
                            }
                    }
                    StopTransaction();
                    return result;
                }
            }
        }
Beispiel #19
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;
        }
Beispiel #20
0
        //---------------------------------------------------------------------------
        Result INetworkFunctions.ReadFileRecord(Message.Message request)
        {
            Message.Result result;
            Message.Message answer;
            //Message.PDU pdu;
            String message;
            UInt16 var;


            Code0x14SubRequest[] subRequestList;

            const int ByteCountIndex = 0; // Индекс параметра Byte Count в массиве данных запроса  

            if (request.Address == 0)
            {
                // Ошибка. Данная команда не может быть широковещательная
                message = "Широковещательный запрос на выполнение функции 0x14 невозможен";
                result = new Message.Result(Error.RequestError,
                    message, request, null);
                return result;
            }
            else
            {
                if (request.PDUFrame.Length < 7)
                {
                    // Ошибка. Минимальная длина pdu запроса 0х14 это 7 байт
                    message = "Ошибка. Длина pdu запроса 0x14 менее 7 байт";
                    answer = new Message.Message(_Address,
                        new PDU((Byte)(0x14 | 0x80), new byte[] { 0x03 }));

                    result = new Message.Result(Error.RequestError,
                        message, request, answer);
                    // Отправляем ответ
                    SendResponse(answer);
                    return result;
                }
                else
                {
                    if ((request.PDUFrame.Data[ByteCountIndex] < 0x07) ||
                        (request.PDUFrame.Data[ByteCountIndex] > 0xF5))
                    {
                        // Ошибка. Указанная длина Byte Count вне допустимого диапазона значений
                        message = String.Format(
                            "Ошибка. Код функции 0x14. Параметр Byte Count = {0} вне допустимого диапазона 0x07...0xF5",
                            request.PDUFrame.Data[ByteCountIndex], (request.PDUFrame.Length - 2));

                        answer = new Message.Message(_Address,
                        new PDU((Byte)(0x14 | 0x80), new byte[] { 0x03 }));

                        result = new Message.Result(Error.RequestError,
                            message, request, answer);
                        // Отправляем ответ
                        SendResponse(answer);
                        return result;
                    }
                    else
                    {
                        // Проверяем фактическую длину запроса и величину переданную 
                        // в запросе "Byte Count"
                        if ((Int32)request.PDUFrame.Data[ByteCountIndex] != (request.PDUFrame.Length - 2))
                        {
                            // Ошибка. Указанная длина не совпадает с фактической
                            message = String.Format(
                                "Ошибка. Параметр Byte Count = {0} не совпадает с фактической длиной {1}",
                                request.PDUFrame.Data[ByteCountIndex], (request.PDUFrame.Length - 2));

                            answer = new Message.Message(_Address,
                            new PDU((Byte)(0x14 | 0x80), new byte[] { 0x03 }));

                            result = new Message.Result(Error.RequestError,
                                message, request, answer);
                            // Отправляем ответ
                            SendResponse(answer);
                            return result;
                        }
                        else
                        {
                            // Определяем количество групп (подзапросов) в данном запросе
                            if ((request.PDUFrame.Data.Length - 1) % 7 != 0)
                            {
                                // Длина подзапроса всегда равна 7, поэтому должно быть
                                // кратно. Если при делении на 7, остаток не равен 0, то
                                // данные не корректны
                                // Ошибка. Указанная длина не совпадает с фактической
                                message = String.Format("Ошибка. Неверная длина данных в запросе");

                                answer = new Message.Message(_Address,
                                new PDU((Byte)(0x14 | 0x80), new byte[] { 0x03 }));

                                result = new Message.Result(Error.RequestError,
                                    message, request, answer);
                                // Отправляем ответ
                                SendResponse(answer);
                                return result;

                            }
                            else
                            {
                                // Подзапросы имеют корректный формат. Получаем их
                                // Получаем количество подзапросов
                                subRequestList = new Code0x14SubRequest[((request.PDUFrame.Data.Length - 1) / 7)];
                                // Получаем сами подзапросы
                                for (int i = 0; i < subRequestList.Length; i++)
                                {
                                    subRequestList[i].ReferenceType = request.PDUFrame.Data[(7 * i + 1)];
                                    var = (UInt16)(((UInt16)request.PDUFrame.Data[(7 * i + 2)]) << 8); // Hi
                                    var = (UInt16)(var | request.PDUFrame.Data[(7 * i + 3)]); // Lo
                                    subRequestList[i].FileNumber = var;
                                    var = (UInt16)(((UInt16)request.PDUFrame.Data[(7 * i + 4)]) << 8); // Hi
                                    var = (UInt16)(var | request.PDUFrame.Data[(7 * i + 5)]); // Lo
                                    subRequestList[i].RecordNumber = var;
                                    var = (UInt16)(((UInt16)request.PDUFrame.Data[(7 * i + 6)]) << 8); // Hi
                                    var = (UInt16)(var | request.PDUFrame.Data[(7 * i + 7)]); // Lo
                                    subRequestList[i].RecordLength = var;
                                }
                                // Проверяем корректность данных в подзапросах 
                                for (int i = 0; i < subRequestList.Length; i++)
                                {
                                    // Проверяем значение параметра "The reference type". Оно всегда
                                    // должно равняться 0x6
                                    if (subRequestList[i].ReferenceType != 0x6)
                                    {
                                        // Ошибка
                                        answer = new Message.Message(_Address,
                                            new PDU((Byte)(0x80 | 0x14), new byte[] { 0x2 }));
                                        message = "Ошибка: Подзапрос имеет недопустимое значение праметра The reference type";
                                        result = new Result(Error.RequestError, message, request, answer);
                                        
                                        SendResponse(answer);
                                        
                                        return result;
                                    }
                                    else
                                    {
                                        // Проверяем адрес старовтовой записы. Должен быть 
                                        // не более 10000 (0x270F)
                                        if (subRequestList[i].RecordNumber > 0x270F)
                                        {
                                            // Ошибка
                                            answer = new Message.Message(_Address,
                                                new PDU((Byte)(0x80 | 0x14), new byte[] { 0x2 }));
                                            message = "Ошибка: Подзапрос имеет недопустимое значение номера записи файла";
                                            result = new Result(Error.RequestError, message, request, answer);

                                            SendResponse(answer);

                                            return result;
                                        }
                                        else
                                        {
                                            // Проверяем конечный адрес (Начальный адрес + длина блока)
                                            if (subRequestList[i].RecordNumber + subRequestList[i].RecordLength > 0x270F)
                                            {
                                                // Ошибка
                                                answer = new Message.Message(_Address,
                                                    new PDU((Byte)(0x80 | 0x14), new byte[] { 0x2 }));
                                                message = "Ошибка: Подзапрос имеет недопустимое значение длины блока читаемых записей из файла";
                                                result = new Result(Error.RequestError, message, request, answer);

                                                SendResponse(answer);

                                                return result;
                                            }
                                            else
                                            {
                                                // Все проверки пройдены. Теперь можно получать конечные 
                                                // значения
                                            }
                                        }
                                    }
                                }
                                
                                // Определяем общую длину ответа и проверяем превышает ли она допустимый размер
                                var = 2; // Function code + Resp. Data length
                                for (int i = 0; i < subRequestList.Length; i++)
                                {
                                    var = System.Convert.ToUInt16(var + 2); // File resp. length + Ref. Type 
                                    var = System.Convert.ToUInt16(var + (subRequestList[i].RecordLength * 2));
                                }

                                if (var > 253)
                                {
                                    // Ошибка. Длина запрощенных данных превышает максимальную
                                    // длину PDU ответного пакета
                                    answer = new Message.Message(_Address,
                                        new PDU((Byte)(0x80 | 0x14), new byte[] { 0x2 }));
                                    message = "Ошибка: Длина запрошенных данных превышает максимальную длину PDU";
                                    result = new Result(Error.RequestError, message, request, answer);

                                    SendResponse(answer);

                                    return result;
                                }
                                else
                                {
                                    // Если оказались в этой точке, значит запрос корректен. Получаем значения
                                    Code0x14SubRequest subRequest;
                                    List<byte> list = new List<byte>(var);
                                    list.Add(System.Convert.ToByte(var - 2)); // Поле Resp. data length

                                    for (int i = 0; i < subRequestList.Length; i++)
                                    {
                                        subRequest = subRequestList[i];

                                        if (_Files.Contains(subRequest.FileNumber) == true)
                                        {
                                            // Файл найден. Получаем его записи
                                            list.Add(System.Convert.ToByte(subRequest.RecordLength * 2 + 1)); // File resp. length
                                            list.Add(0x06); // Ref. type

                                            File file = _Files[subRequest.FileNumber];
                                            
                                            for (int y = 0; y < subRequest.RecordLength; y++)
                                            {
                                                // Проверяем существует ли запись с данным номером
                                                var = System.Convert.ToUInt16(
                                                    subRequest.RecordNumber + System.Convert.ToUInt16(y)); 
                                                if (file.Records.Contains(var) == true)
                                                {
                                                    // Указанная запись существует. Получаем её значение
                                                    // Сохраняем в ответе в виде последоватлеьности байт
                                                    list.AddRange(Modbus.Convert.ConvertToBytes(
                                                        file.Records[var].Value));
                                                }
                                                else
                                                {
                                                    // Указанной записи не существует в данном файле
                                                    // Ошибка. Длина запрощенных данных превышает максимальную
                                                    // длину PDU ответного пакета
                                                    answer = new Message.Message(_Address,
                                                        new PDU((Byte)(0x80 | 0x14), new byte[] { 0x4 }));
                                                    message = String.Format(
                                                        "Ошибка: Не найдена запрашиваемая запись с номером {0} в запрашиваемом файле c номером {0}",
                                                        var, file.Number);
                                                    result = new Result(Error.RequestError, message, request, answer);

                                                    SendResponse(answer);

                                                    return result;
                                                }
                                            }
                                        }
                                        else
                                        {
                                            // Файла с таким номером не существует. Возвращает исключение
                                            answer = new Message.Message(_Address,
                                                new PDU((Byte)(0x80 | 0x14), new byte[] { 0x4 }));
                                            message = String.Format(
                                                "Ошибка: Не найден запрашиваемый файл c номером {0}",
                                                subRequest.FileNumber);
                                            result = new Result(Error.RequestError, message, request, answer);

                                            SendResponse(answer);

                                            return result;
                                        }
                                    }

                                    // Если оказались в данной точке, значит предыдущий цикл выполнился устпешно
                                    // Можно отправлять данные
                                    answer = new Message.Message(_Address,
                                        new PDU(0x14, list.ToArray()));
                                    message = String.Empty;
                                    result = new Result(Error.NoError, message, request, answer);

                                    SendResponse(answer);

                                    return result;
                                }
                            }
                        }
                    }
                }
            }
            //return result;
        }
Beispiel #21
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;
        }