/// <summary> /// Reserved for internal use. /// </summary> internal static object GetData(byte[] buff, ref int pos, ActionType action, out int count, out int index, ref DataType type, ref int cachePosition) { count = 0; index = 0; object value = null; if (pos == buff.Length) { pos = -1; return(null); } bool knownType = type != DataType.None; if (!knownType) { type = (DataType)buff[pos++]; } if (type == DataType.None) { return(value); } if (pos == buff.Length) { pos = -1; return(null); } int size = buff.Length - pos; if (type == DataType.Array || type == DataType.Structure) { count = GXCommon.GetObjectCount(buff, ref pos); if (action == ActionType.Count) { return(value); //Don't go further. Only object's count is resolved. } if (cachePosition > pos) { pos = cachePosition; } size = buff.Length - pos; if (count != 0 && size < 1) { pos = -1; return(null); } List <object> arr = new List <object>(count); for (index = 0; index != count; ++index) { DataType itemType = DataType.None; int colCount, colIndex; int tmpPos = 0; object tmp = GetData(buff, ref pos, ActionType.None, out colCount, out colIndex, ref itemType, ref tmpPos); if (colCount == colIndex && pos != -1) { arr.Add(tmp); } if (pos == -1) { break; } else { cachePosition = pos; } } if (index == count && pos != -1) { cachePosition = buff.Length; } value = arr.ToArray(); } else if (type == DataType.Boolean) { value = buff[pos++] != 0; } else if (type == DataType.BitString) { int oldPos = pos; int cnt = GetObjectCount(buff, ref pos); size -= pos - oldPos; double t = cnt; t /= 8; if (cnt % 8 != 0) { ++t; } int byteCnt = (int)Math.Floor(t); if (size < byteCnt) //If there is not enough data available. { pos = -1; return(null); } string str = ""; while (cnt > 0) { str += ToBitString(buff[pos++], cnt); cnt -= 8; } value = str; } else if (type == DataType.Int32) { if (size < 4) //If there is not enough data available. { pos = -1; return(null); } value = GXCommon.GetInt32(buff, ref pos); } else if (type == DataType.UInt32) { if (size < 4) //If there is not enough data available. { pos = -1; return(null); } value = GXCommon.GetUInt32(buff, ref pos); } else if (type == DataType.StringUTF8) { int len = 0; if (knownType) { len = buff.Length; } else { len = GXCommon.GetObjectCount(buff, ref pos); if (buff.Length - pos < len) //If there is not enough data available. { pos = -1; return(null); } } if (len > 0) { value = ASCIIEncoding.UTF8.GetString(GXCommon.RawData(buff, ref pos, len)); } else { value = ""; } } else if (type == DataType.String) { int len = 0; if (knownType) { len = buff.Length; } else { len = GXCommon.GetObjectCount(buff, ref pos); if (buff.Length - pos < len) //If there is not enough data available. { pos = -1; return(null); } } if (len > 0) { bool octetString = false; if (knownType) { //Check that this is not octet string. foreach (byte it in buff) { if (it != 0 && it < 0x20) { octetString = true; break; } } } if (octetString) { StringBuilder sb = new StringBuilder(3 * buff.Length); foreach (byte it in buff) { sb.Append(it); sb.Append('.'); } sb.Remove(sb.Length - 1, 1); value = sb.ToString(); } else { //Remove '\0' from string if used. while (len > 0 && buff[len - 1] == 0) { --len; } value = ASCIIEncoding.ASCII.GetString(GXCommon.RawData(buff, ref pos, len)); } } } //Example Logical name is octet string, so do not change to string... else if (type == DataType.OctetString) { int len = 0; if (knownType) { len = buff.Length; } else { len = GXCommon.GetObjectCount(buff, ref pos); if (buff.Length - pos < len) //If there is not enough data available. { pos = -1; return(null); } } value = GXCommon.RawData(buff, ref pos, len); } else if (type == DataType.BinaryCodedDesimal) { int len; if (knownType) { len = buff.Length; } else { len = GXCommon.GetObjectCount(buff, ref pos); } StringBuilder bcd = new StringBuilder(len * 2); for (int a = 0; a != len; ++a) { int idHigh = buff[pos] >> 4; int idLow = buff[pos] & 0x0F; ++pos; bcd.Append(string.Format("{0}{1}", idHigh, idLow)); } return(bcd.ToString()); } else if (type == DataType.Int8) { value = (sbyte)buff[pos++]; } else if (type == DataType.Int16) { if (size < 2) //If there is not enough data available. { pos = -1; return(null); } value = GXCommon.GetInt16(buff, ref pos); } else if (type == DataType.UInt8) { value = buff[pos++]; } else if (type == DataType.UInt16) { if (size < 2) //If there is not enough data available. { pos = -1; return(null); } value = GXCommon.GetUInt16(buff, ref pos); } else if (type == DataType.CompactArray) { throw new Exception("Invalid data type."); } else if (type == DataType.Int64) { if (size < 8) //If there is not enough data available. { pos = -1; return(null); } value = GXCommon.GetInt64(buff, ref pos); } else if (type == DataType.UInt64) { if (size < 8) //If there is not enough data available. { pos = -1; return(null); } value = GXCommon.GetUInt64(buff, ref pos); } else if (type == DataType.Enum) { if (size < 1) //If there is not enough data available. { pos = -1; return(null); } value = buff[pos++]; } else if (type == DataType.Float32) { if (size < 4) //If there is not enough data available. { pos = -1; return(null); } value = GXCommon.ToFloat(buff, ref pos); } else if (type == DataType.Float64) { if (size < 8) //If there is not enough data available. { pos = -1; return(null); } value = GXCommon.ToDouble(buff, ref pos); } else if (type == DataType.DateTime) { if (size < 12) //If there is not enough data available. { pos = -1; return(null); } GXDateTime dt = new GXDateTime(); //Get year. int year = GXCommon.GetUInt16(buff, ref pos); if (year == 0xFFFF || year == 0) { year = DateTime.MinValue.Year; dt.Skip |= DateTimeSkips.Year; } //Get month int month = buff[pos++]; if (month == 0 || month == 0xFF || month == 0xFE || month == 0xFD) { month = 1; dt.Skip |= DateTimeSkips.Month; } int day = buff[pos++]; if (day < 1 || day == 0xFF) { day = 1; dt.Skip |= DateTimeSkips.Day; } else if (day == 0xFD || day == 0xFE) { day = DateTime.DaysInMonth(year, month) + (sbyte)day + 2; } //Skip week day ++pos; //Get time. int hours = buff[pos++]; if (hours == 0xFF) { hours = 0; dt.Skip |= DateTimeSkips.Hour; } int minutes = buff[pos++]; if (minutes == 0xFF) { minutes = 0; dt.Skip |= DateTimeSkips.Minute; } int seconds = buff[pos++]; if (seconds == 0xFF) { seconds = 0; dt.Skip |= DateTimeSkips.Second; } int milliseconds = buff[pos++]; if (milliseconds != 0xFF && milliseconds != 0) { milliseconds *= 10; } else { milliseconds = 0; dt.Skip |= DateTimeSkips.Ms; } int deviation = GXCommon.GetInt16(buff, ref pos); dt.Status = (ClockStatus)buff[pos++]; if ((deviation & 0xFFFF) != 0x8000 && year != 1) { dt.Value = DateTime.SpecifyKind(new DateTime(year, month, day, hours, minutes, seconds, milliseconds), DateTimeKind.Utc); dt.Value = dt.Value.AddMinutes(deviation); dt.Value = dt.Value.ToLocalTime(); } else //Use current time if deviation is not defined. { dt.Value = new DateTime(year, month, day, hours, minutes, seconds, milliseconds); } value = dt; } else if (type == DataType.Date) { if (size < 5) //If there is not enough data available. { pos = 0xFF; return(null); } //Get year. int year = GXCommon.GetUInt16(buff, ref pos); //IskraEmeco meter returns bytes in wrong order. if (year != 0xFFFF && year > 2100) { pos -= 2; year = buff[pos++] | buff[pos++] << 8; //If Actaris SL 7000 and ACE 6000 returns invalid date. if (year == 0x5C13) { year = -1; } } //Get month int month = buff[pos++]; int day = buff[pos++]; //Skip week day int DayOfWeek = buff[pos++]; //If day of week are not used. GXDateTime dt = new GXDateTime(year, month, day, -1, -1, 1, -1); return(dt); } else if (type == DataType.Time) { if (size < 4) //If there is not enough data available. { pos = -1; return(null); } //Get time. int hours = buff[pos++]; int minutes = buff[pos++]; int seconds = buff[pos++]; int milliseconds = buff[pos++]; GXDateTime dt = new GXDateTime(-1, -1, -1, hours, minutes, seconds, milliseconds); value = dt; } else { throw new Exception("Invalid data type."); } return(value); }
/// <summary> /// Reserved for internal use. /// </summary> /// <param name="buff"></param> /// <param name="type"></param> /// <param name="value"></param> public static void SetData(List <byte> buff, DataType type, object value) { bool reverse = true; List <byte> tmp = new List <byte>(); //If byte array is added do not add type. if ((type == DataType.Array || type == DataType.Structure) && value is byte[]) { buff.AddRange((byte[])value); return; } if (type == DataType.None) { value = null; } else if (type == DataType.Boolean) { value = (byte)(Convert.ToBoolean(value) ? 1 : 0); } else if (type == DataType.BitString) { byte val = 0; int index = 0; if (value is string) { string str = value as string; SetObjectCount(str.Length, tmp); foreach (char it in str) { if (it == '1') { val |= (byte)(1 << index++); } else if (it == '0') { index++; } else { throw new ArgumentException("Not a bit string."); } if (index == 8) { index = 0; tmp.Add(val); val = 0; } } if (index != 0) { tmp.Add(val); } value = tmp.ToArray(); reverse = false; } else if (value is byte[]) { byte[] arr = value as byte[]; SetObjectCount(arr.Length, tmp); tmp.AddRange(arr); value = tmp.ToArray(); reverse = false; } else if (value is bool[]) { bool[] arr = value as bool[]; SetObjectCount(arr.Length, tmp); foreach (bool it in arr) { if (it) { val |= (byte)(1 << index++); } else { ++index; } if (index == 8) { index = 0; tmp.Add(val); val = 0; } } if (index != 0) { tmp.Add(val); } value = tmp.ToArray(); reverse = false; } else if (value == null) { tmp.Add(0); value = tmp.ToArray(); reverse = false; } else { throw new Exception("BitString must give as string."); } } else if (type == DataType.Int32) { value = Convert.ToInt32(value); } else if (type == DataType.UInt32) { value = Convert.ToUInt32(value); } else if (type == DataType.String) { if (value != null) { string str = value.ToString(); SetObjectCount(str.Length, tmp); tmp.AddRange(ASCIIEncoding.ASCII.GetBytes(str)); } else { SetObjectCount(0, tmp); } value = tmp.ToArray(); reverse = false; } else if (type == DataType.StringUTF8) { if (value != null) { string str = value.ToString(); byte[] tmp1 = ASCIIEncoding.UTF8.GetBytes(str); SetObjectCount(tmp1.Length, tmp); tmp.AddRange(tmp1); } else { SetObjectCount(0, tmp); } value = tmp.ToArray(); reverse = false; } else if (type == DataType.Array || type == DataType.Structure) { if (value != null) { Array arr = (Array)value; SetObjectCount(arr.Length, tmp); foreach (object it in arr) { SetData(tmp, GetValueType(it), it); } } else { SetObjectCount(0, tmp); } value = tmp.ToArray(); reverse = false; } else if (type == DataType.OctetString) { reverse = false; if (value is string) { if ((value as string) == "") { SetObjectCount(0, tmp); value = tmp.ToArray(); } else { string[] items = (value as string).Split('.'); tmp.Clear(); SetObjectCount(items.Length, tmp); foreach (string it in items) { tmp.Add(byte.Parse(it)); } value = tmp.ToArray(); } } else if (value == null) { SetObjectCount(0, tmp); value = tmp.ToArray(); } else if (value is byte[]) { SetObjectCount((value as byte[]).Length, tmp); tmp.AddRange(value as byte[]); value = tmp.ToArray(); } else if (value is GXDateTime) { value = GetDateTime(value as GXDateTime); } else if (value is DateTime) { value = GetDateTime(new GXDateTime(Convert.ToDateTime(value))); } else { value = Convert.ToString(value); } } else if (type == DataType.BinaryCodedDesimal) { if (!(value is string)) { throw new Exception("BCD value must give as string."); } string str = value.ToString().Trim(); int len = str.Length; if (len % 2 != 0) { str = "0" + str; ++len; } len /= 2; List <byte> val = new List <byte>(len); val.Add((byte)(len)); for (int pos = 0; pos != len; ++pos) { byte ch1 = byte.Parse(str.Substring(2 * pos, 1)); byte ch2 = byte.Parse(str.Substring(2 * pos + 1, 1)); val.Add((byte)(ch1 << 4 | ch2)); } reverse = false; value = val.ToArray(); } else if (type == DataType.Int8) { value = Convert.ToSByte(value); } else if (type == DataType.Int16) { value = (short)Convert.ToInt32(value); } else if (type == DataType.UInt8) { value = Convert.ToByte(value); } else if (type == DataType.UInt16) { value = Convert.ToUInt16(value); } else if (type == DataType.CompactArray) { throw new Exception("Invalid data type."); } else if (type == DataType.Int64) { value = Convert.ToInt64(value); } else if (type == DataType.UInt64) { value = Convert.ToUInt64(value); } else if (type == DataType.Enum) { value = Convert.ToByte(value); } else if (type == DataType.Float32) { value = Convert.ToSingle(value); } else if (type == DataType.Float64) { value = Convert.ToDouble(value); } else if (type == DataType.DateTime) { type = DataType.OctetString; if (value is GXDateTime) { value = GetDateTime(value as GXDateTime); } else { value = GetDateTime(new GXDateTime(Convert.ToDateTime(value))); } reverse = false; } else if (type == DataType.Date) { GXDateTime dt; if (value is GXDateTime) { dt = value as GXDateTime; } else if (value is DateTime) { dt = new GXDateTime((DateTime)value); } else { throw new Exception("Invalid date format."); } type = DataType.OctetString; //Add size tmp.Add(5); //Add year. if ((dt.Skip & DateTimeSkips.Year) != 0) { GXCommon.SetUInt16(0xFFFF, tmp); } else { GXCommon.SetUInt16((ushort)dt.Value.Year, tmp); } //Add month. if (dt.DaylightSavingsBegin) { tmp.Add(0xFE); } else if (dt.DaylightSavingsEnd) { tmp.Add(0xFD); } else if ((dt.Skip & DateTimeSkips.Month) != 0) { tmp.Add(0xFF); } else { tmp.Add((byte)dt.Value.Month); } if ((dt.Skip & DateTimeSkips.Day) != 0) { tmp.Add(0xFF); } else { tmp.Add((byte)dt.Value.Day); } //Week day is not spesified. tmp.Add(0xFF); value = tmp.ToArray(); reverse = false; } else if (type == DataType.Time) { GXDateTime dt; if (value is GXDateTime) { dt = value as GXDateTime; } else if (value is DateTime) { dt = new GXDateTime((DateTime)value); } else { throw new Exception("Invalid date format."); } type = DataType.OctetString; //Add size tmp.Add(4); //Add time. if ((dt.Skip & DateTimeSkips.Hour) != 0) { tmp.Add(0xFF); } else { tmp.Add((byte)dt.Value.Hour); } if ((dt.Skip & DateTimeSkips.Minute) != 0) { tmp.Add(0xFF); } else { tmp.Add((byte)dt.Value.Minute); } if ((dt.Skip & DateTimeSkips.Second) != 0) { tmp.Add(0xFF); } else { tmp.Add((byte)dt.Value.Second); } tmp.Add((byte)0xFF); //Hundredths of second is not used. value = tmp.ToArray(); reverse = false; } else { throw new Exception("Invalid data type."); } buff.Add((byte)type); if (value != null) { byte[] data = Gurux.Shared.GXCommon.GetAsByteArray(value); if (reverse) { Array.Reverse(data); } buff.AddRange(data); } }
static byte[] GetDateTime(GXDateTime dt) { if (dt.Value == DateTime.MinValue) { dt.Value = DateTime.SpecifyKind(new DateTime(2000, 1, 1).Date, DateTimeKind.Utc); } else if (dt.Value == DateTime.MaxValue) { dt.Value = DateTime.SpecifyKind(DateTime.Now.AddYears(1).Date, DateTimeKind.Utc); } DateTime tm; //If used normal time. if ((dt.Skip & DateTimeSkips.Devitation) == 0) { tm = dt.Value; } else //If devitation is skipped. { //If value is given as UTC time. if (TimeZone.CurrentTimeZone.GetUtcOffset(dt.Value).TotalMinutes == 0) { tm = dt.Value; } else { tm = dt.Value.ToUniversalTime(); } } List <byte> tmp = new List <byte>(); //Add size tmp.Add(12); if ((dt.Skip & DateTimeSkips.Year) == 0) { GXCommon.SetUInt16((ushort)tm.Year, tmp); } else { GXCommon.SetUInt16((ushort)0xFFFF, tmp); } if ((dt.Skip & DateTimeSkips.Month) == 0) { if (dt.DaylightSavingsBegin) { tmp.Add(0xFE); } else if (dt.DaylightSavingsEnd) { tmp.Add(0xFD); } else { tmp.Add((byte)tm.Month); } } else { tmp.Add(0xFF); } if ((dt.Skip & DateTimeSkips.Day) == 0) { tmp.Add((byte)tm.Day); } else { tmp.Add(0xFF); } //Week day is not spesified. //Standard defines. tmp.Add(0xFF); tmp.Add(0xFF); //Add time. if ((dt.Skip & DateTimeSkips.Hour) == 0) { tmp.Add((byte)tm.Hour); } else { tmp.Add(0xFF); } if ((dt.Skip & DateTimeSkips.Minute) == 0) { tmp.Add((byte)tm.Minute); } else { tmp.Add(0xFF); } if ((dt.Skip & DateTimeSkips.Second) == 0) { tmp.Add((byte)tm.Second); } else { tmp.Add(0xFF); } if ((dt.Skip & DateTimeSkips.Ms) == 0) { tmp.Add((byte)(tm.Millisecond / 10)); } else { tmp.Add((byte)0xFF); //Hundredths of second is not used. } //Add deviation. if ((dt.Skip & DateTimeSkips.Devitation) == 0) { short devitation = (short)TimeZone.CurrentTimeZone.GetUtcOffset(dt.Value).TotalMinutes; GXCommon.SetInt16(devitation, tmp); } else //deviation not used. { tmp.Add((byte)0x00); tmp.Add((byte)0x00); } //Add clock_status tmp.Add((byte)dt.Status); return(tmp.ToArray()); }