Exemplo n.º 1
0
 /// <summary>
 /// Parses a telegram received by ReceiveTelegram.
 /// </summary>
 /// <param name="buffer">Buffer containing the data.</param>
 /// <param name="telegramLength">Total length of the telegram in bytes.</param>
 /// <param name="isResponse">true if the telegram is a response telegram; false if the telegram is a request telegram.</param>
 /// <param name="telegramContext">
 /// If isResponse == true: pass the telegramContext returned by CreateTelegram from the request.
 /// If isResponse == false: returns the telegramContext from the received request. It must pe passed to the CreateTelegram method for the response.
 /// </param>
 /// <param name="address">Returns the device address.</param>
 /// <param name="fkt">Returns the function code.</param>
 /// <param name="dataPos">Returns the offset in buffer of the function code specific data.</param>
 /// <param name="dataLength">Returns the length of the function code specific data.</param>
 /// <returns>Returns true if this is the matching response according to the telegramContext; else false. If isResponse == false this method should return always true.</returns>
 public bool ParseTelegram(byte[] buffer, short telegramLength, bool isResponse, ref object telegramContext, out byte address,
                           out byte fkt, out short dataPos, out short dataLength)
 {
     if (telegramLength < 8)
     {
         throw new ModbusException(ModbusErrorCode.ResponseTooShort);
     }
     if (isResponse)
     {
         if (telegramContext is ushort)
         {
             ushort transactionId = ModbusUtils.ExtractUShort(buffer, 0);
             if (transactionId != (ushort)telegramContext)
             {
                 // telegram does not match
                 address    = 0;
                 fkt        = 0;
                 dataPos    = 0;
                 dataLength = 0;
                 return(false);
             }
         }
     }
     else
     {
         telegramContext = ModbusUtils.ExtractUShort(buffer, 0);
     }
     address    = buffer[6];
     fkt        = buffer[7];
     dataPos    = 8;
     dataLength = (short)(telegramLength - 8);
     return(true);
 }
        protected override void Finished(string sid, string portName, string receivedData)
        {
            if (ModbusUtils.CRC("01", "02", "01 00").Equals(receivedData))
            {
                this.handleResult(sid, portName, 0);
                return;
            }

            if (ModbusUtils.CRC("01", "02", "01 01").Equals(receivedData))
            {
                this.handleResult(sid, portName, 1);
                return;
            }

            if (ModbusUtils.CRC("01", "02", "01 02").Equals(receivedData))
            {
                this.handleResult(sid, portName, 2);
                return;
            }

            if (ModbusUtils.CRC("01", "02", "01 03").Equals(receivedData))
            {
                this.handleResult(sid, portName, 3);
                return;
            }

            // TODO 记录异常日志
            this.handleResult(sid, portName, -1);
        }
Exemplo n.º 3
0
        /// <summary>
        /// Создать узел группы элементов
        /// </summary>
        private TreeNode NewElemGroupNode(ElemGroup elemGroup)
        {
            string   name   = elemGroup.Name == "" ? KpPhrases.DefGrName : elemGroup.Name;
            TreeNode grNode = new TreeNode(name + " (" + ModbusUtils.GetTableTypeName(elemGroup.TableType) + ")");

            grNode.ImageKey = grNode.SelectedImageKey = elemGroup.Active ? "group.png" : "group_inactive.png";
            grNode.Tag      = elemGroup;

            ushort elemAddr = elemGroup.Address;
            int    elemSig  = elemGroup.StartKPTagInd + 1;

            foreach (Elem elem in elemGroup.Elems)
            {
                ElemInfo elemInfo = new ElemInfo()
                {
                    Elem      = elem,
                    ElemGroup = elemGroup,
                    Settings  = template.Sett,
                    Address   = elemAddr,
                    Signal    = elemSig++
                };

                grNode.Nodes.Add(NewElemNode(elemInfo));
                elemAddr += (ushort)elem.Quantity;
            }

            return(grNode);
        }
Exemplo n.º 4
0
 /// <summary>
 /// Получить обозначение команды в дереве
 /// </summary>
 private string GetCmdCaption(ModbusCmd modbusCmd)
 {
     return((string.IsNullOrEmpty(modbusCmd.Name) ? KpPhrases.DefCmdName : modbusCmd.Name) +
            " (" + ModbusUtils.GetTableTypeName(modbusCmd.TableType) + ", " +
            ModbusUtils.GetAddressRange(modbusCmd.Address, modbusCmd.ElemCnt,
                                        template.Sett.ZeroAddr, template.Sett.DecAddr) + ")");
 }
