/// <summary> /// Execute protocol command /// </summary> /// <param name="cmd">The command to execute</param> /// <param name="parameter">Interface to command parameters</param> /// <returns>Interface to executed command result</returns> public IEECommandResult ExecuteCommand(EE31Command cmd, IEECommandParameter parameter) { if (!_listCommands.ContainsKey(cmd)) { return new EECmdResultBase() { Code = EECmdResultCode.UnknownCmd } } ; if (parameter == null) { return new EECmdResultBase() { Code = EECmdResultCode.InvalidParamClass } } ; // Set command basics and special treatments needed to handle commands properly var command = _listCommands[cmd]; command.ProtocolCallbacks = this; command.ProtocolConverters = this; // Some command parameters need special conversion (parameter as EECmdParamBase).ConvertData(this); return(command.Execute(parameter)); }
/// <summary> /// Sends a command to the device and receives a response. /// </summary> /// <param name="param">The command parameter data.</param> /// <param name="response">@ACK: Payload data (without ACK), @NAK: Error code (1 Byte)</param> /// <param name="rawDataToTx">Raw data bytes to transmit immediately after sending the command frame.</param> /// <returns></returns> public EECmdResultCode SendReceive(IEECommandParameter param, out byte[] response, byte[] rawDataToTx = null) { response = null; int rxBusAddr = 0; try { SendCmdMultiResponse(CommunicationInterface, param.Cmd, param.CmdData, param.CmdTries ?? CmdTimeoutAutoRetries, param.CmdTimeoutMs ?? CmdTimeoutMSec, param.CmdBusAddr ?? TransmitterBusAddr, false, out IList <EE31CmdResponseData> responses, rawDataToTx); if (responses.Count > 0) { response = responses[0].Response; rxBusAddr = responses[0].RxBusAddr; // Evaluate result if (responses[0].Result == EE31Result.ACK) { return(EECmdResultCode.Success); } else if (responses[0].Result == EE31Result.NAK && response.Length > 0 && response[0] == 0xF9) { return(EECmdResultCode.Busy); } else if (responses[0].Result == EE31Result.NAK && response.Length > 0 && response[0] == 0xFC) { return(EECmdResultCode.InvalidParameter); } else if (responses[0].Result == EE31Result.NAK && response.Length > 0 && response[0] == 0xFE) { return(EECmdResultCode.UnknownCmd); } else { return(EECmdResultCode.Failed); } } } catch (System.IO.IOException) { } // IOException happens i.e. when USB hardware is disconnected catch (Exception ex) { Diagnostic.Msg(1, string.Format("SendReceive ({0:X2})", param.Cmd), "Exception: " + ex.Message); } return(EECmdResultCode.Failed); }
public override IEECommandResult Execute(IEECommandParameter parameter) { if (parameter is DiscoveryCmdParams diasParams) { // Multiple transmitters might respond to this command ProtocolCallbacks.SendReceiveMulti(parameter, out IList <EE31CmdResponseData> responses); // i.e. EE600 (FSM Firmware): DIAS message is answered with NAK/FC => Invalid or wrong parameter // 00 00 52 02 15 FC 65 if (null != responses && responses.Count >= 1) { EE31CmdResponseData respData = responses[0]; if (EE31Result.NAK == respData.Result && null != respData.Response && respData.Response.Length >= 1 && respData.Response[0] == 0xFC) { // Retry query with standard 0x52 command (no parameters) ProtocolCallbacks.SendReceiveMulti(parameter, out responses); } } DiscoveryCmdResult result = new DiscoveryCmdResult(); result.Code = EECmdResultCode.Success; result.Data = new byte[0]; // DiasCmdResult cannot use base class data buffer // because it needs special result data based on multiple responses (found devices) if (null != responses) { foreach (EE31CmdResponseData responseData in responses) { if (EE31Result.ACK != responseData.Result) { continue; } if (IdentifyDevice(responseData, out ushort busAddr, out ushort hwCode, out string modelText, out byte nativeProtocol)) { // Append result data result.Devices.Add(new DiscoveryCmdResult.FoundDevice() { BusAddr = busAddr, HwCode = hwCode, ModelText = modelText, NativeProtocol = nativeProtocol, }); } } } return(result); } else { return(CreateResult(EECmdResultCode.InvalidParamClass, null, null)); } }
/// <summary> /// Provide default execution function. Might be overwritten in command classes. /// </summary> /// <param name="parameter"></param> /// <returns></returns> public virtual IEECommandResult Execute(IEECommandParameter parameter) { if (parameter is TParamClass) { EECmdResultCode result = ProtocolCallbacks.SendReceive(parameter, out byte[] response); return(CreateResult(result, response, parameter)); } else { return(CreateResult(EECmdResultCode.InvalidParamClass, null, null)); } }
public override IEECommandResult Execute(IEECommandParameter parameter) { if (parameter is UploadBlockCmdParams uploadParams) { // Send command with payload (right after cmd CRC) EECmdResultCode result = ProtocolCallbacks.SendReceive(parameter, out byte[] response, uploadParams.BlockData); return(CreateResult(result, response, parameter)); } else { return(CreateResult(EECmdResultCode.InvalidParamClass, null, null)); } }
public override IEECommandResult Execute(IEECommandParameter parameter) { IEECommandResult commandResult = base.Execute(parameter); // BUSY retries if configured int retries = (parameter as GetTunnelCmdParams).TunnelCmdBusyRetries; while (commandResult.Code == EECmdResultCode.Busy && retries-- > 0) { Thread.Sleep((parameter as GetTunnelCmdParams).TunnelCmdBusyWaitMs); commandResult = base.Execute(parameter); Diagnostic.Msg(4, "GetTunnelCmd", "Retry after BUSY"); } return(commandResult); }
public override IEECommandResult Execute(IEECommandParameter parameter) { IEECommandResult commandResult = base.Execute(parameter); if (commandResult.Code != EECmdResultCode.Success) { return(commandResult); } if (commandResult.Code == EECmdResultCode.InvalidResult && !(parameter as GetSerialCmdParams).FactoryData) { // Maybe a device that does not support the fallback scenario // (customer sernr is empty, deliver factory sernr) commandResult = base.Execute(new GetSerialCmdParams(false, true)); } return(commandResult); }
/// <summary> /// Sends a command to the device and receives multiple responses. /// </summary> /// <param name="param">The command parameter data.</param> /// <param name="response">@ACK: Payload data (without ACK), @NAK: Error code (1 Byte)</param> /// <returns></returns> public void SendReceiveMulti(IEECommandParameter param, out IList <EE31CmdResponseData> responses) { responses = null; try { SendCmdMultiResponse(CommunicationInterface, param.Cmd, param.CmdData, param.CmdTries ?? CmdTimeoutAutoRetries, param.CmdTimeoutMs ?? CmdTimeoutMSec, param.CmdBusAddr ?? TransmitterBusAddr, true, out responses); } catch (Exception ex) { // i.e. TimeoutException may occur, no problem Diagnostic.Msg(1, string.Format("SendReceiveMulti ({0:X2})", param.Cmd), "Exception: " + ex.Message); } }
public override IEECommandResult Execute(IEECommandParameter parameter) { if (parameter is DiscoveryAckCmdParams diasParams) { try { ProtocolCallbacks.SendReceive(parameter, out byte[] response); } catch (Exception ex) { // i.e. TimeoutException may occur, no problem Diagnostic.Msg(1, "DiscoveryAckCmd", "Exception: " + ex.Message); } // Always return success because transmitters will not answer on this command return(CreateResult(EECmdResultCode.Success, null, parameter)); } else { return(CreateResult(EECmdResultCode.InvalidParamClass, null, null)); } }
public override IEECommandResult Execute(IEECommandParameter parameter) { if (parameter is AuthCmdParams authParams) { // First request challenge authParams.PrepareStep0(); IEECommandResult commandResult = base.Execute(authParams); if (commandResult.Code != EECmdResultCode.Success) { return(commandResult); } // Now authenticate with response authParams.PrepareStep1((commandResult as AuthCmdResult).Challenge); commandResult = base.Execute(authParams); // A password change is requested? if (authParams.ChangePassword) { // Request new challenge authParams.PrepareStep0(); if (commandResult.Code != EECmdResultCode.Success) { return(commandResult); } // Generate response with new secret authParams.PrepareStep1((commandResult as AuthCmdResult).Challenge, true); commandResult = base.Execute(authParams); } return(commandResult); } else { return(CreateResult(EECmdResultCode.InvalidParamClass, null, null)); } }
internal override void InterpretResult(bool reverseByteOrder, IEECmdConverters cmdConv, IEECommandParameter cmdParams) { // Create command specific result from data if (Data.Length < 1) { Code = EECmdResultCode.InvalidResult; } else { if (Data.Length > 1) { ModuleState = Data[1]; } ComPortSettings cps = new ComPortSettings(); // Decode settings byte cpsCoded = Data[0]; // Bits 0..2: Baudrate // Bit 7 = 0: (000 = 4k8, 001 = 9k6, 010 = 19k2, 011 = 38k4, 100 = 57k6, 101 = 76k8, 110 = 115k2) // Bit 7 = 1: (000 = 300, 001 = 600, 010 = 1k2, 011 = 2k4) // Bits 3..4: Parität (01 = None, 10 = Odd, 11 = Even) // Bit 5: Stoppbits (0 = 1 Stoppbit, 1 = 2 Stoppbits) // Bit 6: Datenbits (0 = 8 Datenbits, 1 = 7 Datenbits) if (0x80 == (cpsCoded & 0x80)) { // Bit 7 is 1 switch (cpsCoded & 0x07) { case 0: cps.Baudrate = 300; break; case 1: cps.Baudrate = 600; break; case 2: cps.Baudrate = 1200; break; case 3: cps.Baudrate = 2400; break; default: Code = EECmdResultCode.InvalidResult; break; } } else { // Bit 7 is 0 switch (cpsCoded & 0x07) { case 0: cps.Baudrate = 4800; break; case 1: cps.Baudrate = 9600; break; case 2: cps.Baudrate = 19200; break; case 3: cps.Baudrate = 38400; break; case 4: cps.Baudrate = 57600; break; case 5: cps.Baudrate = 76800; break; case 6: cps.Baudrate = 115200; break; default: Code = EECmdResultCode.InvalidResult; break; } } switch (cpsCoded & 0x18) { case (1 * 8): cps.Parity = System.IO.Ports.Parity.None; break; case (2 * 8): cps.Parity = System.IO.Ports.Parity.Odd; break; case (3 * 8): cps.Parity = System.IO.Ports.Parity.Even; break; default: Code = EECmdResultCode.InvalidResult; break; } switch (cpsCoded & 0x20) { case (0 * 32): cps.Stopbits = System.IO.Ports.StopBits.One; break; case (1 * 32): cps.Stopbits = System.IO.Ports.StopBits.Two; break; default: Code = EECmdResultCode.InvalidResult; break; } switch (cpsCoded & 0x40) { case (0 * 64): cps.Databits = 8; break; case (1 * 64): cps.Databits = 7; break; default: Code = EECmdResultCode.InvalidResult; break; } if (Code == EECmdResultCode.Success) { ComSettings = cps; } } }
internal override void InterpretResult(bool reverseByteOrder, IEECmdConverters cmdConv, IEECommandParameter cmdParams) { // Create command specific result from data if (Data.Length < cmdParams.CmdData.Length + 1) { Code = EECmdResultCode.InvalidResult; } else { // First response byte is 0, data begins at 1 int resultIdx = 1; // Get number of requested values from sent command data int nrValues = cmdParams.CmdData.Length / 2; for (int i = 0; i < nrValues; i++) { // Get MVCode from sent command data MVCode code = cmdConv.MVIndexToMVCode(cmdParams.CmdData[i * 2]); // Get data type (try to get from MVCode if invalid) MVDataType dataType = (MVDataType)Data[resultIdx++]; // Get value for data type double value = double.NaN; switch (dataType) { case MVDataType.Float: if ((resultIdx + 4) <= Data.Length) { value = DataTypeConverter.ByteConverter.ToFloat(Data, resultIdx, reverseByteOrder).ToDoubleWithFloatResolution(); } resultIdx += 4; break; case MVDataType.Double: if ((resultIdx + 8) <= Data.Length) { value = DataTypeConverter.ByteConverter.ToDouble(Data, resultIdx, reverseByteOrder); } resultIdx += 8; break; } MeasValues.Add(new KeyValuePair <MVCode, double>(code, value)); } } }
internal override void InterpretResult(bool reverseByteOrder, IEECmdConverters cmdConv, IEECommandParameter cmdParams) { Challenge = 0; if (Data.Length < 1) { Code = EECmdResultCode.InvalidResult; } else { if (Data[0] == 0x0) { // Authentication request (request challenge) Challenge = DataTypeConverter.ByteConverter.ToUInt32(Data, 1, reverseByteOrder); } else if (Data[0] == 0x1) { // Authentication response ExpirationIdleSec = DataTypeConverter.ByteConverter.ToUInt32(Data, 1, reverseByteOrder); } else if (Data[0] == 0x2) { // Changed password (no additional data) } else { Code = EECmdResultCode.InvalidResult; } } }
internal override void InterpretResult(bool reverseByteOrder, IEECmdConverters cmdConv, IEECommandParameter cmdParams) { if (Data.Length < 2) { Code = EECmdResultCode.InvalidResult; } else { // Create command specific result from data MaxBlockSize = DataTypeConverter.ByteConverter.ToUInt16(Data, 0, reverseByteOrder); } }
internal override void InterpretResult(bool reverseByteOrder, IEECmdConverters cmdConv, IEECommandParameter cmdParams) { // Create command specific result from data if (Data.Length < 19) { Code = EECmdResultCode.InvalidResult; return; } // First two bytes are 0! BattVoltage = DataTypeConverter.ByteConverter.ToFloat(Data, 2, reverseByteOrder); byte hour = Data[6]; byte minute = Data[7]; byte second = Data[8]; byte day = Data[9]; byte month = Data[10]; ushort year = DataTypeConverter.ByteConverter.ToUInt16(Data, 11, reverseByteOrder); int offsetUTC = DataTypeConverter.ByteConverter.ToInt32(Data, 13, reverseByteOrder); DaylightSavingMode = Data[17]; DaylightSavingTime = Data[18] != 0; // Convert data to DateTimeOffset object RTC = new DateTimeOffset(year, month, day, hour, minute, second, new TimeSpan(0, 0, offsetUTC)); }
internal override void InterpretResult(bool reverseByteOrder, IEECmdConverters cmdConv, IEECommandParameter cmdParams) { if (Data.Length < 1) { Code = EECmdResultCode.InvalidResult; } else { var compList = new List <HardwareComponent>(); // Create command specific result from data int dataIdx = 0; int nrDescriptors = Data[dataIdx++]; for (int i = 0; i < nrDescriptors; i++) { int len = Data[dataIdx++]; var descriptor = new HardwareComponent(); descriptor.Component = Data[dataIdx++]; descriptor.Category = Data[dataIdx++]; descriptor.Type = Data[dataIdx++]; // Any attributes? int attribLen = len - 3; if (attribLen > 0) { descriptor.Attributes = new byte[len - 3]; Array.Copy(Data, dataIdx, descriptor.Attributes, 0, descriptor.Attributes.Length); dataIdx += descriptor.Attributes.Length; } else { descriptor.Attributes = new byte[0]; } // Any text? int textLen = Data[dataIdx++]; if (textLen > 0) { descriptor.Text = StringHelper.ExtractStringContent(Data, dataIdx, textLen); dataIdx += textLen; } compList.Add(descriptor); } ComponentList = compList; } }
internal override void InterpretResult(bool reverseByteOrder, IEECmdConverters cmdConv, IEECommandParameter cmdParams) { // ACK received... if (Data.Length < 2) { Code = EECmdResultCode.InvalidResult; return; } DateFormat = Data[1]; }
internal override void InterpretResult(bool reverseByteOrder, IEECmdConverters cmdConv, IEECommandParameter cmdParams) { base.InterpretResult(reverseByteOrder, cmdConv, cmdParams); // Create command specific result from data if (Code == EECmdResultCode.Success) { if (Data.Length < 20) { Code = EECmdResultCode.InvalidResult; return; } // ACK received, response data valid int dataIdx = 2; RelaisConfig = Data[dataIdx++]; MVCode = cmdConv.MVIndexToMVCode(Data[dataIdx++]); MVRangeMin = DataTypeConverter.ByteConverter.ToFloat(Data, dataIdx, reverseByteOrder).ToDoubleWithFloatResolution(); dataIdx += 4; MVRangeMax = DataTypeConverter.ByteConverter.ToFloat(Data, dataIdx, reverseByteOrder).ToDoubleWithFloatResolution(); dataIdx += 4; PulseWidthSec = DataTypeConverter.ByteConverter.ToFloat(Data, dataIdx, reverseByteOrder).ToDoubleWithFloatResolution(); dataIdx += 4; PulseWeight = DataTypeConverter.ByteConverter.ToFloat(Data, dataIdx, reverseByteOrder).ToDoubleWithFloatResolution(); dataIdx += 4; // OPTIONAL: Variant Index (Byte) Variant = OptionalVariant(Data, ref dataIdx); // OPTIONAL: Error Indication ErrorIndicationEnabled = OptionalErrorIndication(ref dataIdx, reverseByteOrder, out double?value); ErrorIndicationValue = value; } }
/// <summary> /// Result classes might overwrite to provide special result handling. /// </summary> internal virtual void InterpretResult(bool reverseByteOrder, IEECmdConverters cmdConv, IEECommandParameter cmdParams) { }
internal override void InterpretResult(bool reverseByteOrder, IEECmdConverters cmdConv, IEECommandParameter cmdParams) { // Create command specific result from data if (Data.Length < 1) { Code = EECmdResultCode.InvalidResult; } else { SettingsSavedNotApplied = Data[0] == 0x1; } }
internal override void InterpretResult(bool reverseByteOrder, IEECmdConverters cmdConv, IEECommandParameter cmdParams) { // ACK received... if (Data.Length < 4) { Code = EECmdResultCode.InvalidResult; return; } DpIdx = Data[1]; Variant = (ValueVariant)Data[2]; Precision = Data[3]; Name = StringHelper.ExtractStringContent(Data, 4, -1); }
internal override void InterpretResult(bool reverseByteOrder, IEECmdConverters cmdConv, IEECommandParameter cmdParams) { // ACK received... if (Data.Length < 6) { Code = EECmdResultCode.InvalidResult; return; } DpIdx = Data[1]; Variant = (ValueVariant)Data[2]; DataType = Data[3]; ScaleFactor = DataTypeConverter.ByteConverter.ToUInt16(Data, 4, reverseByteOrder); }
/// <summary> /// Provide default result function. Might be overwritten in command classes. /// </summary> /// <param name="cmdResultCode"></param> /// <param name="cmdResponse"></param> /// <returns></returns> protected virtual IEECommandResult CreateResult(EECmdResultCode cmdResultCode, byte[] cmdResponse, IEECommandParameter cmdParams) { EECmdResultBase result = new TResultClass() as EECmdResultBase; // Set properties that might be needed to interpret command result result.Code = cmdResultCode; result.Data = cmdResponse; // Commands have the chance to interpret the result data (in case of {ACK}/Success) if (cmdResultCode == EECmdResultCode.Success) { result.InterpretResult(ProtocolCallbacks.LookupOrCreateCmdSpecialTreatment(cmdParams.Cmd).ReverseByteOrder.Value, ProtocolConverters, cmdParams); } return(result); }
internal override void InterpretResult(bool reverseByteOrder, IEECmdConverters cmdConv, IEECommandParameter cmdParams) { // Create command specific result from data if (Data.Length < 9) { Code = EECmdResultCode.InvalidResult; return; } Voltage = Data[0] == 0x1; RangeMin = DataTypeConverter.ByteConverter.ToFloat(Data, 1, reverseByteOrder); RangeMax = DataTypeConverter.ByteConverter.ToFloat(Data, 5, reverseByteOrder); }
internal override void InterpretResult(bool reverseByteOrder, IEECmdConverters cmdConv, IEECommandParameter cmdParams) { // ACK received... if (Data.Length < 1) { Code = EECmdResultCode.InvalidResult; return; } Unit = StringHelper.ExtractStringContent(Data, 1, -1); }
internal override void InterpretResult(bool reverseByteOrder, IEECmdConverters cmdConv, IEECommandParameter cmdParams) { if (Data.Length < 4) { Code = EECmdResultCode.InvalidResult; } else { // Create command specific result from data SetTo96008N1 = Data[0] != 0; KeepUsingBusAddr = Data[1] != 0; WaitForMs = DataTypeConverter.ByteConverter.ToUInt16(Data, 2, reverseByteOrder); } }
internal override void InterpretResult(bool reverseByteOrder, IEECmdConverters cmdConv, IEECommandParameter cmdParams) { // Create command specific result from data if (Data.Length < 1) { Code = EECmdResultCode.InvalidResult; } else { // First byte is string length int strLen = Data[0]; Text = StringHelper.ExtractStringContent(Data, 1, strLen); } }
internal override void InterpretResult(bool reverseByteOrder, IEECmdConverters cmdConv, IEECommandParameter cmdParams) { // ACK received... if (Data.Length < 7) { Code = EECmdResultCode.InvalidResult; return; } MACAddr = new byte[6]; Array.Copy(Data, 1, MACAddr, 0, 6); }
internal override void InterpretResult(bool reverseByteOrder, IEECmdConverters cmdConv, IEECommandParameter cmdParams) { if (Data.Length < 2) { Code = EECmdResultCode.InvalidResult; } else { // Create command specific result from data var hwCodes = new List <ushort>(); var major = new List <byte>(); var minor = new List <byte>(); var rev = new List <byte>(); for (int i = 0; i < Data.Length; i++) { hwCodes.Add(DataTypeConverter.ByteConverter.ToUInt16(Data, i, reverseByteOrder)); i += 2; if (i + 2 < Data.Length) { // Optional information for this HW code major.Add(Data[i]); minor.Add(Data[i + 1]); rev.Add(Data[i + 2]); } else { break; } } HWCodes = hwCodes; MajorVersions = major; MinorVersions = minor; Revisions = rev; } }
internal override void InterpretResult(bool reverseByteOrder, IEECmdConverters cmdConv, IEECommandParameter cmdParams) { // ACK received, response data valid if (Data.Length >= 3) { // 0x00 fixed (Byte), then Waiting time [1/100 msec] (WORD) UInt16 wait = DataTypeConverter.ByteConverter.ToUInt16(Data, 1, reverseByteOrder); if (0 != wait) { System.Threading.Thread.Sleep(wait * 100); } } }