/// <summary>
        /// This method fills in the first 2 to 4 bytes of a <c>SECSItem</c>'s
        /// value (the <c>SECSItem</c>'s header) in its raw wire/transmission format.
        /// The first byte contains value of the item's format code and number of length
        /// bytes and the next 1 to 3 bytes contain the value of the item's length in bytes.
        /// <para>
        /// Make sure <c>buffer</c> is large enough!!!
        /// </para>
        /// </summary>
        /// <returns>The offset to where the payload data may loaded into the buffer.</returns>
        /// <param name="buffer">The buffer that will be used to contain an outgoing message item.</param>
        /// <param name="numberOfBytes">The number of bytes in the payload...get this right.</param>
        protected int PopulateSECSItemHeaderData(byte[] buffer, int numberOfBytes)
        {
            int offset = 0;

            buffer[0] = (byte)((SECSItemFormatCodeFunctions.GetNumberFromSECSItemFormatCode(formatCode) << 2) | outboundNumberOfLengthBytes.ValueOf());

            byte[] outputLengthBytes = BitConverter.GetBytes(numberOfBytes);

            if (BitConverter.IsLittleEndian)
            {
                Array.Reverse(outputLengthBytes);
            }

            if (outboundNumberOfLengthBytes == SECSItemNumLengthBytes.ONE)
            {
                buffer [1] = outputLengthBytes [3];
                offset     = 2;
            }
            else if (outboundNumberOfLengthBytes == SECSItemNumLengthBytes.TWO)
            {
                buffer [1] = outputLengthBytes [2];
                buffer [2] = outputLengthBytes [3];
                offset     = 3;
            }
            else if (outboundNumberOfLengthBytes == SECSItemNumLengthBytes.THREE)
            {
                buffer [1] = outputLengthBytes [1];
                buffer [2] = outputLengthBytes [2];
                buffer [3] = outputLengthBytes [3];
                offset     = 4;
            }
            else
            {
                Console.WriteLine("The case where outboundNumberOfLengthBytes is still in its NOT_INITIALIZED state should never happen.");
            }

            return(offset);
        }
        /// <summary>
        /// Generates a <c>SECSItem</c> from data in &quot;wire/transmission&quot; format.
        /// </summary>
        /// <returns>The resulting <c>SECSItem</c>.</returns>
        /// <param name="data">An array of bytes that is in wire/transmission format.</param>
        /// <param name="offset">The byte offset into <c>data</c> where the data for
        /// a <c>SECSITEM</c> starts.</param>
        public static SECSItem GenerateSECSItem(byte[] data, int offset)
        {
            SECSItem result = null;

            SECSItemFormatCode formatCode = SECSItemFormatCodeFunctions.GetSECSItemFormatCodeFromNumber((byte)((data[offset] >> 2) & 0x0000003F));
            int numberOfLengthBytes       = (data[offset] & 0x03);
            int incomingDataLength        = 0;

            switch (numberOfLengthBytes)
            {
            case 1:
            {
                byte[] temp = new byte[4];
                temp[0] = 0;
                temp[1] = 0;
                temp[2] = 0;
                temp[3] = data[offset + 1];

                if (BitConverter.IsLittleEndian)
                {
                    Array.Reverse(temp);
                }

                incomingDataLength = BitConverter.ToInt32(temp, 0);
                break;
            }

            case 2:
            {
                byte[] temp = new byte[4];
                temp[0] = 0;
                temp[1] = 0;
                temp[2] = data[offset + 1];
                temp[3] = data[offset + 2];
                if (BitConverter.IsLittleEndian)
                {
                    Array.Reverse(temp);
                }

                incomingDataLength = BitConverter.ToInt32(temp, 0);
                break;
            }

            case 3:
            {
                byte[] temp = new byte[4];
                temp[0] = 0;
                temp[1] = data[offset + 1];
                temp[2] = data[offset + 2];
                temp[3] = data[offset + 3];
                if (BitConverter.IsLittleEndian)
                {
                    Array.Reverse(temp);
                }

                incomingDataLength = BitConverter.ToInt32(temp, 0);
                break;
            }
            }


            switch (formatCode)
            {
            case SECSItemFormatCode.L:
                result = new ListSECSItem(data, offset);
                break;

            case SECSItemFormatCode.B:
                result = new BinarySECSItem(data, offset);
                break;

            case SECSItemFormatCode.BO:
                if (incomingDataLength == 1)
                {
                    result = new BooleanSECSItem(data, offset);
                }
                else
                {
                    result = new BooleanArraySECSItem(data, offset);
                }
                break;

            case SECSItemFormatCode.A:
                result = new ASCIISECSItem(data, offset);
                break;

            case SECSItemFormatCode.J8:
                break;

            case SECSItemFormatCode.C2:
                break;

            case SECSItemFormatCode.I8:
                if (incomingDataLength == 8)
                {
                    result = new I8SECSItem(data, offset);
                }
                else
                {
                    result = new I8ArraySECSItem(data, offset);
                }
                break;

            case SECSItemFormatCode.I1:
                if (incomingDataLength == 1)
                {
                    result = new I1SECSItem(data, offset);
                }
                else
                {
                    result = new I1ArraySECSItem(data, offset, 0);                             // Need to use this version because of method signature issues
                }
                break;

            case SECSItemFormatCode.I2:
                if (incomingDataLength == 2)
                {
                    result = new I2SECSItem(data, offset);
                }
                else
                {
                    result = new I2ArraySECSItem(data, offset);
                }
                break;

            case SECSItemFormatCode.I4:
                if (incomingDataLength == 4)
                {
                    result = new I4SECSItem(data, offset);
                }
                else
                {
                    result = new I4ArraySECSItem(data, offset);
                }
                break;

            case SECSItemFormatCode.F8:
                if (incomingDataLength == 8)
                {
                    result = new F8SECSItem(data, offset);
                }
                else
                {
                    result = new F8ArraySECSItem(data, offset);
                }
                break;

            case SECSItemFormatCode.F4:
                if (incomingDataLength == 4)
                {
                    result = new F4SECSItem(data, offset);
                }
                else
                {
                    result = new F4ArraySECSItem(data, offset);
                }
                break;

            case SECSItemFormatCode.U8:
                if (incomingDataLength == 8)
                {
                    result = new U8SECSItem(data, offset);
                }
                else
                {
                    result = new U8ArraySECSItem(data, offset);
                }
                break;

            case SECSItemFormatCode.U1:
                if (incomingDataLength == 1)
                {
                    result = new U1SECSItem(data, offset);
                }
                else
                {
                    result = new U1ArraySECSItem(data, offset, 0);                              // Remember to use the proper constructor for this case
                }
                break;

            case SECSItemFormatCode.U2:
                if (incomingDataLength == 2)
                {
                    result = new U2SECSItem(data, offset);
                }
                else
                {
                    result = new U2ArraySECSItem(data, offset);
                }
                break;

            case SECSItemFormatCode.U4:
                if (incomingDataLength == 4)
                {
                    result = new U4SECSItem(data, offset);
                }
                else
                {
                    result = new U4ArraySECSItem(data, offset);
                }
                break;

            case SECSItemFormatCode.UNDEFINED:
                break;

            case SECSItemFormatCode.HeaderOnly:
                break;

            default:
                break;
            }

            return(result);
        }