Exemplo n.º 5
0
        /// <summary>
        /// Waits and receives a telegram.
        /// </summary>
        /// <param name="buffer">Buffer to write data into.</param>
        /// <param name="desiredDataLength">Desired length of the function code specific data in bytes. -1 if length is unknown.</param>
        /// <param name="timeout">Timeout in milliseconds to wait for the telegram.</param>
        /// <param name="telegramLength">Returns the total length of the telegram in bytes.</param>
        /// <returns>Returns true if the telegram was received successfully; false on timeout.</returns>
        public bool ReceiveTelegram(byte[] buffer, short desiredDataLength, int timeout, out short telegramLength)
        {
            if (_Socket == null)
            {
                throw new ObjectDisposedException("ModbusTcp interface");
            }
            if (!_Socket.Poll(timeout * 1000, SelectMode.SelectRead) || _Socket.Available == 0)
            {
                telegramLength = 0;
                return(false);
            }
            // get the 1st 6 bytes, which includes the remaining length
            int pos = 0;

            while (pos < 6)
            {
                pos += _Socket.Receive(buffer, pos, 6 - pos, SocketFlags.None);
            }
            telegramLength = (short)(ModbusUtils.ExtractUShort(buffer, 4) + 6);

            // receive remaining data
            while (pos < telegramLength)
            {
                pos += _Socket.Receive(buffer, pos, telegramLength - pos, SocketFlags.None);
            }
            return(true);
        }
Exemplo n.º 6
0
        /// <summary>
        /// Gets the appropriate default byte order as array.
        /// </summary>
        public int[] GetDefaultByteOrder(int byteCnt)
        {
            switch (byteCnt)
            {
            case 2:
                if (byteOrderArr2 == null)
                {
                    byteOrderArr2 = ModbusUtils.ParseByteOrder(DefByteOrder2);
                }
                return(byteOrderArr2);

            case 4:
                if (byteOrderArr4 == null)
                {
                    byteOrderArr4 = ModbusUtils.ParseByteOrder(DefByteOrder4);
                }
                return(byteOrderArr4);

            case 8:
                if (byteOrderArr8 == null)
                {
                    byteOrderArr8 = ModbusUtils.ParseByteOrder(DefByteOrder8);
                }
                return(byteOrderArr8);

            default:
                return(null);
            }
        }
Exemplo n.º 7
0
 /// <summary>
 /// Обновить узел выбранной группы элементов
 /// </summary>
 private void UpdateElemGroupNode()
 {
     if (selElemGroup != null)
     {
         selNode.ImageKey = selNode.SelectedImageKey = selElemGroup.Active ? "group.png" : "group_inactive.png";
         selNode.Text     = (selElemGroup.Name == "" ? KpPhrases.DefGrName : selElemGroup.Name) +
                            " (" + ModbusUtils.GetTableTypeName(selElemGroup.TableType) + ")";
     }
 }
Exemplo n.º 8
0
        public void SwapsEndiannessGeneric <T>(T[] dataset, T[] expected) where T : unmanaged
        {
            // Act
            ModbusUtils.SwitchEndianness(dataset.AsSpan());
            var actual = dataset;

            // Assert
            Assert.Equal(actual, expected);
        }
Exemplo n.º 9
0
        public void CanParseEndpoint(string endpoint)
        {
            // Arrange
            var expected = IPEndPoint.Parse(endpoint);

            // Act
            var success = ModbusUtils.TryParseEndpoint(endpoint, out var actual);

            // Assert
            Assert.True(success);
            Assert.Equal(expected, actual);
        }
Exemplo n.º 10
0
 /// <summary>
 /// Shows the function code of the element group.
 /// </summary>
 private void ShowFuncCode(ElemGroupConfig elemGroup)
 {
     if (elemGroup == null)
     {
         txtGrFuncCode.Text = "";
     }
     else
     {
         byte funcCode = ModbusUtils.GetReadFuncCode(elemGroup.DataBlock);
         txtGrFuncCode.Text = string.Format("{0} ({1}h)", funcCode, funcCode.ToString("X2"));
     }
 }
Exemplo n.º 11
0
        public void CalculatesCrcCorrectly()
        {
            // Arrange
            var data = new byte[] { 0xA0, 0xB1, 0xC2 };

            // Act
            var expected = 0x2384;
            var actual   = ModbusUtils.CalculateCRC(data);

            // Assert
            Assert.Equal(actual, expected);
        }
Exemplo n.º 12
0
        public void SwapsEndiannessUShort()
        {
            // Arrange
            var data = (ushort)512;

            // Act
            var expected = (ushort)2;
            var actual   = ModbusUtils.SwitchEndianness(data);

            // Assert
            Assert.Equal(actual, expected);
        }
Exemplo n.º 13
0
        public void SwapsEndiannessMidLittleEndian()
        {
            // Arrange
            var data = (uint)0x01020304;

            // Act
            var expected = (uint)0x02010403;
            var actual1  = ModbusUtils.ConvertBetweenLittleEndianAndMidLittleEndian(data);
            var actual2  = ModbusUtils.ConvertBetweenLittleEndianAndMidLittleEndian(actual1);

            // Assert
            Assert.Equal(expected, actual1);
            Assert.Equal(data, actual2);
        }
