コード例 #1
0
        /// <summary>
        /// Helper for packing the discrete data outgoing as a bit-array
        /// </summary>
        /// <param name="command"></param>
        /// <param name="body"></param>
        internal static void PushDiscretes(
            ModbusCommand command,
            ByteArrayWriter body)
        {
            var count = command.Count;

            body.WriteByte((byte)((count + 7) / 8));

            int i    = 0;
            int cell = 0;

            for (int k = 0; k < count; k++)
            {
                if (command.Data[k] != 0)
                {
                    cell |= (1 << i);
                }

                if (++i == 8)
                {
                    body.WriteByte((byte)cell);
                    i    = 0;
                    cell = 0;
                }
            }

            if (i > 0)
            {
                body.WriteByte((byte)cell);
            }
        }
コード例 #2
0
        public override async Task WriteBuffer(ByteArrayWriter Writer, int CurrentOffset)
        {
            Writer.WriteInt32(TypeReference);
            Writer.WriteInt32(ParentReference);
            Writer.WriteInt32(OwnerReference);

            await NameTableIndex.WriteBuffer(Writer, 0);

            Writer.WriteInt32(ArchetypeReference);

            Writer.WriteUInt32(FlagsHigh);
            Writer.WriteUInt32(FlagsLow);

            Writer.WriteInt32(BuilderSerialDataSize);
            Writer.WriteInt32(BuilderSerialDataOffset);

            Writer.WriteUInt32(ExportFlags);

            Writer.WriteInt32(NetObjectCount);

            await Writer.WriteBytes(Guid);

            Writer.WriteUInt32(Unknown1);

            await Writer.WriteBytes(Unknown2);
        }
コード例 #3
0
        //public static readonly ModbusCommandCodec[] CommandCodecs = new ModbusCommandCodec[36];



        /// <summary>
        /// Append the typical header for a request command (master-side)
        /// </summary>
        /// <param name="command"></param>
        /// <param name="body"></param>
        internal static void PushRequestHeader(
            ModbusCommand command,
            ByteArrayWriter body)
        {
            body.WriteUInt16BE((ushort)command.Offset);
            body.WriteInt16BE((short)command.Count);
        }
コード例 #4
0
 public async Task WriteCompressedChunkBlock(ByteArrayWriter Writer)
 {
     await Task.Run(() => {
         Writer.WriteInt32(CompressedSize);
         Writer.WriteInt32(UncompressedSize);
     });
 }
コード例 #5
0
        void IProtocolCodec.ServerEncode(CommDataBase data)
        {
            ModbusServer    ownerProtocol    = (ModbusServer)data.OwnerProtocol;
            ModbusCommand   userData         = (ModbusCommand)data.UserData;
            byte            functionCode     = userData.FunctionCode;
            ByteArrayWriter byteArrayWriter1 = new ByteArrayWriter();

            ModbusCodecBase.CommandCodecs[(int)functionCode]?.ServerEncode(userData, byteArrayWriter1);
            int             num = userData.ExceptionCode == (byte)0 ? 2 + byteArrayWriter1.Length : 3;
            ByteArrayWriter byteArrayWriter2 = new ByteArrayWriter();

            byteArrayWriter2.WriteUInt16BE((ushort)userData.TransId);
            byteArrayWriter2.WriteInt16BE((short)0);
            byteArrayWriter2.WriteInt16BE((short)num);
            byteArrayWriter2.WriteByte(ownerProtocol.Address);
            if (userData.ExceptionCode == (byte)0)
            {
                byteArrayWriter2.WriteByte(userData.FunctionCode);
                byteArrayWriter2.WriteBytes(byteArrayWriter1);
            }
            else
            {
                byteArrayWriter2.WriteByte((byte)((uint)userData.FunctionCode | 128U));
                byteArrayWriter2.WriteByte(userData.ExceptionCode);
            }
            data.OutgoingData = byteArrayWriter2.ToReader();
        }
