Пример #1
0
        //---------------------------------------------------------------------------
        /// <summary>
        /// Отправляет сообщение с запросом
        /// </summary>
        /// <param name="requst">Запрос</param>
        /// <param name="answer">Ответ</param>
        /// <returns>Результат выполнения операции</returns>
        public RequestError SendMessage(
            Modbus.OSIModel.Message.Message requst,
            out Modbus.OSIModel.Message.Message answer)
        {
            RequestError error;

            Byte[] reply;
            Byte[] tempArray;

            error = SendMessage(requst.Address, requst.PDUFrame.Function,
                                requst.PDUFrame.Data, out reply);

            if (error == RequestError.NoError)
            {
                tempArray = new Byte[reply.Length - 1];
                Array.Copy(reply, 1, tempArray, 0, (reply.Length - 1));

                answer = new Modbus.OSIModel.Message.Message(requst.Address, reply[0], tempArray);
            }
            else
            {
                answer = null;
            }

            return(error);
        }
Пример #2
0
        //---------------------------------------------------------------------------
        /// <summary>
        /// Отправляет сообщение с запросом
        /// </summary>
        /// <param name="requst">Запрос</param>
        /// <param name="answer">Ответ</param>
        /// <returns>Результат выполнения операции</returns>
        public RequestError SendMessage(
            Modbus.OSIModel.Message.Message requst,
            out Modbus.OSIModel.Message.Message answer)
        {
            RequestError error;
            Byte[] reply;
            Byte[] tempArray;

            error = SendMessage(requst.Address, requst.PDUFrame.Function, 
                requst.PDUFrame.Data, out reply);

            if (error == RequestError.NoError)
            {
                tempArray = new Byte[reply.Length - 1];
                Array.Copy(reply, 1, tempArray, 0, (reply.Length - 1));

                answer = new Modbus.OSIModel.Message.Message(requst.Address, reply[0], tempArray);
            }
            else
            {
                answer = null;
            }

            return error;
        }
Пример #3
0
        //---------------------------------------------------------------------------
        /// <summary>
        /// Функция 0х4. Читает входные регистры
        /// </summary>
        /// <param name="AddressSlave">адрес удалённого slave-устройства, 
        /// из которого нужно получить данные</param>
        /// <param name="StartingAddress">Адрес начального входного регистра</param>
        /// <param name="Quantity">Количество регистров для чтения 1...125</param>
        /// <param name="values">Прочатанные значения регистров</param>
        /// <returns>Результат выполнения операции</returns>
        public Message.Result ReadInputRegisters(byte AddressSlave,
            UInt16 StartingAddress, UInt16 Quantity, out UInt16[] values)
        {
            string message;
            Modbus.OSIModel.Message.Message request;
            Modbus.OSIModel.Message.Message answer;
            Modbus.OSIModel.Message.Result result;

            // Данный запрос не может быть широковещательным
            if (AddressSlave == 0)
            {
                message = "Функция с кодом 0х4, не может быть широковещательным запросом";
                throw new ArgumentException(message, "AddressSlave");
            }
            else
            {
                if ((Quantity > 0) && (Quantity <= 125))
                {
                    // Подготавливаем данные
                    List<byte> array = new List<byte>();
                    array.AddRange(Modbus.Convert.ConvertToBytes(StartingAddress));
                    array.AddRange(Modbus.Convert.ConvertToBytes(Quantity));

                    // Формируем запрос
                    request = new Modbus.OSIModel.Message.Message(AddressSlave, 0x4, array.ToArray());
                }
                else
                {
                    message = String.Format("Количество регистров для чтения {0}, должно быть от 1...125",
                        Quantity);
                    throw new ArgumentOutOfRangeException("quantity", message);
                }
            }

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

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

                switch (error)
                {
                    case Modbus.OSIModel.DataLinkLayer.RequestError.NoError:
                        {
                            // Разбираем сообщение на предмет ошибок
                            if (IsError(request, answer, out result))
                            {
                                // Ошибка была
                                values = null;
                                break;
                            }
                            else
                            {
                                // Ошибки нет возвращаем результат выполнения запроса
                                values = new ushort[Quantity];

                                // Проверяем количество байт принятых в ответном сообщении
                                // Их должно быть в два раза больше чем количество регистров
                                // для чтения
                                if (Quantity == (answer.PDUFrame.Data[0] / 2))
                                {
                                    // Количество байт в порядке. Получаем прочитанные значения
                                    // входных регистров
                                    for (int i = 0; i < values.Length; i++)
                                    {
                                        values[i] = answer.PDUFrame.Data[i * 2 + 1];
                                        // старший байт регистра
                                        values[i] = (UInt16)(values[i] << 8);
                                        // младший байт регистра
                                        values[i] = (UInt16)(values[i] | answer.PDUFrame.Data[i * 2 + 2]);
                                    }
                                    result = new Modbus.OSIModel.Message.Result(Error.NoError,
                                        String.Empty, request, answer);
                                }
                                else
                                {
                                    values = null;
                                    result = new Modbus.OSIModel.Message.Result(Error.DataFormatError,
                                        "Поле данных ответа содержит некорректные данные",
                                        request, answer);
                                }

                                break;
                            }
                        }
                    case Modbus.OSIModel.DataLinkLayer.RequestError.TimeOut:
                        {
                            // Таймаут ответа
                            values = null;
                            result = new Modbus.OSIModel.Message.Result(Error.TimeOut,
                                "Ответ не был получен в заданное время", request, null);
                            break;
                        }
                    default:
                        {
                            // Ошибка уровня Datalink layer.
                            values = null;
                            result = new Modbus.OSIModel.Message.Result(Error.ReciveMessageError,
                                error.ToString(), request, null);
                            break;
                        }
                }
                StopTransaction();
                return result;
            }
        }
