using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace FLY.Modbus
{
    public static class COMMON 
    {
        /// <summary>
        /// 把2个byte 转为 uint16
        /// </summary>
        /// <param name="value"></param>
        /// <param name="startIndex"></param>
        /// <returns></returns>
        public static UInt16 ToUInt16_Big_endian(byte[] value, int startIndex) 
        {
            return (UInt16)((value[startIndex] << 8) | value[startIndex+1]);
        }
        /// <summary>
        /// 把 uint16 转为2个byte
        /// </summary>
        /// <param name="value"></param>
        /// <returns></returns>
        public static byte[] GetBytes_Big_endian(this UInt16 value)
        {
            byte[] b = new byte[2];
            b[0] = (byte)(value >> 8);
            b[1] = (byte)value;
            return b;
        }
    }
    /// <summary>
    /// 
    /// </summary>
    public class Pack_Proto
    {
        public UInt16 tranid;
        public byte unitid;
        public byte func;
        public byte[] buf = null;

        //格式——————————————                
        //MBAP
        //域                         长度          描述
        //事务标识符         2byte           MODBUS请求/响应的识别码    
        //协议标识符         2byte           0=MODBUS协议
        //——长度—         2byte           以下字节的数量
        //单元标识符         1byte           串行链路或其它总线过来的识别码


        //PDU
        //功能码——         1byte
        //数据                    nbyte

        public byte[] ToBytes()
        {
            List<byte> buf = new List<byte>();
            buf.AddRange(tranid.GetBytes_Big_endian());
            buf.AddRange(((UInt16)0).GetBytes_Big_endian());
            UInt16 len = (UInt16)(1 + 1 + this.buf.Count());
            buf.AddRange(len.GetBytes_Big_endian());
            buf.Add(unitid);
            buf.Add(func);
            if (this.buf != null)
                buf.AddRange(this.buf);

            return buf.ToArray();
        }

        public bool TryParse(byte[] value, int startIndex, int value_len, out int rlen)
        {
            //格式——————————————                
            //MBAP
            //域                         长度          描述
            //事务标识符         2byte           MODBUS请求/响应的识别码    
            //协议标识符         2byte           0=MODBUS协议
            //——长度—         2byte           以下字节的数量
            //单元标识符         1byte           串行链路或其它总线过来的识别码


            //PDU
            //功能码——         1byte
            //数据                    nbyte

            rlen = 0;
            int cnt = 7 + 1;
            if (value_len < cnt)
                return false;
            int index = startIndex;
            tranid = COMMON.ToUInt16_Big_endian(value, index);
            index += 2;
            UInt16 protoid = COMMON.ToUInt16_Big_endian(value, index);
            index += 2;
            
            int len = COMMON.ToUInt16_Big_endian(value, index);
            index += 2;
            
            cnt += len - 2;
            if (value_len < cnt)
                return false;

            unitid = value[index];
            index++;

            func = value[index];
            index++;

            len -= 2;
            if (len > 0)
            {
                buf = new byte[len];
                Array.Copy(value, index, buf, 0, len);
            }
            rlen = cnt;

            return true;
        }
    }
}