コード例 #6
0
 public override void ClientEncode(
     ModbusCommand command,
     ByteArrayWriter body)
 {
     body.WriteUInt16BE((ushort)command.Offset);
     body.WriteUInt16BE(command.Data[0]);
 }
コード例 #7
0
        protected bool RaiseStateChangeEvent(Action <ByteArrayWriter> eventWriter)
        {
            if (eventWriter == null)
            {
                return(false);
            }
            var writer = ByteArrayWriter.Get();

            eventWriter(writer);

            if (!Game.Authoritative || writer == null || writer.Size == 0 ||
                writer.Size > Game.Settings.MaxStateChangeSize ||
                (TimeAlive - _lastStateChange) < Game.Settings.MaxStateChangeFrequency ||
                !_eventsEnabled)
            {
                return(false);
            }

            _stateArgs.Object = this;
            _stateArgs.State  = writer.Data;
            Game.EventEngine.RaiseGameObjectStateChanged(_stateArgs);

            writer.Release();

            return(true);
        }
コード例 #8
0
 public override void ClientEncode(
     ModbusCommand command,
     ByteArrayWriter body)
 {
     body.WriteUInt16BE((ushort)command.Offset);
     body.WriteUInt16BE(command.Data[0]);
 }
コード例 #9
0
        public async Task WriteCompressedChunk(ByteArrayWriter Writer, int CurrentOffset)
        {
            Writer.WriteUInt32(BulkDataFlags);

            if (((BulkDataCompressionTypes)BulkDataFlags & NothingToDo) > 0)
            {
                Writer.WriteInt32(0);
                Writer.WriteInt32(-1);

                Writer.WriteInt32(-1);

                return;
            }

            Writer.WriteInt32(UncompressedSize);
            Writer.WriteInt32(CompressedSize);

            Writer.WriteInt32(CurrentOffset + Writer.Index + sizeof(int));

            if (((BulkDataCompressionTypes)BulkDataFlags & BulkDataCompressionTypes.Unused) > 0)
            {
                return;
            }

            if (((BulkDataCompressionTypes)BulkDataFlags & BulkDataCompressionTypes.StoreInSeparatefile) > 0)
            {
                return;
            }

            await Header.WriteCompressedChunkHeader(Writer, CurrentOffset);
        }
コード例 #10
0
        void IProtocolCodec.ServerEncode(CommDataBase data)
        {
            ModbusServer    ownerProtocol    = (ModbusServer)data.OwnerProtocol;
            ModbusCommand   userData         = (ModbusCommand)data.UserData;
            byte            functionCode     = userData.FunctionCode;
            ByteArrayWriter byteArrayWriter1 = new ByteArrayWriter();

            ModbusCodecBase.CommandCodecs[(int)functionCode]?.ServerEncode(userData, byteArrayWriter1);
            if (userData.ExceptionCode == (byte)0)
            {
                int length = byteArrayWriter1.Length;
            }
            ByteArrayWriter byteArrayWriter2 = new ByteArrayWriter();

            byteArrayWriter2.WriteByte(ownerProtocol.Address);
            if (userData.ExceptionCode == (byte)0)
            {
                byteArrayWriter2.WriteByte(userData.FunctionCode);
                byteArrayWriter2.WriteBytes(byteArrayWriter1);
            }
            else
            {
                byteArrayWriter2.WriteByte((byte)((uint)userData.FunctionCode | 128U));
                byteArrayWriter2.WriteByte(userData.ExceptionCode);
            }
            ushort num = ByteArrayHelpers.CalcCRC16(byteArrayWriter2.ToArray(), 0, byteArrayWriter2.Length);

            byteArrayWriter2.WriteInt16LE((short)num);
            data.OutgoingData = byteArrayWriter2.ToReader();
        }