Exemplo n.º 14
0
        /// <summary>
        /// Sends the given telegram.
        /// If necessary additional information like a checksum can be inserted here.
        /// </summary>
        /// <param name="buffer">Buffer containing the data.</param>
        /// <param name="telegramLength">Length of the telegram in bytes.</param>
        public void SendTelegram(byte[] buffer, short telegramLength)
        {
            var crc = ModbusUtils.CalcCrc(buffer, telegramLength - 2);

            buffer[telegramLength - 2] = (byte)(crc & 0x00ff);
            buffer[telegramLength - 1] = (byte)((crc & 0xff00) >> 8);

            // ticks and _NextSend are multiples of 100 ns
            var dt = _nextSend - DateTime.Now.Ticks;

            if (dt > 0)
            {
                Thread.Sleep(Math.Max(1, (int)dt / 10000));
            }

            // clear buffers
            _serial.DiscardInBuffer();
            _serial.DiscardOutBuffer();

            // next send is 3.5 chars after the end of this telegram
            _nextSend = DateTime.Now.Ticks + (telegramLength * 2 + 7) * _halfCharLength;
#if NETMF
            try
            {
                _serial.Write(buffer, 0, telegramLength);
                // make sure all bytes are sent out
                _serial.Flush();
            }
            catch (ArgumentException)
            {
                // happens some times -> Close -> Open -> try again
                try
                {
                    _serial.Close();
                }
                catch
                {
                    // ignored
                }
                _serial.Open();
                _serial.Write(buffer, 0, telegramLength);
                _serial.Flush();
            }
#else
            _serial.Write(buffer, 0, telegramLength);
#endif
        }
Exemplo n.º 15
0
        /// <summary>
        /// Gets the command node text.
        /// </summary>
        private string GetCmdNodeText(CmdConfig cmd)
        {
            string cmdName   = string.IsNullOrEmpty(cmd.Name) ? ModbusDriverPhrases.UnnamedCommand : cmd.Name;
            string blockName = ModbusUtils.GetDataBlockName(cmd.DataBlock);

            if (cmd.DataBlock == DataBlock.Custom)
            {
                return(string.Format("{0} ({1})", cmdName, blockName));
            }
            else
            {
                string addrRange = ModbusUtils.GetAddressRange(cmd.Address,
                                                               cmd.ElemCnt * ModbusUtils.GetQuantity(cmd.ElemType),
                                                               template.Options.ZeroAddr, template.Options.DecAddr);
                return(string.Format("{0} ({1}, {2})", cmdName, blockName, addrRange));
            }
        }
Exemplo n.º 16
0
        /// <summary>
        /// Creates a new Modbus command based on the element configuration.
        /// </summary>
        private ModbusCmd CreateModbusCmd(DeviceTemplateOptions options,
                                          ElemGroupConfig elemGroupConfig, ElemConfig elemConfig, int elemIndex)
        {
            ModbusCmd modbusCmd = deviceModel.CreateModbusCmd(elemGroupConfig.DataBlock, false);

            modbusCmd.Name      = elemConfig.Name;
            modbusCmd.Address   = (ushort)(elemGroupConfig.Address + elemIndex);
            modbusCmd.ElemType  = elemConfig.ElemType;
            modbusCmd.ElemCnt   = 1;
            modbusCmd.ByteOrder = ModbusUtils.ParseByteOrder(elemConfig.ByteOrder) ??
                                  options.GetDefaultByteOrder(ModbusUtils.GetDataLength(elemConfig.ElemType));
            modbusCmd.CmdNum  = 0;
            modbusCmd.CmdCode = elemConfig.TagCode;

            modbusCmd.InitReqPDU();
            modbusCmd.InitReqADU(deviceModel.Addr, transMode);
            return(modbusCmd);
        }
Exemplo n.º 17
0
 /// <summary>
 /// Shows the function code of the command.
 /// </summary>
 private void ShowFuncCode(CmdConfig cmd)
 {
     if (cmd == null)
     {
         numCmdFuncCode.Value    = 0;
         numCmdFuncCode.ReadOnly = true;
     }
     else if (cmd.DataBlock == DataBlock.Custom)
     {
         numCmdFuncCode.Value    = (byte)cmd.CustomFuncCode;
         numCmdFuncCode.ReadOnly = false;
     }
     else
     {
         numCmdFuncCode.Value    = ModbusUtils.GetWriteFuncCode(cmd.DataBlock, cmd.Multiple);
         numCmdFuncCode.ReadOnly = true;
     }
 }