Beispiel #3
0
        protected SECSItem(byte[] data, int itemOffset)
        {
            int incomingDataLength = 0;

            if (data.Length == 0)
            {
                formatCode = SECSItemFormatCode.HeaderOnly;
                inboundNumberOfLengthBytes = 0;
                data = null;
                return;
            }

            formatCode = SECSItemFormatCodeFunctions.getSECSItemFormatCodeFromNumber((byte)((data[itemOffset] >> 2) & 0x0000003F));
            inboundNumberOfLengthBytes = (data[itemOffset] & 0x03);

            byte[] temp1 = new byte[4];
            switch (inboundNumberOfLengthBytes)
            {
            case 1:
            {
                temp1[0] = 0;
                temp1[1] = 0;
                temp1[2] = 0;
                temp1[3] = data[itemOffset + 1];

                break;
            }

            case 2:
            {
                temp1[0] = 0;
                temp1[1] = 0;
                temp1[2] = data[itemOffset + 1];
                temp1[3] = data[itemOffset + 2];
                break;
            }

            case 3:
            {
                temp1[0] = 0;
                temp1[1] = data[itemOffset + 1];
                temp1[2] = data[itemOffset + 2];
                temp1[3] = data[itemOffset + 3];
                break;
            }
            }

            if (BitConverter.IsLittleEndian)
            {
                Array.Reverse(temp1);
            }

            incomingDataLength = BitConverter.ToInt32(temp1, 0);

            if (formatCode == SECSItemFormatCode.L)
            {
                numberOfElements = incomingDataLength;
            }
            else
            {
                lengthInBytes = incomingDataLength;
            }
        }
        /// <summary>
        ///  This is a base class constructor for a SECSItem.  This form of the constructor
        /// is used when parsing wire/transmission format data and converting it into
        /// its "C# form".
        ///
        /// This constructor sets the following base class attributes from the provided data:
        /// <c>formatCode</c>,
        /// <c>inboundNumberOfLengthBytes</c>,
        /// <c>outboundNumberOfLengthBytes</c>
        /// <c>lengthInBytes</c> or if the <c>formatCode</c> is of type <c>L</c>(List) <c>lengthInBytes</c>
        /// will be the number of items in the list.
        ///
        /// The exception <c>ArgumentException</c> will be thrown in the following circumstances:
        /// the <c>data</c> argument is <c>null</c>, the <c>data</c> argument has a length of zero, or
        /// the number of length bytes parsed out is zero.
        ///
        /// In normal use the only time the <c>ArgumentException</c>
        /// exception should be caught is if you are reading data from a piece of
        /// equipment that does not properly speak SECS and you want to be able to
        /// recover from the error gracefully.Typically the ACM process will have
        /// detected this equipment and it will not be allowed into the factory in
        /// the first place.
        /// </summary>
        protected SECSItem(byte[] data, int itemOffset)
        {
            if (data == null)
            {
                throw new ArgumentNullException("\"data\" argument must not be null.");
            }

            if (data.Length < 2)
            {
                throw new ArgumentException("\"data\" argument must have a length >= 2.");
            }

            /*
             * if (data.Length == 0)
             * {
             *  throw new ArgumentException ("The number of length bytes is not allowed to be ZERO.");
             * }
             */

            formatCode = SECSItemFormatCodeFunctions.GetSECSItemFormatCodeFromNumber((byte)((data[itemOffset] >> 2) & 0x0000003F));

            byte[] temp1 = new byte[4];
            switch (data [itemOffset] & 0x03)
            {
            case 0:
            {
                throw new ArgumentException("The number of length bytes is not allowed to be ZERO.");
            }

            case 1:
            {
                inboundNumberOfLengthBytes  = SECSItemNumLengthBytes.ONE;
                outboundNumberOfLengthBytes = inboundNumberOfLengthBytes;
                temp1[0] = 0;
                temp1[1] = 0;
                temp1[2] = 0;
                temp1[3] = data[itemOffset + 1];

                break;
            }

            case 2:
            {
                inboundNumberOfLengthBytes  = SECSItemNumLengthBytes.TWO;
                outboundNumberOfLengthBytes = inboundNumberOfLengthBytes;
                if (data.Length < 3)
                {
                    throw new ArgumentException("With two length bytes the minimum length for the \"data\" argument is 3.");
                }

                temp1[0] = 0;
                temp1[1] = 0;
                temp1[2] = data[itemOffset + 1];
                temp1[3] = data[itemOffset + 2];
                break;
            }

            case 3:
            {
                inboundNumberOfLengthBytes  = SECSItemNumLengthBytes.THREE;
                outboundNumberOfLengthBytes = inboundNumberOfLengthBytes;
                if (data.Length < 4)
                {
                    throw new ArgumentException("With three length bytes the minimum length for the \"data\" argument is 4.");
                }

                temp1[0] = 0;
                temp1[1] = data[itemOffset + 1];
                temp1[2] = data[itemOffset + 2];
                temp1[3] = data[itemOffset + 3];
                break;
            }
            }

            if (BitConverter.IsLittleEndian)
            {
                Array.Reverse(temp1);
            }

            lengthInBytes = BitConverter.ToInt32(temp1, 0);

            /*
             * if (formatCode == SECSItemFormatCode.L)
             *  numberOfElements = incomingDataLength;
             * else
             *  lengthInBytes = incomingDataLength;
             */
        }