コード例 #11
0
        public override void ClientEncode(ModbusCommand command, ByteArrayWriter body)
        {
            body.WriteUInt16BE((ushort)command.Offset);
            int num = command.Data[0] != (ushort)0 ? 65280 : 0;

            body.WriteInt16BE((short)num);
        }
コード例 #12
0
        protected bool RaiseStateChangeEvent(Action <ByteArrayWriter> eventWriter)
        {
            if (eventWriter == null)
            {
                return(false);
            }

            var writer = ByteArrayWriter.Get();

            eventWriter(writer);

            if (!Game.Authoritative || writer.Size == 0 ||
                writer.Size > Game.Settings.MaxStateChangeSize ||
                (Game.Time - _lastStateChange) < Game.Settings.MaxStateChangeFrequency)
            {
                return(false);
            }

            _args.Gamemode = this;
            _args.State    = writer.Data;
            OnGamemodeStateChanged(this, _args);

            writer.Release();
            return(true);
        }
コード例 #13
0
ファイル: Weapon.cs プロジェクト: pashcovich/mptanks2d
 public void GetFullState(ByteArrayWriter writer)
 {
     if (_isNullWeapon)
     {
         writer.Write(false);
         return;
     }
     else
     {
         writer.Write(true);
         writer.Write((byte)TargetingType);
         writer.Write(MaxDistance);
         writer.Write(GetProjectileString());
         writer.Write(new HalfVector2(ProjectileVelocity));
         writer.Write(new HalfVector2(ProjectileOffset));
         writer.Write((Half)ProjectileRotation);
         writer.Write((Half)ProjectileRotationVelocity);
         writer.Write(MaxActiveProjectileCount);
         writer.Write(FireRotationIsRelativeToTankRotation);
         writer.Write(FireRotationIsRelativeToTankLookDirection);
         writer.Write((Half)AddedRotation);
         writer.Write(TransformPositionAndVelocityByRotation);
         writer.Write(WeaponRechargeTime);
         writer.Write(WeaponName);
         writer.Write(TimeRecharged);
         writer.Write(_projectiles.Select(p => p.ObjectId).Select(BitConverter.GetBytes).SelectMany(a => a).ToArray());
     }
 }
コード例 #14
0
        public async Task SaveUpkFile(DomainHeader Header, string Filename)
        {
            if (Header == null)
            {
                return;
            }

            foreach (DomainExportTableEntry export in Header.ExportTable.Where(export => export.DomainObject == null))
            {
                await export.ParseDomainObject(Header, false, false);
            }

            FileStream stream = new FileStream(Filename, FileMode.Create);

            int headerSize = Header.GetBuilderSize();

            ByteArrayWriter writer = ByteArrayWriter.CreateNew(headerSize);

            await Header.WriteBuffer(writer, 0);

            await stream.WriteAsync(writer.GetBytes(), 0, headerSize);

            foreach (DomainExportTableEntry export in Header.ExportTable)
            {
                ByteArrayWriter objectWriter = await export.WriteObjectBuffer();

                await stream.WriteAsync(objectWriter.GetBytes(), 0, objectWriter.Index);
            }

            await stream.FlushAsync();

            stream.Close();
        }
コード例 #15
0
        public byte[] GetFullState()
        {
            var writer = ByteArrayWriter.Get();

            GetFullState(writer);
            return(writer.ReleaseAndReturnData());
        }
コード例 #16
0
ファイル: ModbusRtuCodec.cs プロジェクト: gbcwbz/ModbusTool
        void IProtocolCodec.ClientEncode(CommDataBase data)
        {
            var client = (ModbusClient)data.OwnerProtocol;
            var command = (ModbusCommand)data.UserData;
            var fncode = command.FunctionCode;

            //encode the command body, if applies
            var body = new ByteArrayWriter();
            var codec = CommandCodecs[fncode];
            if (codec != null)
                codec.ClientEncode(command, body);

            //create a writer for the outgoing data
            var writer = new ByteArrayWriter();

            //unit identifier (address)
            writer.WriteByte(client.Address);

            //function code
            writer.WriteByte(fncode);

            //body data
            writer.WriteBytes(body);

            //CRC-16
            ushort crc = ByteArrayHelpers.CalcCRC16(
                writer.ToArray(),
                0,
                writer.Length);

            writer.WriteInt16LE((short)crc);

            data.OutgoingData = writer.ToReader();
        }