Exemplo n.º 18
0
        /// <summary>
        /// Parses a telegram received by ReceiveTelegram.
        /// </summary>
        /// <param name="buffer">Buffer containing the data.</param>
        /// <param name="telegramLength">Total length of the telegram in bytes.</param>
        /// <param name="isResponse">true if the telegram is a response telegram; false if the telegram is a request telegram.</param>
        /// <param name="telegramContext">
        /// If isResponse == true: pass the telegramContext returned by CreateTelegram from the request.
        /// If isResponse == false: returns the telegramContext from the received request. It must pe passed to the CreateTelegram method for the response.
        /// </param>
        /// <param name="address">Returns the device address.</param>
        /// <param name="fkt">Returns the function code.</param>
        /// <param name="dataPos">Returns the offset in buffer of the function code specific data.</param>
        /// <param name="dataLength">Returns the length of the function code specific data.</param>
        /// <returns>Returns true if this is the matching response according to the telegramContext; else false. If isResponse == false this method should return always true.</returns>
        public bool ParseTelegram(byte[] buffer, short telegramLength, bool isResponse, ref object telegramContext, out byte address, out byte fkt,
                                  out short dataPos, out short dataLength)
        {
            if (telegramLength < 4)
            {
                throw new ModbusException(ModbusErrorCode.ResponseTooShort);
            }
            var crc = ModbusUtils.CalcCrc(buffer, telegramLength - 2);

            if (buffer[telegramLength - 2] != (byte)(crc & 0x00ff) ||
                buffer[telegramLength - 1] != (byte)((crc & 0xff00) >> 8))
            {
                throw new ModbusException(ModbusErrorCode.CrcError);
            }
            address    = buffer[0];
            fkt        = buffer[1];
            dataPos    = 2;
            dataLength = (short)(telegramLength - 4);
            return(true);
        }
Exemplo n.º 19
0
        private void cbCmdElemType_SelectedIndexChanged(object sender, EventArgs e)
        {
            // изменение типа элементов
            if (modbusCmd != null)
            {
                ElemType newElemType = (ElemType)cbCmdElemType.SelectedIndex;

                if (modbusCmd.TableType == TableType.HoldingRegisters && newElemType == ElemType.Bool)
                {
                    // отмена выбора типа Bool для регистров хранения
                    cbCmdElemType.SelectedIndexChanged -= cbCmdElemType_SelectedIndexChanged;
                    cbCmdElemType.SelectedIndex         = (int)modbusCmd.ElemType;
                    cbCmdElemType.SelectedIndexChanged += cbCmdElemType_SelectedIndexChanged;
                }
                else
                {
                    modbusCmd.ElemType  = newElemType;
                    numCmdElemCnt.Value = ModbusUtils.GetElemCount(modbusCmd.ElemType);
                    OnObjectChanged(TreeUpdateTypes.None);
                }
            }
        }
Exemplo n.º 20
0
        /// <summary>
        /// Creates a new Modbus command based on the command configuration.
        /// </summary>
        private ModbusCmd CreateModbusCmd(DeviceTemplateOptions options, CmdConfig cmdConfig)
        {
            ModbusCmd modbusCmd = deviceModel.CreateModbusCmd(cmdConfig.DataBlock, cmdConfig.Multiple);

            modbusCmd.Name      = cmdConfig.Name;
            modbusCmd.Address   = (ushort)cmdConfig.Address;
            modbusCmd.ElemType  = cmdConfig.ElemType;
            modbusCmd.ElemCnt   = cmdConfig.ElemCnt;
            modbusCmd.ByteOrder = ModbusUtils.ParseByteOrder(cmdConfig.ByteOrder) ??
                                  options.GetDefaultByteOrder(ModbusUtils.GetDataLength(cmdConfig.ElemType) * cmdConfig.ElemCnt);
            modbusCmd.CmdNum  = cmdConfig.CmdNum;
            modbusCmd.CmdCode = cmdConfig.CmdCode;

            if (cmdConfig.DataBlock == DataBlock.Custom)
            {
                modbusCmd.SetFuncCode((byte)cmdConfig.CustomFuncCode);
            }

            modbusCmd.InitReqPDU();
            modbusCmd.InitReqADU(deviceModel.Addr, transMode);
            return(modbusCmd);
        }
