laatzen/Common/modbus_master_csharp/Communication/ValueEncoders/DeviceValueEncoder.cs

953 lines
46 KiB
C#

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using XYLEM.Communication;
using System.Xml;
using System.Xml.Linq;
using XYLEM.Base;
using XYLEM.Base.Files;
using XYLEM.Device.Value;
using System.Numerics;
using XYLEM.Communication.ValueEncoders;
using XYLEM.Base.XML;
namespace XYLEM.Communication.ValueEncoders
{
/// <summary>
/// Return used character set used for email or empty if not Loaded from setup
/// </summary>
/// <returns>ex. "iso-8859-1"</returns>
public delegate string GetEmailCharacterSetToUse();
public static class DeviceValueEncoder
{
public static object Default(this ValueDataType dataType)
{
try
{
switch (dataType)
{
case ValueDataType.U8:
case ValueDataType.B8: return (byte)0;
case ValueDataType.S8: return (sbyte)0;
case ValueDataType.B16:
case ValueDataType.U16:
case ValueDataType.U16MJK_SN:
return (UInt16)0;
case ValueDataType.U32TIME_Y1970:
case ValueDataType.U32TIME_Y1970_UTC: return ((UInt32)0).Convert1970SecToTime(TimeType.UTC);
case ValueDataType.U32TIME_Y2000: return ((UInt32)0).Convert2000SecToTime();
case ValueDataType.U32MJK_SN: return ((UInt32)0);
//case DeviceValueDataType.U24DateHH_MM_SS:
//case DeviceValueDataType.U48DateYY_MM_DD_HH_MM_SS: return ((UInt32)0);
//case DeviceValueDataType.U24:
//case DeviceValueDataType.U32TIMESPAN_MIDNIGHT_UTC:
case ValueDataType.B32:
case ValueDataType.U32: return (UInt32)0;
case ValueDataType.B64:
case ValueDataType.U64: return (UInt64)0;
case ValueDataType.F64: return (double)0;
case ValueDataType.U128: return (BigInteger)0;
case ValueDataType.S16: return (Int16)0;
case ValueDataType.F32: return (Single)0;
//case DeviceValueDataType.U32IPV4: return "0.0.0.0"; // handled as a string
default:
if (dataType.IsText())
{ // Do this as the last check to save CPU power
return "";
}
throw new Exception(dataType.ToString() + "has no default value)");
}
}
catch (Exception ex)
{
throw new Exception(ex.ToFuncErrorText(typeof(DeviceValueEncoder).ToString(), "Default()", "dataType = " + dataType.ToString()));
}
}
public static string EncodeXML(this object value, ValueDataType type)
{
try
{
string valueAsTxt = value.ToString();
switch (type)
{
case ValueDataType.U32TIME_Y1970:
case ValueDataType.U32TIME_Y1970_UTC:
if (value is DateTime)
{
var value32bit = ((DateTime)value).ConvertTimeTo1970Sec(TimeType.Local);
return XmlConvert.ToString(value32bit);
}
return XmlConvert.ToString((Double)value);
case ValueDataType.U32TIME_Y2000:
if (value is DateTime)
{
var value32bit = ((DateTime)value).ConvertTimeTo2000Sec(TimeType.Local);
return XmlConvert.ToString(value32bit);
}
return XmlConvert.ToString((Double)value);
case ValueDataType.U8:
case ValueDataType.B8:
case ValueDataType.S8:
//case DeviceValueDataType.U32TIMESPAN_MIDNIGHT_UTC:
case ValueDataType.B16:
case ValueDataType.U16:
case ValueDataType.U16MJK_SN:
//case DeviceValueDataType.U48DateYY_MM_DD_HH_MM_SS:
//case DeviceValueDataType.U24DateHH_MM_SS:
//case DeviceValueDataType.U24:
case ValueDataType.B32:
case ValueDataType.U32:
case ValueDataType.B64:
case ValueDataType.U64:
case ValueDataType.S16:
case ValueDataType.S32:
case ValueDataType.S64:
case ValueDataType.F32:
case ValueDataType.F64:
case ValueDataType.U32MJK_SN:
{
if (typeof(Double) == value.GetType())
{
valueAsTxt = XmlConvert.ToString((Double)value);
}
else if (typeof(Single) == value.GetType())
{
valueAsTxt = XmlConvert.ToString((Single)value);
}
return valueAsTxt;
}
case ValueDataType.U128:
if (typeof(BigInteger) == value.GetType())
{
valueAsTxt = ((BigInteger)value).ToString("X"); // enclode as hex
}
else
{
throw new Exception($"{value.GetType()} is not supported for U128 xml convert");
}
return valueAsTxt;
//case DeviceValueDataType.U32IPV4: return valueAsTxt.Trim( ).StripIllegalXMLChars( );// handled as a string
default:
if (type.IsText())
{ // Do this as the last check to save CPU power
return valueAsTxt.Trim().StripIllegalXMLChars();
}
throw new NotImplementedException("DataType '" + type + "' not recognized.");
}
}
catch (Exception ex)
{
throw new Exception(ex.ToFuncErrorText(typeof(DeviceValueEncoder).ToString(), "EncodeXML()", "dataType = " + type.ToString() + " Value is = " + value.ToString()));
}
}
public static Object DecodeXML(this string valueInXml, ValueDataType type)
{
try
{
switch (type)
{
case ValueDataType.U32TIME_Y1970:
case ValueDataType.U32TIME_Y1970_UTC:
return XmlConvert.ToUInt32(valueInXml).Convert1970SecToTime(TimeType.Local);
case ValueDataType.U32TIME_Y2000:
return XmlConvert.ToUInt32(valueInXml).Convert2000SecToTime();
//case DeviceValueDataType.U32TIMESPAN_MIDNIGHT_UTC: return XmlConvert.ToUInt32( valueInXml );
case ValueDataType.B8:
case ValueDataType.U8:
return XmlConvert.ToByte(valueInXml);
case ValueDataType.S8:
return XmlConvert.ToSByte(valueInXml);
case ValueDataType.B16:
case ValueDataType.U16:
case ValueDataType.U16MJK_SN:
return XmlConvert.ToUInt16(valueInXml);
//case DeviceValueDataType.U24DateHH_MM_SS:
//case DeviceValueDataType.U48DateYY_MM_DD_HH_MM_SS:
//case DeviceValueDataType.U24:
case ValueDataType.B32:
case ValueDataType.U32:
case ValueDataType.U32MJK_SN:
return XmlConvert.ToUInt32(valueInXml);
case ValueDataType.B64:
case ValueDataType.U64: return XmlConvert.ToUInt64(valueInXml);
case ValueDataType.S16: return XmlConvert.ToInt16(valueInXml);
case ValueDataType.S32: return XmlConvert.ToInt32(valueInXml);
case ValueDataType.S64: return XmlConvert.ToInt64(valueInXml);
case ValueDataType.F32: return XmlConvert.ToSingle(valueInXml);
case ValueDataType.F64: return XmlConvert.ToDouble(valueInXml);
case ValueDataType.U128: return BigInteger.Parse(valueInXml, System.Globalization.NumberStyles.HexNumber);
//case DeviceValueDataType.U32IPV4: return valueInXml.ReinsetIllegalXMLChars( );// handled as a string
default:
if (type.IsText())
{ // Do this as the last check to save CPU power
return valueInXml.ReinsetIllegalXMLChars();
}
throw new NotImplementedException("DataType '" + type + "' not recognized.");
}
}
catch (Exception ex)
{
throw new Exception(ex.ToFuncErrorText(typeof(DeviceValueEncoder).ToString(), "DecodeXML()", "dataType = " + type.ToString() + " Value is = " + valueInXml));
}
}
/// <summary>
/// do layout changes on byte stream
/// </summary>
/// <param name="bytes"></param>
/// <param name="layout"></param>
/// <returns></returns>
static byte[] DoLayout(this byte[] bytes, LayoutType layout = LayoutType.Normal)
{
try
{
switch (layout)
{
case LayoutType.Normal: return bytes; ; // Do nothing
case LayoutType.SwapAll: return bytes.Reverse();
default:
throw new NotSupportedException(layout + " is not supported");
}
}
catch (Exception ex)
{
throw new Exception(ex.ToFuncErrorText(typeof(DeviceValueEncoder).ToString(), "DoLayout", "layout = " + layout));
}
}
/// <summary>
/// Encode data with normal data layout
/// </summary>
/// <param name="value"></param>
/// <param name="dataType"></param>
/// <param name="EmailCharacterSet">Null if not used</param>
/// <returns></returns>
public static byte[] Encode(this object value, ValueDataType dataType, GetEmailCharacterSetToUse emailCharacterSet = null)
{
try
{
if (value == null)
{
throw new Exception("Value is null");
}
switch (dataType)
{
case ValueDataType.B8:
case ValueDataType.U8:
{
value = CorrectTypeIfNotTheSame(value, dataType, typeof(byte));// Try set type if not the correct one
return BitConverter.GetBytes((byte)value);
}
case ValueDataType.S8:
{
value = CorrectTypeIfNotTheSame(value, dataType, typeof(sbyte));// Try set type if not the correct one
return BitConverter.GetBytes((sbyte)value);
}
case ValueDataType.B16:
case ValueDataType.U16:
case ValueDataType.U16MJK_SN:
return BitConverter.GetBytes((UInt16)value);
case ValueDataType.U32TIME_Y1970:
if (value is DateTime)
{
return BitConverter.GetBytes(((DateTime)value).ConvertTimeTo1970Sec(TimeType.Local));
}
return BitConverter.GetBytes((UInt32)value); // Work around on olde types
case ValueDataType.U32TIME_Y1970_UTC:
if (value is DateTime)
{
return BitConverter.GetBytes(((DateTime)value).ConvertTimeTo1970Sec(TimeType.UTC));
}
return BitConverter.GetBytes((UInt32)value); // Work around on olde types
case ValueDataType.U32TIME_Y2000:
if (value is DateTime)
{
return BitConverter.GetBytes(((DateTime)value).ConvertTimeTo2000Sec(TimeType.Local));
}
return BitConverter.GetBytes((UInt32)value);
// Work around on olde types
//case DeviceValueDataType.U32TIMESPAN_MIDNIGHT_UTC:
// return BitConverter.GetBytes( TimeConvertClass.ToMidnightSecOffsetUTC( (UInt32)value ) );
//case DeviceValueDataType.U24DateHH_MM_SS: {
// var timeSpan = TimeConvertClass.ConvertTimeSpan( (UInt32)value );
// return new byte[] { (byte)timeSpan.Seconds, (byte)timeSpan.Minutes, (byte)timeSpan.Hours };
// }
//case DeviceValueDataType.U48DateYY_MM_DD_HH_MM_SS: {
// var date = ((UInt32)value).Convert1970SecToTime( TimeType.Local );
// return new byte[] {
// (byte)date.Second,
// (byte)date.Minute,
// (byte)date.Hour,
// (byte)date.Day,
// (byte)date.Month,
// (byte)(date.Year - 2000)
// };
// }
//case DeviceValueDataType.U24: {
// value = CorrectTypeIfNotTheSame( value, dataType, typeof( UInt32 ) );// Try set type if not the correct one
// return BitConverter.GetBytes( (UInt32)value ).Remove( 3 );
// }
case ValueDataType.B32:
case ValueDataType.U32:
case ValueDataType.U32MJK_SN:
{
value = CorrectTypeIfNotTheSame(value, dataType, typeof(UInt32));// Try set type if not the correct one
return BitConverter.GetBytes((UInt32)value);
}
case ValueDataType.B64:
case ValueDataType.U64:
{
value = CorrectTypeIfNotTheSame(value, dataType, typeof(UInt64));// Try set type if not the correct one
return BitConverter.GetBytes((UInt64)value);
}
case ValueDataType.S16:
{
value = CorrectTypeIfNotTheSame(value, dataType, typeof(Int16));// Try set type if not the correct one
return BitConverter.GetBytes((Int16)value);
}
case ValueDataType.S32:
{
value = CorrectTypeIfNotTheSame(value, dataType, typeof(Int32));// Try set type if not the correct one
return BitConverter.GetBytes((Int32)value);
}
case ValueDataType.F32:
{
value = CorrectTypeIfNotTheSame(value, dataType, typeof(Single));// Try set type if not the correct one
return BitConverter.GetBytes((Single)value);
}
case ValueDataType.F64:
{
value = CorrectTypeIfNotTheSame(value, dataType, typeof(double));// Try set type if not the correct one
return BitConverter.GetBytes((double)value);
}
case ValueDataType.U128:
{
value = CorrectTypeIfNotTheSame(value, dataType, typeof(BigInteger));// Try set type if not the correct one
return ((BigInteger)value).ToByteArray(); // TODO: Is this okay or need always to be the 16 byte in size?
}
//case DeviceValueDataType.U32IPV4: return U32_IP_Encoder.Encode( value.ToString( ) );
default:
if (dataType.IsText())
{ // Do this as the last check to save CPU power
var typeAsText = dataType.ToString();
// is Email
if (dataType.IsEmailText())
{
return StringEncoderEmail.Encode(value.ToString(), Length(dataType), ((emailCharacterSet == null) ? "" : emailCharacterSet()));
}
// is SMS
if (dataType.IsSMSText())
{
return StringEncoderUnicode.Encode(value.ToString(), Length(dataType));
}
// is Windows 1252
if (dataType.IsWindows1252Text())
{
return StringEncoder_W1252.Encode(value.ToString(), Length(dataType));
}
// is Windows 1252, but needs to have "<>" in frond and end
// Ex. end result is "<tmo@xyleminc.com>,<tmo@mjk.dk>" or "<tmo@xyleminc.com>"
if (dataType.IsWindows1252TextRecipient())
{
var valueAsText = value.ToString().Trim();
if (!String.IsNullOrEmpty(valueAsText))
{
// Remove manual added brackets or " if user has done it in the past
if (valueAsText.Contains("\""))
{
valueAsText = valueAsText.Replace("\"", "");
}
//// work arround if user has already used "," as separation
//if (valueAsText.Contains( "," )) {
// valueAsText = valueAsText.Replace( ",", ">,<" ); //old modem firmware V1.003 and TDC NO
//}
// Replace ";" with correct "," as separation and add bracked ">" "<" to support RCF821
if (valueAsText.Contains(";"))
{
//valueAsText = valueAsText.Replace( ";", ">,<" ); old modem firmware V1.003 and TDC NO
valueAsText = valueAsText.Replace(";", ",");//new modem firmware V1.3 using mail.mjk-link.dk
}
// Trim
valueAsText = valueAsText.Trim();
// Add brackets "<>" around address / addresses and end with " to tell modem where it starts and end in MC55I at command
//Ex. end result is "<tmo@xyleminc.com>,<tmo@mjk.dk>" or "<tmo@xyleminc.com>"
if (!String.IsNullOrEmpty(valueAsText))
{
//valueAsText = "\"<" + valueAsText + "\">"; old modem firmware V1.003 and TDC NO
valueAsText = "\"" + valueAsText + "\""; //new modem firmware V1.3 using mail.mjk-link.dk
}
}
return StringEncoder_W1252.Encode(valueAsText, Length(dataType));
}
// is Quoted Printable Text
if (dataType.IsEmailQuotedPrintableText())
{
return StringEncoderEmail_Q_Types.Encode(value.ToString(), Length(dataType), ((emailCharacterSet == null) ? "" : emailCharacterSet()));
}
// Is is normal utf8
return StringEncoder.Encode(value.ToString(), Length(dataType));
}
throw new NotImplementedException("DataType '" + dataType + "' not recognized.");
}
}
catch (Exception ex)
{
throw new Exception(ex.ToFuncErrorText(typeof(DeviceValueEncoder).ToString(), "Encode", "dataType = " + dataType.ToString()));
}
}
private static object CorrectTypeIfNotTheSame(object value, ValueDataType correctTypeTag, Type typeUsedForCast)
{
try
{
if (value.GetType() == typeUsedForCast)
{
return value; // Nothing to change
}
{
AppConst.Logger.AddFuncLog(
#if DEBUG //
true // log as error
#else
false // Log silent in log
#endif //#if DEBUG
, typeof(DeviceValueEncoder).ToString(), "CorrectTypeIfNotTheSame()",
"Warning! correction was needed. Is this a older setting else not okay? " + MakeCorrectTypeValueInfoText(value, correctTypeTag, typeUsedForCast)
);
}
return ToValue(value.ToString(), correctTypeTag);
}
catch (Exception ex)
{
var valueInfo = MakeCorrectTypeValueInfoText(value, correctTypeTag, typeUsedForCast);
throw new Exception(ex.ToFuncErrorText(typeof(DeviceValueEncoder).ToString(), "CorrectTypeIfNotTheSame", valueInfo));
}
}
/// <summary>
/// Generate the value info possible to get for a value to convert
/// </summary>
/// <param name="value">Value to correct</param>
/// <param name="correctTypeTag">correct value type tag</param>
/// <param name="typeUsedForCast">type used for cast</param>
/// <returns>Text to show in log</returns>
private static string MakeCorrectTypeValueInfoText(object value, ValueDataType correctTypeTag, Type typeUsedForCast)
{
var ValueInfo = "";
try
{
if (ValueInfo == null)
{
ValueInfo += " Value= IS NULL and not possible to correct!";
}
else
{
ValueInfo += " Value=\"" + value.ToString() + "\"";
ValueInfo += " From Type=\"" + value.GetType() + "\"";
}
ValueInfo += " To Type=\"" + correctTypeTag.ToString() + "\"";
}
catch { ValueInfo += " [Fail to get info ?] "; }
return ValueInfo;
}
/// <summary>
/// Encode data with data layout setting
/// </summary>
/// <param name="value"></param>
/// <param name="dataType"></param>
/// <param name="layout"></param>
/// <param name="emailCharacterSet">Null if not used</param>
/// <returns></returns>
public static byte[] Encode(this object value, ValueDataType dataType, LayoutType layout, GetEmailCharacterSetToUse emailCharacterSet = null)
{
try
{
var bytes = Encode(value, dataType, emailCharacterSet);
if (bytes == null)
{
return bytes;
}
return bytes.DoLayout(layout);
}
catch (Exception ex)
{
throw new Exception(ex.ToFuncErrorText(typeof(DeviceValueEncoder).ToString(), "Encode", "dataType = " + dataType.ToString()));
}
}
/// <summary>
/// Decode data with normal data layout
/// </summary>
/// <param name="value"></param>
/// <param name="dataType"></param>
/// <param name="emailCharacterSet">Null if not used</param>
/// <returns></returns>
public static object Decode(this byte[] value, ValueDataType dataType, GetEmailCharacterSetToUse emailCharacterSet = null)
{
try
{
if (value == null)
{
throw new Exception("Value is null");
}
if (value.Count() == 0)
{
throw new Exception("Value Has no values in array");
}
switch (dataType)
{
case ValueDataType.B8:
case ValueDataType.U8:
return (byte)value.First();
case ValueDataType.S8:
return (sbyte)value.First();
case ValueDataType.B16:
case ValueDataType.U16:
case ValueDataType.U16MJK_SN:
return BitConverter.ToUInt16(value, 0);
case ValueDataType.U32TIME_Y1970:
return BitConverter.ToUInt32(value, 0).Convert1970SecToTime(TimeType.Local);
case ValueDataType.U32TIME_Y1970_UTC:
return BitConverter.ToUInt32(value, 0).Convert1970SecToTime(TimeType.UTC).ToLocalTime();
case ValueDataType.U32TIME_Y2000:
return BitConverter.ToUInt32(value, 0).Convert2000SecToTime();
//case DeviceValueDataType.U32TIMESPAN_MIDNIGHT_UTC:
// return TimeConvertClass.FromMidnightSecOffsetUTC( BitConverter.ToUInt32( value, 0 ) );
//case DeviceValueDataType.U24DateHH_MM_SS: {
// return (UInt32)((UInt32)value[ 2 ] * 3600) + ((UInt32)value[ 1 ] * 60 + (UInt32)value[ 0 ]);
// }
//case DeviceValueDataType.U48DateYY_MM_DD_HH_MM_SS: {
// var date = new DateTime( (int)value[ 5 ] + 2000, value[ 4 ], value[ 3 ], value[ 2 ], value[ 1 ], value[ 0 ] );
// return date.ConvertTimeTo1970Sec( TimeType.Local );
// }
//case DeviceValueDataType.U24: {
// var as32bitValue = new byte[] { value[ 0 ], value[ 1 ], value[ 2 ], 0 };
// return BitConverter.ToUInt32( as32bitValue, 0 );
// }
case ValueDataType.B32:
case ValueDataType.U32:
case ValueDataType.U32MJK_SN:
return BitConverter.ToUInt32(value, 0);
case ValueDataType.B64:
case ValueDataType.U64: return BitConverter.ToUInt64(value, 0);
case ValueDataType.S16: return BitConverter.ToInt16(value, 0);
case ValueDataType.S32: return BitConverter.ToInt32(value, 0);
case ValueDataType.F32: return BitConverter.ToSingle(value, 0);
case ValueDataType.F64: return BitConverter.ToDouble(value, 0);
case ValueDataType.U128:
{
// Need a zero in msb to avoid value is handled as signed
var valueConverted = new BigInteger((value).Concat(new byte[1]).ToArray());
return valueConverted;
}
case ValueDataType.Array6B:
case ValueDataType.Array10B:
case ValueDataType.Array12B:
case ValueDataType.Array64B:
case ValueDataType.Array128B:
case ValueDataType.Array136B:
case ValueDataType.Array250B: return value;
//case DeviceValueDataType.U32IPV4: return U32_IP_Encoder.Decode( value );
default:
if (dataType.IsText())
{ // Do this as the last check to save CPU power
var typeAsText = dataType.ToString();
if (dataType.IsEmailText())
{ // is Email
return StringEncoderEmail.Decode(value, Length(dataType), ((emailCharacterSet == null) ? "" : emailCharacterSet()));
}
if (dataType.IsSMSText())
{ // is SMS
return StringEncoderUnicode.Decode(value, Length(dataType));
}
if (dataType.IsWindows1252Text())
{ // is Windows 1252
return StringEncoder_W1252.Decode(value, Length(dataType));
}
if (dataType.IsWindows1252TextRecipient())
{ // is Windows 1252, but needs to have "<>" in frond and end
var valueAsText = StringEncoder_W1252.Decode(value, Length(dataType));
if (!String.IsNullOrEmpty(valueAsText))
{
// Remove added brackets or " nessesarry that is only to be
// Ex. end result is "<tmo@xyleminc.com>,<tmo@mjk.dk>" or "<tmo@xyleminc.com>"
if (valueAsText.Contains("\""))
{
valueAsText = valueAsText.Replace("\"", "");
}
if (valueAsText.Contains("<"))
{
valueAsText = valueAsText.Replace("<", "");
}
if (valueAsText.Contains(">"))
{
valueAsText = valueAsText.Replace(">", "");
}
// Replace email seperation and replace it with correct the standard ";"
if (valueAsText.Contains(","))
{
valueAsText = valueAsText.Replace(",", ";");
}
}
return valueAsText;
}
if (dataType.IsEmailQuotedPrintableText())
{
return StringEncoderEmail_Q_Types.Decode(value, Length(dataType), ((emailCharacterSet == null) ? "" : emailCharacterSet()));
}
// Is allowed to have a variable length on a string / text
var maxLng = dataType.Length();
if (value.Length > maxLng)
{
throw new Exception(String.Format("Size of text is {0} and more than max {1}", value.Length, maxLng));
}
// Is is normal utf8
return StringEncoder.Decode(value, value.Length);
}
throw new NotImplementedException("DataType '" + dataType + "' not recognized.");
}
}
catch (Exception ex)
{
throw new Exception(ex.ToFuncErrorText(typeof(DeviceValueEncoder).ToString(), "Decode", "dataType = " + dataType.ToString()));
}
}
/// <summary>
/// Decode data with data layout setting
/// </summary>
/// <param name="value"></param>
/// <param name="dataType"></param>
/// <param name="emailCharacterSet">Null if not used</param>
/// <param name="layout"></param>
/// <returns></returns>
public static object Decode(this byte[] value, ValueDataType dataType, LayoutType layout, GetEmailCharacterSetToUse emailCharacterSet = null)
{
try
{
var bytes = value.DoLayout(layout);
return Decode(value, dataType, emailCharacterSet);
}
catch (Exception ex)
{
throw new Exception(ex.ToFuncErrorText(typeof(DeviceValueEncoder).ToString(), "Encode", "dataType = " + dataType.ToString()));
}
}
/// <summary>
/// Convert a local defined string value to the correct value object according to dataType ("DeviceValueType")
/// </summary>
/// <param name="value">Value as string (floating point must use local setting for "," or ".") and DateTime as local time </param>
/// <param name="dataType"></param>
/// <returns></returns>
public static object ToValue(this string value, ValueDataType dataType)
{
try
{
if (value == null)
{
throw new Exception("Value is null");
}
switch (dataType)
{
case ValueDataType.B8:
case ValueDataType.U8:
return (byte)Convert.ToUInt16(value);
case ValueDataType.S8:
return (sbyte)Convert.ToInt16(value);
case ValueDataType.B16:
case ValueDataType.U16:
case ValueDataType.U16MJK_SN:
return Convert.ToUInt16(value);
case ValueDataType.U32TIME_Y1970:
case ValueDataType.U32TIME_Y1970_UTC:
case ValueDataType.U32TIME_Y2000:
// Always expect this as local time
return new DateTime(Convert.ToDateTime(value).Ticks, DateTimeKind.Local);
//case DeviceValueDataType.U32TIMESPAN_MIDNIGHT_UTC:
//case DeviceValueDataType.U24DateHH_MM_SS:
//case DeviceValueDataType.U24:
case ValueDataType.B32:
case ValueDataType.U32:
case ValueDataType.U32MJK_SN:
return Convert.ToUInt32(value);
case ValueDataType.B64:
case ValueDataType.U64: return Convert.ToUInt64(value);
case ValueDataType.S16: return Convert.ToInt16(value);
case ValueDataType.S32: return Convert.ToInt32(value);
case ValueDataType.F32: return Convert.ToSingle(value);
case ValueDataType.F64: return Convert.ToDouble(value);
case ValueDataType.U128:
// Need a zero in msb to avoid value is handled as signed
return BigInteger.Parse("0"+value, System.Globalization.NumberStyles.HexNumber);
//case DeviceValueDataType.U32IPV4: {
// if (dataType.IsText( )) {
// return value.ToString( );
// }
// throw new NotImplementedException( "DataType '" + dataType + "' not recognized." );
// }
default:
if (dataType.IsText())
{ // Do this as the last check to save CPU power
var typeAsText = dataType.ToString();
if (dataType.IsEmailText())
{ // is Email
return value;
}
if (dataType.IsSMSText())
{ // is SMS
return value;
}
if (dataType.IsWindows1252Text())
{ // is Windows 1252
return value;
}
if (dataType.IsWindows1252TextRecipient())
{ // is Windows 1252, but needs to have "<>" in frond and end
return value;
}
if (dataType.IsEmailQuotedPrintableText())
{ // is Special Email Quoted Printable
return value;
}
// Is is normal utf8
return value; //TODO: No converting is done. may have to be converted to utf8?
}
throw new NotImplementedException("DataType '" + dataType + "' not recognized.");
}
}
catch (Exception ex)
{
throw new Exception(ex.ToFuncErrorText(typeof(DeviceValueEncoder).ToString(), "ToValue()", "dataType = " + dataType.ToString()));
}
}
/// <summary>
/// Return data Byte Length (1x8bit)
/// </summary>
/// <returns></returns>
public static int Length(this ValueDataType DataType)
{
try
{
switch (DataType)
{
case ValueDataType._Empty: return 0;
#region ---- 8 Bit ----
case ValueDataType.Bool:
case ValueDataType.B8:
case ValueDataType.S8:
case ValueDataType.U8: return 1;
#endregion // #region ---- 8 Bit ----
//case DeviceValueDataType.U24DateHH_MM_SS:
//case DeviceValueDataType.U24: return 3;
//case DeviceValueDataType.U48DateYY_MM_DD_HH_MM_SS: return 6;
default:
return WLength(DataType) << 1;
}
}
catch (Exception ex)
{
throw new Exception(ex.ToFuncErrorText(typeof(DeviceValueEncoder).ToString(), "Length"));
}
}
/// <summary>
/// Return data Word Length (2x8bit)
/// </summary>
/// <returns></returns>
public static int WLength(this ValueDataType DataType)
{
try
{
switch (DataType)
{
case ValueDataType._Empty: return 0;
#region ---- 8 / 16 Bit ----
case ValueDataType.Bool:
case ValueDataType.B8:
case ValueDataType.S8:
case ValueDataType.U8:
case ValueDataType.U16:
case ValueDataType.U16MJK_SN:
case ValueDataType.B16:
case ValueDataType.S16:
case ValueDataType.U16TEXTID:
case ValueDataType.U16UNIT:
case ValueDataType.U16UNITGROUP: return 1;
#endregion
//case DeviceValueDataType.U48DateYY_MM_DD_HH_MM_SS: return 3;
//case DeviceValueDataType.U24DateHH_MM_SS:
//case DeviceValueDataType.U24: return 2;
#region ---- 32 Bit ----
case ValueDataType.B32:
case ValueDataType.U32:
case ValueDataType.U32MJK_SN:
case ValueDataType.S32:
case ValueDataType.F32:
//case DeviceValueDataType.U32TIMESPAN_MIDNIGHT_UTC:
case ValueDataType.U32TIME_Y2000:
case ValueDataType.U32TIME_Y1970:
case ValueDataType.U32TIME_Y1970_UTC:
//case DeviceValueDataType.U32IPV4:
return 2;
#endregion
#region ---- 12 x 8 Bit Time Types ----
case ValueDataType.TIME_ASCII_12B:
case ValueDataType.TIME_ymdhms:
return 6;
#endregion
#region ---- 64 Bit ----
case ValueDataType.B64:
case ValueDataType.U64:
case ValueDataType.S64:
case ValueDataType.F64:
return 4;
#endregion
#region ---- 128 Bit ----
case ValueDataType.U128:
return 8;
#endregion
#region ---- Bit Arrays ----
case ValueDataType.Array6B: return (6 / 2);
case ValueDataType.Array10B: return (10 / 2);
case ValueDataType.Array12B: return (12 / 2);
case ValueDataType.Array64B: return (64 / 2);
case ValueDataType.Array128B: return (128 / 2);
case ValueDataType.Array136B: return (136 / 2);
case ValueDataType.Array250B: return (250 / 2);
#endregion
#region ---- Strings / Text ----
//6bytes
case ValueDataType.STR6E:
case ValueDataType.STR6S:
//case DeviceValueDataType.STR6Q:
//case DeviceValueDataType.STR6W1252:
case ValueDataType.STR6: return 3;
//8bytes
case ValueDataType.STR8E:
case ValueDataType.STR8S:
//case DeviceValueDataType.STR8Q:
//case DeviceValueDataType.STR8W1252:
case ValueDataType.STR8: return 4;
//10bytes
case ValueDataType.STR10E:
case ValueDataType.STR10S:
//case DeviceValueDataType.STR10Q:
//case DeviceValueDataType.STR10W1252:
case ValueDataType.STR10: return 5;
//16bytes
case ValueDataType.STR16E:
case ValueDataType.STR16S:
//case DeviceValueDataType.STR16Q:
//case DeviceValueDataType.STR16W1252:
case ValueDataType.STR16: return 8;
//18bytes
case ValueDataType.STR18E:
case ValueDataType.STR18S:
//case DeviceValueDataType.STR18Q:
//case DeviceValueDataType.STR18W1252:
case ValueDataType.STR18: return 9;
//20bytes
case ValueDataType.STR20E:
case ValueDataType.STR20S:
//case DeviceValueDataType.STR20Q:
//case DeviceValueDataType.STR20W1252:
case ValueDataType.STR20: return 10;
//22bytes
case ValueDataType.STR22E:
case ValueDataType.STR22S:
//case DeviceValueDataType.STR22Q:
//case DeviceValueDataType.STR22W1252:
case ValueDataType.STR22: return 11;
//30bytes
case ValueDataType.STR30E:
case ValueDataType.STR30S:
//case DeviceValueDataType.STR30Q:
//case DeviceValueDataType.STR30W1252:
case ValueDataType.STR30: return 15;
//32bytes
case ValueDataType.STR32E:
case ValueDataType.STR32S:
//case DeviceValueDataType.STR32Q:
//case DeviceValueDataType.STR32W1252:
case ValueDataType.STR32: return 16;
//64bytes
case ValueDataType.STR64E:
case ValueDataType.STR64S:
//case DeviceValueDataType.STR64Q:
//case DeviceValueDataType.STR64W1252:
case ValueDataType.STR64: return 32;
//100bytes
case ValueDataType.STR100E:
case ValueDataType.STR100S:
//case DeviceValueDataType.STR100Q:
//case DeviceValueDataType.STR100W1252:
case ValueDataType.STR100: return 50;
//128bytes
case ValueDataType.STR128E:
case ValueDataType.STR128S:
//case DeviceValueDataType.STR128Q:
//case DeviceValueDataType.STR128W1252:
//case DeviceValueDataType.STR128W1252rec:
case ValueDataType.STR128: return 64;
//160bytes
//case DeviceValueDataType.STR160E:
//case DeviceValueDataType.STR160S:
//case DeviceValueDataType.STR160Q:
//case DeviceValueDataType.STR160W1252:
//case DeviceValueDataType.STR160: return 80;
//240bytes
case ValueDataType.STR240E:
case ValueDataType.STR240S:
//case DeviceValueDataType.STR240Q:
//case DeviceValueDataType.STR240W1252:
case ValueDataType.STR240: return 240;
#endregion
default:
throw (new Exception("No known length for tag = " + DataType.ToString()));
}
}
catch (Exception ex)
{
throw new Exception(ex.ToFuncErrorText(typeof(DeviceValueEncoder).ToString(), "WLength"));
}
}
/// <summary>
/// Return the text length for value type if it is a text
/// </summary>
/// <returns></returns>
public static int StringLength(this ValueDataType DataType)
{
try
{
switch (DataType)
{
//case DeviceValueDataType.U32IPV4: return (4 * 3 + 3);
default:
if (DataType.IsSMSText())
{ // is SMS
return DataType.Length() / 2; // is always 16bit
}
return Length(DataType);
}
}
catch (Exception ex)
{
throw new Exception(ex.ToFuncErrorText(typeof(DeviceValueEncoder).ToString(), "StringLength"));
}
}
}
}