コード例 #17
0
        public void GetPosition_AfterWriteBytes(bool alwaysCopyInputData)
        {
            IByteArrayWriter writer = new ByteArrayWriter(alwaysCopyInputData);

            writer.WriteBytes(100, 100);
            Assert.AreEqual(2, writer.Position);
        }
コード例 #18
0
        public void GetBytes_AfterCreate(bool alwaysCopyInputData)
        {
            IByteArrayWriter writer = new ByteArrayWriter(alwaysCopyInputData);

            byte[] output = writer.GetBytes();
            Assert.AreEqual(0, output.Length);
        }
コード例 #19
0
ファイル: ModbusCodecBase.cs プロジェクト: gbcwbz/ModbusTool
        //public static readonly ModbusCommandCodec[] CommandCodecs = new ModbusCommandCodec[36];



        /// <summary>
        /// Append the typical header for a request command (master-side)
        /// </summary>
        /// <param name="command"></param>
        /// <param name="body"></param>
        internal static void PushRequestHeader(
            ModbusCommand command,
            ByteArrayWriter body)
        {
            body.WriteUInt16BE((ushort)command.Offset);
            body.WriteInt16BE((short)command.Count);
        }
コード例 #20
0
        public override async Task WriteBuffer(ByteArrayWriter Writer, int CurrentOffset)
        {
            await Task.Run(() => {
                Writer.WriteInt32(Index);

                Writer.WriteInt32(Numeric);
            });
        }
コード例 #21
0
 public override void ServerEncode(
     ModbusCommand command,
     ByteArrayWriter body)
 {
     ModbusCodecBase.PushDiscretes(
         command,
         body);
 }
コード例 #22
0
 public override async Task WriteBuffer(ByteArrayWriter Writer, int CurrentOffset)
 {
     Writer.WriteInt32(NameArray.Count);
     foreach (DomainString domainstring in NameArray)
     {
         domainstring.WriteBuffer(Writer, CurrentOffset);
     }
 }
コード例 #23
0
        private byte[] GetWritedArrayPart(ByteArrayWriter writer)
        {
            var bytes = new byte[writer.Count];

            Buffer.BlockCopy(writer.Segment.Array, writer.Offset, bytes, 0, bytes.Length);

            return(bytes);
        }
コード例 #24
0
 public override void ClientEncode(
     ModbusCommand command,
     ByteArrayWriter body)
 {
     ModbusTcpCodec.PushRequestHeader(
         command,
         body);
 }
コード例 #25
0
        public override async Task <ByteArrayWriter> WriteObjectBuffer()
        {
            ByteArrayWriter writer = ByteArrayWriter.CreateNew(SerialDataSize);

            await DomainObject.WriteBuffer(writer, SerialDataOffset);

            return(writer);
        }
コード例 #26
0
 public override void ServerEncode(
     ModbusCommand command,
     ByteArrayWriter body)
 {
     ModbusCodecBase.PushDiscretes(
         command,
         body);
 }
コード例 #27
0
 public override void ServerEncode(
     ModbusCommand command,
     ByteArrayWriter body)
 {
     ModbusCodecBase.PushRequestHeader(
         command,
         body);
 }
コード例 #28
0
 public override void ServerEncode(
     ModbusCommand command,
     ByteArrayWriter body)
 {
     ModbusCodecBase.PushRequestHeader(
         command,
         body);
 }