Exemplo n.º 21
0
        /// <summary>
        /// Creates a new telegram for a modbus request or response.
        /// All data except the function code specific user data is written into the given buffer.
        /// </summary>
        /// <param name="addr">Device address. 0 = Breadcast, 1..247 are valid device addresses.</param>
        /// <param name="fkt">Function code. <see cref="ModbusFunctionCode"/></param>
        /// <param name="dataLength">Number of bytes for function code sspecific user data.</param>
        /// <param name="buffer">Buffer to write data into. The buffer must be at least MaxTelegramLength - MaxDataLength + dataLength bytes long.</param>
        /// <param name="telegramLength">Returns the total length of the telegram in bytes.</param>
        /// <param name="dataPos">Returns the offset of the function code specific user data in buffer.</param>
        /// <param name="isResponse">true if this is a response telegram; false if this is a request telegram.</param>
        /// <param name="telegramContext">
        /// If isResponse == false, this parameter returns the interface implementation specific data which must be passed to the ParseTelegram method of the received response.
        /// If isResponse == true, this parameter must be called with the telegramContext parameter returned by ParseTelegram of the request telegram.</param>
        public void CreateTelegram(byte addr, byte fkt, short dataLength, byte[] buffer, out short telegramLength, out short dataPos,
                                   bool isResponse, ref object telegramContext)
        {
            telegramLength = (short)(8 + dataLength);

            if (isResponse)
            {
                // in a response we insert the given telegramContext as transaction id
                if (telegramContext is ushort)
                {
                    ModbusUtils.InsertUShort(buffer, 0, (ushort)telegramContext);
                }
                else
                {
                    ModbusUtils.InsertUShort(buffer, 0, 0);
                }
            }
            else
            {
                // insert new transaction id into request
                telegramContext = _NextTransactionId;
                if (_NextTransactionId == 0xffff)
                {
                    ModbusUtils.InsertUShort(buffer, 0, 0xffff);
                    _NextTransactionId = 0;
                }
                else
                {
                    ModbusUtils.InsertUShort(buffer, 0, _NextTransactionId++);
                }
            }
            ModbusUtils.InsertUShort(buffer, 2, 0);
            ModbusUtils.InsertUShort(buffer, 4, (ushort)(telegramLength - 6));
            buffer[6] = addr;
            buffer[7] = fkt;
            dataPos   = 8;
        }
Exemplo n.º 22
0
        /// <summary>
        /// Sends the given telegram.
        /// If necessary additional information like a checksum can be inserted here.
        /// </summary>
        /// <param name="buffer">Buffer containing the data.</param>
        /// <param name="telegramLength">Length of the telegram in bytes.</param>
        public void SendTelegram(byte[] buffer, short telegramLength)
        {
            var crc = ModbusUtils.CalcCrc(buffer, telegramLength - 2);

            buffer[telegramLength - 2] = (byte)(crc & 0x00ff);
            buffer[telegramLength - 1] = (byte)((crc & 0xff00) >> 8);

            // ticks and _NextSend are multiples of 100 ns
            var dt = this.nextSend - DateTime.Now.Ticks;

            if (dt > 0)
            {
                Thread.Sleep(Math.Max(1, (int)dt / 10000));
            }

            // clear buffers
            this.serial.ClearReadBuffer();
            this.serial.ClearWriteBuffer();

            // next send is 3.5 chars after the end of this telegram
            this.nextSend = DateTime.Now.Ticks + (telegramLength * 2 + 7) * this.halfCharLength;

            this.serial.Write(buffer, 0, telegramLength);
        }
Exemplo n.º 23
0
 /// <summary>
 ///     入队一条指令(MODBUS协议)
 /// </summary>
 /// <param name="allowDiscard">是否允许丢弃该指令</param>
 /// <param name="cmdEventHandler">串口指令事件处理器</param>
 /// <param name="sendCMDTimeout">发送指令超时时长(毫秒)</param>
 /// <param name="reciveDataTimeout">接收数据超时时长(毫秒)</param>
 /// <param name="address">指令-地址码</param>
 /// <param name="func">指令-功能码</param>
 /// <param name="data">指令-数据</param>
 public void EnqueueModbus(Boolean allowDiscard, SerialPortCMDEventHandler cmdEventHandler, int sendCMDTimeout, int reciveDataTimeout, String address, String func, String data)
 {
     EnqueueHexString(allowDiscard, cmdEventHandler, sendCMDTimeout, reciveDataTimeout, ModbusUtils.CRC(address, func, data));
 }
Exemplo n.º 24
0
 /// <summary>
 /// Gets the command node text.
 /// </summary>
 private static string GetElemGroupNodeText(ElemGroupConfig elemGroup)
 {
     return(string.Format("{0} ({1})",
                          string.IsNullOrEmpty(elemGroup.Name) ? ModbusDriverPhrases.UnnamedElemGroup : elemGroup.Name,
                          ModbusUtils.GetDataBlockName(elemGroup.DataBlock)));
 }