Пример #4
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;
                }
            }
        }
Пример #5
0
        /// <summary>
        /// Функция 0х3. Формирует сообщение для организации запроса чтения
        /// holding-регистров в физическом устройстве
        /// </summary>
        /// <param name="addressSlave">адрес удалённого slave-устройства, 
        /// из которого нужно получить данные</param>
        /// <param name="startingAddress">Адрес начального holding-регистра</param>
        /// <param name="quantity">Количество holding-регистров для чтения 1...125</param>
        /// <returns>Результат выполения операции</returns>
        public static Message.Message ReadHoldingRegisters(byte addressSlave,
            UInt16 startingAddress, UInt16 quantity)
        {
            string message;
            Modbus.OSIModel.Message.Message request;
            
            // Данный запрос не может быть широковещательным
            if (addressSlave == 0)
            {
                message = "Функция с кодом 0х3, не может быть широковещательным запросом";
                throw new ArgumentException(message, "addressSlave");
            }
            else
            {
                if ((quantity > 0) && (quantity <= 125))
                {
                    // Подготавливаем данные
                    List<byte> array = new List<byte>();
                    array.AddRange(Modbus.Convert.ConvertToBytes(startingAddress));
                    array.AddRange(Modbus.Convert.ConvertToBytes(quantity));

                    // Формируем запрос
                    request = new Modbus.OSIModel.Message.Message(addressSlave, 0x3, array.ToArray());
                }
                else
                {
                    message = String.Format("Количество регистров для чтения {0}, должно быть от 1...125", 
                        quantity);
                    throw new ArgumentOutOfRangeException("quantity", message);
                }
            }
            return request;
        }
Пример #6
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;
        }
Пример #7
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(
     byte addressSlave,
     UInt16 startingAddress, 
     UInt16 quantity, 
     out State[] coils)
 {
     Modbus.OSIModel.Message.Message request;
     
     // Подготавливаем данные
     List<byte> array = new List<byte>();
     array.AddRange(Modbus.Convert.ConvertToBytes(startingAddress));
     array.AddRange(Modbus.Convert.ConvertToBytes(quantity));
     
     request = 
         new Modbus.OSIModel.Message.Message(addressSlave, 0x1, array.ToArray());
     
     // Выполняем запрос
     Message.Result result = ReadCoils(request, out coils);
     
     return result;
 }
Пример #8
0
        /// <summary>
        /// Метод отсылает запрос с определённым пользователем
        /// кодом и данными.
        /// </summary>
        /// <param name="address">Адрес slave-устройства</param>
        /// <param name="code">Код функции</param>
        /// <param name="data">Данные сообщения</param>
        /// <param name="Answer">Ответное сообщение</param>
        /// <returns>Если запрос прошёл успешно возвращается true</returns>
        public Message.Result SendUserDefinedRequest(Byte address,
            Byte code, Byte[] data)
        {
            Modbus.OSIModel.Message.Message request, answer;
            Modbus.OSIModel.Message.Result result;

            // Проверяем состояние сервера
            if (_flgBusy == true)
            {
                throw new Exception(String.Format(
                    "Попытка выполнить запрос User defined к серверу {0}, во время выполнения предыдущего",
                    Name));
            }
            else
            {
                StartTransaction();

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

                switch (error)
                {
                    case Modbus.OSIModel.DataLinkLayer.RequestError.NoError:
                        {
                            // Разбираем сообщение на предмет ошибок
                            if (IsError(request, answer, out result))
                            {
                                // Ошибка была
                                break;
                            }
                            else
                            {
                                // Ошибки нет возвращаем результат выполнения запроса
                                result = new Modbus.OSIModel.Message.Result(Error.NoError,
                                    String.Empty, request, answer);
                                break;
                            }
                        }
                    case Modbus.OSIModel.DataLinkLayer.RequestError.TimeOut:
                        {
                            // Таймаут ответа
                            result = new Modbus.OSIModel.Message.Result(Error.TimeOut,
                                "Ответ не был получен в заданное время", request, null);
                            break;
                        }
                    default:
                        {
                            // Ошибка уровня Datalink layer.
                            result = new Modbus.OSIModel.Message.Result(Error.ReciveMessageError,
                                error.ToString(), request, null);
                            break;
                        }
                }
                StopTransaction();
                return result;
            }
        }
Пример #9
0
        /// <summary>
        /// Функция 0x6. Формирует запрос на запись регистра хранения
        /// в физическом устройстве
        /// </summary>
        /// <param name="addressSlave">адрес удалённого slave-устройства, 
        /// в котором нужно записать регистр хранения</param>
        /// <param name="addressRegister">адерс регистра хранения</param>
        /// <param name="value">значение регистра</param>
        /// <returns>Modus-запрос</returns>
        public static Message.Message WriteSingleRegister(byte addressSlave,
            UInt16 addressRegister, UInt16 value)
        {
            Modbus.OSIModel.Message.Message request;

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

            // Возвращаем запрос
            request = new Modbus.OSIModel.Message.Message(addressSlave, 0x6, array.ToArray());
            return request;
        }