コード例 #29
0
ファイル: ModbusRtuCodec.cs プロジェクト: josemotta/Netduino
        void IProtocolCodec.ServerEncode(CommDataBase data)
        {
            var server  = (ModbusServer)data.OwnerProtocol;
            var command = (ModbusCommand)data.UserData;
            var fncode  = command.FunctionCode;

            //encode the command body, if applies
            var body  = new ByteArrayWriter();
            var codec = CommandCodecs[fncode];

            if (codec != null)
            {
                codec.ServerEncode(command, body);
            }

            //calculate length field
            var length = (command.ExceptionCode == 0)
                ? 2 + body.Length
                : 3;

            //create a writer for the outgoing data
            var writer = new ByteArrayWriter();

            //unit identifier (address)
            writer.WriteByte(server.Address);

            if (command.ExceptionCode == 0)
            {
                //function code
                writer.WriteByte(fncode);

                //body data
                writer.WriteBytes(body);
            }
            else
            {
                //function code
                writer.WriteByte((byte)(command.FunctionCode | 0x80));

                //exception code
                writer.WriteByte(command.ExceptionCode);
            }

            //CRC-16
            ushort crc;

            unchecked
            {
                crc = (ushort)ModbusRtuCodec.Crc16.Compute(
                    ((IByteArray)writer).Data,
                    0,
                    writer.Length);
            }

            writer.WriteUInt16LE(crc);

            data.OutgoingData = writer.ToReader();
        }
コード例 #30
0
        public override async Task WriteBuffer(ByteArrayWriter Writer, int CurrentOffset)
        {
            Writer.WriteInt32(TypeIndex);

            foreach (DomainProperty property in Properties)
            {
                await property.WriteBuffer(Writer, CurrentOffset);
            }
        }
コード例 #31
0
 protected override void GetTypeStateHeader(ByteArrayWriter writer)
 {
     writer.Write(PrimaryWeapon != null);
     PrimaryWeapon?.GetFullState(writer);
     writer.Write(SecondaryWeapon != null);
     SecondaryWeapon?.GetFullState(writer);
     writer.Write(TertiaryWeapon != null);
     TertiaryWeapon?.GetFullState(writer);
 }
コード例 #32
0
 public override void ServerEncode(
     ModbusCommand command,
     ByteArrayWriter body)
 {
     var count = command.Count;
     body.WriteByte((byte)(count * 2));
     for (int i = 0; i < count; i++)
         body.WriteUInt16BE(command.Data[i]);
 }
コード例 #33
0
        public override async Task WriteBuffer(ByteArrayWriter Writer, int CurrentOffset)
        {
            await PackageNameIndex.WriteBuffer(Writer, 0);

            await TypeNameIndex.WriteBuffer(Writer, 0);

            Writer.WriteInt32(OwnerReference);

            await NameTableIndex.WriteBuffer(Writer, 0);
        }
コード例 #34
0
        public override void ServerEncode(ModbusCommand command, ByteArrayWriter body)
        {
            int count = command.Count;

            body.WriteByte((byte)(count * 2));
            for (int index = 0; index < count; ++index)
            {
                body.WriteUInt16BE(command.Data[index]);
            }
        }
コード例 #35
0
        public override bool ServerEncode(
            ModbusCommand command,
            ByteArrayWriter body)
        {
            ModbusCodecBase.PushRequestHeader(
                command,
                body);

            return(true);
        }
コード例 #36
0
        public void GetBytes_AfterWrite1ByteWithoutOffsetCount()
        {
            IByteArrayWriter writer = new ByteArrayWriter(true);

            writer.WriteBytes(30);

            byte[] output = writer.GetBytes();
            Assert.AreEqual(1, output.Length);
            Assert.AreEqual(30, output[0]);
        }
コード例 #37
0
        public override void ClientEncode(
            ModbusCommand command,
            ByteArrayWriter body)
        {
            body.WriteUInt16BE((ushort)command.Offset);

            var value = command.Data[0] != 0
                ? 0xFF00
                : 0;

            body.WriteInt16BE((short)value);
        }