Exemplo n.º 25
0
        /// <summary>
        /// Gets the channel prototypes for the device.
        /// </summary>
        public override ICollection <CnlPrototype> GetCnlPrototypes()
        {
            if (LoadDeviceTemplate() is not DeviceTemplate deviceTemplate)
            {
                return(null);
            }

            List <CnlPrototype> cnlPrototypes = new();
            int tagNum = 1;

            foreach (ElemGroupConfig elemGroupConfig in deviceTemplate.ElemGroups)
            {
                foreach (ElemConfig elemConfig in elemGroupConfig.Elems)
                {
                    // create channel for element
                    bool isBool    = elemConfig.ElemType == ElemType.Bool;
                    int  eventMask = new EventMask
                    {
                        Enabled      = true,
                        DataChange   = isBool,
                        StatusChange = !isBool,
                        Command      = !elemConfig.ReadOnly
                    }.Value;

                    cnlPrototypes.Add(new CnlPrototype
                    {
                        Active     = elemGroupConfig.Active,
                        Name       = elemConfig.Name,
                        CnlTypeID  = elemConfig.ReadOnly ? CnlTypeID.Input : CnlTypeID.InputOutput,
                        TagNum     = string.IsNullOrEmpty(elemConfig.TagCode) ? tagNum : null,
                        TagCode    = elemConfig.TagCode,
                        FormatCode = isBool
                            ? FormatCode.OffOn
                            : elemConfig.IsBitMask ? FormatCode.X : null,
                        EventMask = eventMask
                    });

                    // create channels for bit mask
                    if (elemConfig.IsBitMask && elemConfig.ElemType != ElemType.Bool)
                    {
                        eventMask = new EventMask
                        {
                            Enabled    = true,
                            DataChange = true,
                            Command    = !elemConfig.ReadOnly
                        }.Value;

                        for (int bit = 0, bitCnt = ModbusUtils.GetDataLength(elemConfig.ElemType) * 8;
                             bit < bitCnt; bit++)
                        {
                            cnlPrototypes.Add(new CnlPrototype
                            {
                                Active         = elemGroupConfig.Active,
                                Name           = elemConfig.Name + "[" + bit + "]",
                                CnlTypeID      = elemConfig.ReadOnly ? CnlTypeID.Calculated : CnlTypeID.CalculatedOutput,
                                FormatCode     = FormatCode.OffOn,
                                FormulaEnabled = true,
                                InFormula      = $"GetBit(DataRel({-bit - 1}), {bit})",
                                OutFormula     = elemConfig.ReadOnly ? null : $"SetBit(DataRel({-bit - 1}), {bit}, Cmd)",
                                EventMask      = eventMask
                            });
                        }
                    }

                    tagNum++;
                }
            }

            // create channels for commands
            int cmdEventMask = new EventMask {
                Enabled = true, Command = true
            }.Value;

            foreach (CmdConfig cmdConfig in deviceTemplate.Cmds)
            {
                cnlPrototypes.Add(new CnlPrototype
                {
                    Name       = cmdConfig.Name,
                    CnlTypeID  = CnlTypeID.Output,
                    TagNum     = string.IsNullOrEmpty(cmdConfig.CmdCode) ? cmdConfig.CmdNum : null,
                    TagCode    = cmdConfig.CmdCode,
                    FormatCode = cmdConfig.DataBlock == DataBlock.Coils && !cmdConfig.Multiple ?
                                 FormatCode.OffOn : null,
                    EventMask = cmdEventMask
                });
            }

            return(cnlPrototypes);
        }
        private int byteLength   = 0;  // 部分响应信息字节长度

        /// <summary>
        ///     开始打开串口
        /// </summary>
        /// <param name="SerialDataReceivedEventHandlerX">串口数据接收事件处理器扩展</param>
        /// <param name="BeforeOpen">尝试打开串口前操作</param>
        /// <param name="OpenSuccess">尝试打开串口成功操作</param>
        /// <param name="OpenError">尝试打开串口失败操作</param>
        /// <param name="StillOpen">仍处于打开状态操作</param>
        /// <param name="Disconnect">已经断开操作</param>
        /// <param name="BeforeReOpen">尝试重新打开串口前操作</param>
        /// <param name="ReOpenSuccess">尝试重新打开串口成功操作</param>
        /// <param name="ReOpenError">尝试重新打开串口失败操作</param>
        /// <param name="AfterOpen">串口打开后操作</param>
        internal void Start(
            SerialDataReceivedEventHandlerX SerialDataReceivedEventHandlerX,
            BeforeOpen BeforeOpen,
            OpenSuccess OpenSuccess,
            OpenError OpenError,
            StillOpen StillOpen,
            Disconnect Disconnect,
            BeforeReOpen BeforeReOpen,
            ReOpenSuccess ReOpenSuccess,
            ReOpenError ReOpenError,
            AfterOpen AfterOpen
            )
        {
            // 设置串口数据接收事件处理器
            serialPort.DataReceived += new System.IO.Ports.SerialDataReceivedEventHandler((sender, e) =>
            {
                if (IsClosed)
                {
                    return;
                }
                byte[] readedBytes = new byte[serialPort.BytesToRead];
                int byteLength     = readedBytes.Length;
                if (byteLength == 0)
                {
                    CMDQueue.CancelCurrentCMD();
                    return;
                }
                serialPort.Read(readedBytes, 0, byteLength);
                String hexString = HexUtils.BytesToHexString(readedBytes, true).Trim();
                if ("".Equals(hexString))
                {
                    CMDQueue.CancelCurrentCMD();
                    return;
                }
                if (ModbusUtils.IsFullCmd(hexString))
                {
                    if (useCMDQueue)
                    {
                        CMDQueue.FinishCurrentCMD(hexString);
                    }
                    SerialDataReceivedEventHandlerX?.Invoke(this.sid, this.portName, hexString);
                    this.hexString  = "";
                    this.byteLength = 0;
                }
                else
                {
                    this.hexString  += " " + hexString;
                    this.hexString   = this.hexString.Trim();
                    this.byteLength += byteLength;
                    if (ModbusUtils.IsFullCmd(this.hexString))
                    {
                        if (useCMDQueue)
                        {
                            CMDQueue.FinishCurrentCMD(hexString);
                        }
                        SerialDataReceivedEventHandlerX?.Invoke(this.sid, this.portName, this.hexString);
                        this.hexString  = "";
                        this.byteLength = 0;
                    }
                }
            });

            // 每100毫秒执行一次指令队列
            if (useCMDQueue)
            {
                CMDQueue = new SerialPortCMDQueue(this.sid, this.portName, serialPort);
                CMDQueue.Start();
            }

            BeforeOpen?.Invoke(this.sid, this.portName);      // 尝试打开串口前操作
            if (this.Open())                                  // 尝试打开串口
            {
                OpenSuccess?.Invoke(this.sid, this.portName); // 尝试打开串口成功操作
                OpenStatus = true;
                if (AfterOpen != null)
                {
                    AfterOpenEventHandlerListenerTimer = new Timer((obj) =>
                    {
                        AfterOpen(this.sid, this.portName);// 串口打开后操作
                    }, null, 0, this.afterOpenEventHandlerPeriod);
                }
            }
            else
            {
                OpenError?.Invoke(this.sid, this.portName);// 尝试打开串口失败操作
                OpenStatus = null;
                if (AfterOpen != null)
                {
                    AfterOpenEventHandlerListenerTimer = new Timer((obj) =>
                    {
                        if (IsClosed)
                        {
                            return;
                        }
                        AfterOpen(this.sid, this.portName);// 串口打开后操作
                    }, null, Timeout.Infinite, Timeout.Infinite);
                }
            }
            // 无论打开成功与否,后续都需要监听该串口是否处于打开状态。
            OpenStatusListenerTimer = new Timer((o) =>
            {
                if (IsClosed)
                {
                    return;
                }
                switch (OpenStatus)                                         // 上一次的串口打开状态
                {
                case null:                                                  // 首次打开串口失败
                case false:                                                 // 后续打开串口失败
                    {
                        BeforeReOpen?.Invoke(this.sid, this.portName);      // 尝试重新打开串口前操作
                        if (this.Open())                                    // 尝试重新打开串口
                        {
                            ReOpenSuccess?.Invoke(this.sid, this.portName); // 尝试重新打开串口成功操作
                            OpenStatus = true;
                            if (AfterOpen != null)
                            {
                                AfterOpenEventHandlerListenerTimer.Change(0, this.afterOpenEventHandlerPeriod);    // 重新开启计时器
                            }
                        }
                        else
                        {
                            ReOpenError?.Invoke(this.sid, this.portName);    // 尝试重新打开串口失败
                            OpenStatus = false;
                        }
                    }
                    break;

                case true:                                              // 首次或后续打开串口成功
                    {
                        if (serialPort.IsOpen)                          // 仍处于打开状态
                        {
                            StillOpen?.Invoke(this.sid, this.portName); // 仍处于打开状态操作
                            OpenStatus = true;
                        }
                        else                                             // 已经断开
                        {
                            Disconnect?.Invoke(this.sid, this.portName); // 已经断开操作
                            OpenStatus = false;
                            if (AfterOpen != null)
                            {
                                AfterOpenEventHandlerListenerTimer.Change(Timeout.Infinite, Timeout.Infinite);    // 暂停计时器
                            }
                        }
                    }
                    break;
                }
            }, null, this.checkOpenStatusPeriod, this.checkOpenStatusPeriod);
        }
