public static bool TryParse(byte[] value, out ObisId result)
        {
            if (value.Length != 6)
            {
                result = ObisId.Invalid;
                return false;
            }

            result = new ObisId(value);
            return true;
        }
 public async Task WriteParameter(BinaryParam param, bool enableManufacturerMode = false)
 {
     var obisId = new ObisId((ulong)param.ObisCode);
     var result = await this.baseMeterDevice.WriteRegisterAsync(obisId, param.Data).ConfigureAwait(false);
     if (result != ResultCode.Ok)
     {
         throw new InvalidOperationException("Write failed with code: " + result);
     }
 }
        public async Task WriteParameter(BooleanParam param, bool enableManufacturerMode = false)
        {
            var obisId = new ObisId((ulong)param.ObisCode);

            if (param.Data == null)
            {
                param.Data = false;
            }

            // delete historic energy is a special 'RESET' command
            if (obisId == RegisterIds.HistoricConsumptionDay)
            {
                await this.productionParameters.ClearHistoricConsumptionData().ConfigureAwait(false);
                return;
            }

            if (obisId == RegisterIds.GridOptionEnabled)
            {
                await this.productionParameters.SetGridOption(param.Data.Value).ConfigureAwait(false);
                return;
            }

            if (obisId == RegisterIds.BaudrateOptionEnabled)
            {
                await this.productionParameters.SetBaudrateOptionEnabled(param.Data.Value).ConfigureAwait(false);
                return;
            }

            if (param.ObisCode == ObisEdl.DzgTerminalControlReverse.AsLong())
            {
                var tc = await this.baseMeterDevice.TariffControl.GetTariffConfiguration().ConfigureAwait(false);
                if (param.Data.Value == true)
                {
                    tc |= TariffConfiguration.OnActivationUseT1;
                }
                else
                {
                    tc &= ~TariffConfiguration.OnActivationUseT1;
                }

                await this.baseMeterDevice.TariffControl.SetTariffConfiguration(tc).ConfigureAwait(false);
                return;
            }

            var result = await this.baseMeterDevice.WriteRegisterAsync(obisId, param.Data).ConfigureAwait(false);//(new MeterValue(param.Data, obisId));
            if (result != ResultCode.Ok)
            {
                throw new InvalidOperationException("Write failed with code: " + result);
            }
        }
        public async Task WriteParameter(UnsignedParam param, bool enableManufacturerMode = false)
        {
            if (param.ObisCode == RegisterIds.SetTariff.AsLong())
            {
                var isTarrifTwo = param.Data.Value == 2;

                TariffConfiguration tariffConfiguration = TariffConfiguration.None;
                
                var mm = await this.productionParameters.GetMeasurementMode().ConfigureAwait(false);
                switch (mm)
                {
                    case MeasurmentMode.MM1_ImportReverseLocking:
                        tariffConfiguration = TariffConfiguration.Import;
                        break;
                    case MeasurmentMode.MM2_ImportExport:
                        tariffConfiguration = TariffConfiguration.Import | TariffConfiguration.Export;
                        break;
                    case MeasurmentMode.MM3_ExportLocking:
                    case MeasurmentMode.MM4_Export:
                        tariffConfiguration = TariffConfiguration.Export;
                        break;
                }

                // read configuration to get status of reverse tariff control
                var tc = await this.baseMeterDevice.TariffControl.GetTariffConfiguration().ConfigureAwait(false);
                if (tc.HasFlag(TariffConfiguration.OnActivationUseT1))
                {
                    tariffConfiguration |= TariffConfiguration.OnActivationUseT1;
                }

                await this.baseMeterDevice.TariffControl.SetTariffConfiguration(tariffConfiguration).ConfigureAwait(false);
                await this.baseMeterDevice.TariffControl.SetLmnTariffSignal(isTarrifTwo).ConfigureAwait(false);
            }
            else if (param.ObisCode == VendorSpecificRegisterIds.MeasurementMode.AsLong())
            {
                MeasurmentMode mmToWrite = (MeasurmentMode) param.Data.Value;
                await this.productionParameters.SetMeasurementMode(mmToWrite);
            }
            else
            {
                var obis = new ObisId((ulong) param.ObisCode);
                await this.baseMeterDevice.WriteRegisterAsync(obis, param.Data.Value).ConfigureAwait(false);
            }
        }
        public async Task<MeasurementValue> ReadRegister(long obisCode)
        {
            var obis = new ObisId((ulong) obisCode);
            var result = await this.baseMeterDevice.ReadRegisterAsync(obis).ConfigureAwait(false);
            if (result == null)
            {
                throw new NullReferenceException();
            }

            return new MeasurementValue()
            {
                ObisValue = obisCode, DataValue = (double?) result.GetAsDecimal(), Unit = result.GetUnit().ToString()
            };
        }
        public async Task<BinaryParam> ReadParameter(BinaryParam param)
        {
            var obis = new ObisId((ulong) param.ObisCode);
            var result = await this.baseMeterDevice.ReadRegisterAsync(obis).ConfigureAwait(false);
            if (result == null)
            {
                throw new NullReferenceException();
            }

            return new BinaryParam()
            {
                ObisCode = param.ObisCode, Data = result.GetAsByte()
            };
        }
        public async Task<BooleanParam> ReadParameter(BooleanParam param)
        {
            var obisId = new ObisId((ulong) param.ObisCode);

            if (obisId == RegisterIds.GridOptionEnabled)
            {
                var hasGridOption = await this.productionParameters.GetGridOption().ConfigureAwait(false);
                return new BooleanParam()
                {
                    ObisCode = param.ObisCode,
                    Data = hasGridOption
                };
            }

            if (obisId == RegisterIds.BaudrateOptionEnabled)
            {
                var hasBaudRateOption = await this.productionParameters.GetBaudrateOptionEnabled().ConfigureAwait(false);
                return new BooleanParam()
                {
                    ObisCode = param.ObisCode,
                    Data = hasBaudRateOption
                };
            }

            if (param.ObisCode == ObisEdl.DzgTerminalControlReverse.AsLong())
            {
                var tc = await this.baseMeterDevice.TariffControl.GetTariffConfiguration().ConfigureAwait(false);
                
                return new BooleanParam()
                {
                    ObisCode = param.ObisCode,
                    Data = tc.HasFlag(TariffConfiguration.OnActivationUseT1)
                };
            }

            var result = await this.baseMeterDevice.ReadRegisterAsync(obisId).ConfigureAwait(false);
            if (result == null)
            {
                throw new NullReferenceException();
            }

            return new BooleanParam()
            {
                ObisCode = param.ObisCode, Data = result.GetAsBool()
            };
        }
        public async Task<UnsignedParam> ReadParameter(UnsignedParam param)
        {
            if (param.ObisCode == VendorSpecificRegisterIds.MeasurementMode.AsLong())
            {
                var pp = new ProductionParameters(this.baseMeterDevice);
                MeasurmentMode mm = await pp.GetMeasurementMode().ConfigureAwait(false);
                ulong mmNumber = 0;
                switch (mm)
                {
                    case MeasurmentMode.MM1_ImportReverseLocking:
                        mmNumber = 1;
                        break;
                    case MeasurmentMode.MM2_ImportExport:
                        mmNumber = 2;
                        break;
                    case MeasurmentMode.MM3_ExportLocking:
                        mmNumber = 3;
                        break;
                    case MeasurmentMode.MM4_Export:
                        mmNumber = 4;
                        break;
                    default:
                        throw new ArgumentOutOfRangeException();
                }

                return new UnsignedParam()
                {
                    ObisCode = param.ObisCode,
                    Data = mmNumber
                };
            }

            var obis = new ObisId((ulong)param.ObisCode);
            var result = await this.baseMeterDevice.ReadRegisterAsync(obis).ConfigureAwait(false);
            if (result == null)
            {
                throw new NullReferenceException();
            }

            return new UnsignedParam()
            {
                ObisCode = param.ObisCode, Data = result.GetAsULong()
            };
        }
        public static bool TryParseString(string value, out ObisId result)
        {
            if (string.IsNullOrWhiteSpace(value))
            {
                result = ObisId.Invalid;
                return false;
            }

            if (value.Contains(" "))
            {
                value = value.Replace(" ", string.Empty);
            }

            if (IsHexString(value))
            {
                result = new ObisId(ulong.Parse(value, NumberStyles.HexNumber));
                return true;
            }

            result = new ObisId();
            if (!result.Set(value))
            {
                result = ObisId.Invalid;
                return false;
            }

            return true;
        }
        public bool CompareTo(ObisId other, ObisIdMembers membersToCompare)
        {
            if (((membersToCompare & ObisIdMembers.A) != 0) && (this.A != other.A))
            {
                return false;
            }

            if (((membersToCompare & ObisIdMembers.B) != 0) && (this.B != other.B))
            {
                return false;
            }

            if (((membersToCompare & ObisIdMembers.C) != 0) && (this.C != other.C))
            {
                return false;
            }

            if (((membersToCompare & ObisIdMembers.D) != 0) && (this.D != other.D))
            {
                return false;
            }

            if (((membersToCompare & ObisIdMembers.E) != 0) && (this.E != other.E))
            {
                return false;
            }

            if (((membersToCompare & ObisIdMembers.F) != 0) && (this.F != other.F))
            {
                return false;
            }

            return true;
        }
 public bool Equals(ObisId other)
 {
     return this.obisValue == other.obisValue;
 }