コード例 #38
0
        public override void ClientEncode(
            ModbusCommand command,
            ByteArrayWriter body)
        {
            ModbusCodecBase.PushRequestHeader(
                command,
                body);

            ModbusCodecBase.PushDiscretes(
                command,
                body);
        }
コード例 #39
0
        public override void ClientEncode(
            ModbusCommand command,
            ByteArrayWriter body)
        {
            ModbusCodecBase.PushRequestHeader(
                command,
                body);

            var count = command.Count;
            body.WriteByte((byte)(count * 2));
            for (int i = 0; i < count; i++)
                body.WriteUInt16BE(command.Data[i]);
        }
コード例 #40
0
        public override void ServerEncode(
            ModbusCommand command,
            ByteArrayWriter body)
        {
            body.WriteByte(_device);
            var count = command.Count;
            body.WriteByte((byte)(count));
            body.WriteByte(0xFF);
            body.WriteByte(0xFF);
            body.WriteInt32BE(_address);

            if (_category == 0)
            {
                for (int i = 0; i < count/2; i++)
                {
                    UInt16 v = (UInt16) GetRandomNumber(0, 25);
                    byte h = (byte)(v >> 8);
                    byte l = (byte)(v &0x00FF);
                    UInt16 t = (UInt16)((l << 8) + h);
                    body.WriteUInt16BE(t);
                }
            }
            else if (_category == 2)
            {
                for (int i = 0; i < count / 2; i++)
                {
                    body.WriteUInt16BE((UInt16)GetRandomNumber(0, 5));
                }

            }
            else 
            {
                for (int i = 0; i < count / 2; i++)
                {
                    body.WriteUInt16BE((UInt16)GetRandomNumber(0, 50));
                }

            }

        }
コード例 #41
0
ファイル: ModbusTcpCodec.cs プロジェクト: gbcwbz/ModbusTool
        void IProtocolCodec.ClientEncode(CommDataBase data)
        {
            var client = (ModbusClient)data.OwnerProtocol;
            var command = (ModbusCommand)data.UserData;
            var fncode = command.FunctionCode;

            //encode the command body, if applies
            var body = new ByteArrayWriter();
            var codec = CommandCodecs[fncode];
            if (codec != null)
                codec.ClientEncode(command, body);

            //calculate length field
            var length = 2 + body.Length;

            //create a writer for the outgoing data
            var writer = new ByteArrayWriter();

            //transaction-id 
            writer.WriteUInt16BE((ushort)command.TransId);

            //protocol-identifier (always zero)
            writer.WriteInt16BE(0);

            //message length
            writer.WriteInt16BE((short)length);

            //unit identifier (address)
            writer.WriteByte(client.Address);

            //function code
            writer.WriteByte(fncode);

            //body data
            writer.WriteBytes(body);

            data.OutgoingData = writer.ToReader();
        }
コード例 #42
0
ファイル: ModbusRtuCodec.cs プロジェクト: gbcwbz/ModbusTool
        void IProtocolCodec.ServerEncode(CommDataBase data)
        {
            var server = (ModbusServer)data.OwnerProtocol;
            var command = (ModbusCommand)data.UserData;
            var fncode = command.FunctionCode;

            //encode the command body, if applies
            var body = new ByteArrayWriter();
            var codec = CommandCodecs[fncode];
            if (codec != null)
                codec.ServerEncode(command, body);

            //calculate length field
            var length = (command.ExceptionCode == 0)
                ? 2 + body.Length
                : 3;

            //create a writer for the outgoing data
            var writer = new ByteArrayWriter();

            //unit identifier (address)
            writer.WriteByte(server.Address);

            if (command.ExceptionCode == 0)
            {
                //function code
                writer.WriteByte(command.FunctionCode);

                //body data
                writer.WriteBytes(body);
            }
            else
            {
                //function code
                writer.WriteByte((byte)(command.FunctionCode | 0x80));

                //exception code
                writer.WriteByte(command.ExceptionCode);
            }

            //CRC-16
            ushort crc = ByteArrayHelpers.CalcCRC16(
                writer.ToArray(),
                0,
                writer.Length);

            writer.WriteInt16LE((short)crc);

            data.OutgoingData = writer.ToReader();
        }