Exemplo n.º 27
0
        /// <summary>
        /// Initializes the device tags.
        /// </summary>
        public override void InitDeviceTags()
        {
            DeviceTemplate deviceTemplate = GetDeviceTemplate();

            if (deviceTemplate == null)
            {
                return;
            }

            // create device model
            deviceModel      = CreateDeviceModel();
            deviceModel.Addr = (byte)NumAddress;

            // add model elements and device tags
            foreach (ElemGroupConfig elemGroupConfig in deviceTemplate.ElemGroups)
            {
                bool      groupActive   = elemGroupConfig.Active;
                bool      groupCommands = groupActive && elemGroupConfig.ReadOnlyEnabled;
                ElemGroup elemGroup     = null;
                TagGroup  tagGroup      = new TagGroup(elemGroupConfig.Name)
                {
                    Hidden = !groupActive
                };
                int elemIndex = 0;

                if (groupActive)
                {
                    elemGroup             = deviceModel.CreateElemGroup(elemGroupConfig.DataBlock);
                    elemGroup.Name        = elemGroupConfig.Name;
                    elemGroup.Address     = (ushort)elemGroupConfig.Address;
                    elemGroup.StartTagIdx = DeviceTags.Count;
                }

                foreach (ElemConfig elemConfig in elemGroupConfig.Elems)
                {
                    // add model element
                    if (groupActive)
                    {
                        Elem elem = elemGroup.CreateElem();
                        elem.Name      = elemConfig.Name;
                        elem.ElemType  = elemConfig.ElemType;
                        elem.ByteOrder = ModbusUtils.ParseByteOrder(elemConfig.ByteOrder) ??
                                         deviceTemplate.Options.GetDefaultByteOrder(ModbusUtils.GetDataLength(elemConfig.ElemType));
                        elemGroup.Elems.Add(elem);
                    }

                    // add model command
                    if (groupCommands && !elemConfig.ReadOnly && !string.IsNullOrEmpty(elemConfig.TagCode))
                    {
                        deviceModel.Cmds.Add(
                            CreateModbusCmd(deviceTemplate.Options, elemGroupConfig, elemConfig, elemIndex));
                    }

                    // add device tag
                    tagGroup.AddTag(elemConfig.TagCode, elemConfig.Name).SetFormat(GetTagFormat(elemConfig));
                    elemIndex++;
                }

                if (groupActive)
                {
                    elemGroup.InitReqPDU();
                    elemGroup.InitReqADU(deviceModel.Addr, transMode);
                    deviceModel.ElemGroups.Add(elemGroup);
                }

                DeviceTags.AddGroup(tagGroup);
            }

            // add model commands
            foreach (CmdConfig cmdConfig in deviceTemplate.Cmds)
            {
                deviceModel.Cmds.Add(CreateModbusCmd(deviceTemplate.Options, cmdConfig));
            }

            deviceModel.InitCmdMap();
            CanSendCommands = deviceModel.Cmds.Count > 0;
            InitModbusPoll();
        }