コード例 #43
0
 /// <summary>
 /// Encode the client-side command toward the remote slave device
 /// </summary>
 /// <param name="command"></param>
 /// <param name="body"></param>
 public virtual void ClientEncode(
     ModbusCommand command,
     ByteArrayWriter body)
 {
 }
コード例 #44
0
 /// <summary>
 /// Encode the server-side command toward the master remote device
 /// </summary>
 /// <param name="command"></param>
 /// <param name="body"></param>
 public virtual void ServerEncode(
 ModbusCommand command,
 ByteArrayWriter body)
 {
 }
コード例 #45
0
ファイル: ModbusTcpCodec.cs プロジェクト: gbcwbz/ModbusTool
        void IProtocolCodec.ServerEncode(CommDataBase data)
        {
            var server = (ModbusServer)data.OwnerProtocol;
            var command = (ModbusCommand)data.UserData;
            var fncode = command.FunctionCode;

            //encode the command body, if applies
            var body = new ByteArrayWriter();
            var codec = CommandCodecs[fncode];
            if (codec != null)
                codec.ServerEncode(command, body);

            //calculate length field
            var length = (command.ExceptionCode == 0)
                ? 2 + body.Length
                : 3;

            //create a writer for the outgoing data
            var writer = new ByteArrayWriter();

            //transaction-id
            writer.WriteUInt16BE((ushort)command.TransId);

            //protocol-identifier
            writer.WriteInt16BE(0);

            //message length
            writer.WriteInt16BE((short)length);

            //unit identifier (address)
            writer.WriteByte(server.Address);

            if (command.ExceptionCode == 0)
            {
                //function code
                writer.WriteByte(command.FunctionCode);

                //body data
                writer.WriteBytes(body);
            }
            else
            {
                //function code
                writer.WriteByte((byte)(command.FunctionCode | 0x80));

                //exception code
                writer.WriteByte(command.ExceptionCode);
            }

            data.OutgoingData = writer.ToReader();
        }
コード例 #46
0
ファイル: ModbusCodecBase.cs プロジェクト: gbcwbz/ModbusTool
 /// <summary>
 /// Helper for packing the discrete data outgoing as a bit-array
 /// </summary>
 /// <param name="command"></param>
 /// <param name="body"></param>
 internal static void PushDiscretes(
     ModbusCommand command,
     ByteArrayWriter body)
 {
     var count = ((byte)((command.Count + 7) / 8));
     var wholeWords = command.Count / 16;
     var remainingBits = command.Count % 16;
     body.WriteByte(count);
     int k;
     for (k = 0; k < wholeWords; k++)
     {
         var hb = (byte)(command.Data[k] >> 8);
         var lb = (byte)(command.Data[k] & 0x00FF);
         body.WriteByte(hb);
         body.WriteByte(lb);
     }
     if (remainingBits > 0)
     {
         byte bitMask = 1;
         byte cell = 0;
         byte currentByte = (byte)(command.Data[k] >> 8);
         for (int j = 0; j < remainingBits; j++)
         {
             if (j == 8)
             {
                 body.WriteByte(cell);
                 currentByte = (byte)(command.Data[k] & 0x00FF);
                 bitMask = 1;
                 cell = 0;
             }
             cell |= (byte)(currentByte & bitMask);
             bitMask = (byte)(bitMask << 1);
         }
         body.WriteByte(cell);
     }
 }