Exemplo n.º 28
0
        /// <summary>
        /// Waits and receives a telegram.
        /// </summary>
        /// <param name="buffer">Buffer to write data into.</param>
        /// <param name="desiredDataLength">Desired length of the function code specific data in bytes. -1 if length is unknown.</param>
        /// <param name="timeout">Timeout in milliseconds to wait for the telegram.</param>
        /// <param name="telegramLength">Returns the total length of the telegram in bytes.</param>
        /// <returns>Returns true if the telegram was received successfully; false on timeout.</returns>
        public bool ReceiveTelegram(byte[] buffer, short desiredDataLength, int timeout, out short telegramLength)
        {
            short desiredLength;

            if (desiredDataLength >= 0)
            {
                desiredLength = (short)(desiredDataLength + 4);
                if (desiredLength > buffer.Length)
                {
                    throw new ArgumentException(string.Concat("buffer size (", buffer.Length, ") must be at least 4 byte larger than desiredDataLength (", desiredDataLength, ")"));
                }
            }
            else
            {
                desiredLength = -1;
            }

            var  n            = 0;
            var  tOut         = DateTime.Now.AddMilliseconds(timeout);
            long nextRead     = 0;
            var  errorChecked = false;

            while (true)
            {
                //if ((desiredLength > 0 || n == 0) && DateTime.Now > tOut)
                if (DateTime.Now > tOut)
                {
                    break;
                }
                if (this.serial.BytesToRead > 0)
                {
                    if (desiredLength > 0)
                    {
                        n += this.serial.Read(buffer, n, desiredLength - n);
                    }
                    else
                    {
                        n += this.serial.Read(buffer, n, buffer.Length - n);
                    }
                    // a delay of more than 1.5 chars means end of telegram /////, but since this is a extreme short time, we extend it by factor 2
                    nextRead = DateTime.Now.Ticks + 6 * this.halfCharLength;
                }
                if (!errorChecked && n >= 2)
                {
                    errorChecked = true;
                    if ((buffer[1] & 0x80) != 0)
                    {
                        // modbus error, so desired length is 5
                        desiredLength = 5;
                    }
                }
                if (desiredLength > 0 && n == desiredLength)
                {
                    telegramLength = (short)n;
                    return(true);
                }
                if (desiredLength <= 0 && n >= 2 && DateTime.Now.Ticks > nextRead && this.serial.BytesToRead == 0)
                {
                    var crc = ModbusUtils.CalcCrc(buffer, n - 2);
                    if (buffer[n - 2] != (byte)(crc & 0x00ff) ||
                        buffer[n - 1] != (byte)((crc & 0xff00) >> 8))
                    {
                        // read a little bit longer
                        Thread.Sleep(1);
                        nextRead = DateTime.Now.Ticks + 6 * this.halfCharLength;
                    }
                    else
                    {
                        telegramLength = (short)n;
                        return(true);
                    }
                }
            }
            telegramLength = 0;
            return(false);
        }
Exemplo n.º 29
0
 /// <summary>
 ///     写指令(MODBUS协议)
 /// </summary>
 /// <param name="address">指令-地址码</param>
 /// <param name="func">指令-功能码</param>
 /// <param name="data">指令-数据</param>
 public void WriteModbus(String address, String func, String data)
 {
     WriteHexString(ModbusUtils.CRC(address, func, data));
 }