Exemplo n.º 1
0
        /// <summary>
        /// Create instance of EE31 protocol class.
        /// </summary>
        /// <param name="communicationInterface">The communication layer</param>
        /// <returns></returns>
        public static IEECommProtocol GetEE31Protocol(IEECommDevice communicationInterface)
        {
            if (communicationInterface == null)
            {
                throw new ArgumentNullException("communicationInterface");
            }

            // Only create one protocol instance per interface
            lock (_protectInstances)
            {
                IEECommProtocol protItf = _protInstances.Find(p =>
                                                              (p.CommunicationInterface.InterfaceType == communicationInterface.InterfaceType &&
                                                               p.CommunicationInterface.InterfaceId == communicationInterface.InterfaceId));

                if (protItf != null)
                {
                    return(protItf);
                }

                var prot = new EE31Protocol(communicationInterface);
                _protInstances.Add(prot);

                return(prot);
            }
        }
Exemplo n.º 2
0
 private void FireDeviceFound(IEECommDevice device)
 {
     if (DeviceFound != null)
     {
         if (DeviceFound.Target is ISynchronizeInvoke sync && sync.InvokeRequired)
         {
             sync.Invoke(DeviceFound, new object[] { this, device });
         }
         else
         {
             DeviceFound(this, device);
         }
     }
Exemplo n.º 3
0
        /// <summary>
        /// Constructor. The protocol must have an underlying communication layer.
        /// </summary>
        /// <param name="communicationInterface">The communication layer</param>
        internal EE31Protocol(IEECommDevice communicationInterface)
        {
            CommunicationInterface = communicationInterface;

            // Default protocol configuration
            CmdTimeoutAutoRetries = 1;
            CmdTimeoutMSec        = 2000;
            IncludeNetworkAddress = true;
            MaxPayload            = 255;
            SIUS = SIUSUnit.SI;
            CfgMVCodeTranslations       = null;
            CmdSpecialTreatments        = new Dictionary <byte, CmdSpecialTreatment>();
            UseMVCodeInsteadOfEE31Index = true;
        }
Exemplo n.º 4
0
        public IEECommDevice TryGetDevice(IScanConfiguration config, ushort busAddr)
        {
            if (config is ScanConfigurationUART scanConfigurationUART)
            {
                if (busAddr == 0)
                {
                    throw new ArgumentException("Device bus address must not be 0", "busAddr");
                }

                IEECommDevice device = null;

                // Search in already existing devices before starting a new scan
                lock (_foundDevices)
                {
                    device = _foundDevices.FirstOrDefault(x => x.InterfaceType == InterfaceType.UART && x.InterfaceId == busAddr.ToString());
                }

                if (device != null)
                {
                    // Try to revitalize device
                    IEECommProtocol  protEE31 = EECommProtocolFactory.GetEE31Protocol(device);
                    IEECommandResult result   = null;

                    // Force silence
                    Thread.Sleep(50);

                    // For non-EE31 devices (Modbus, etc.): Send protocol switch command to make them speak EE31 (again)
                    ushort discoveryId = DiscoveryCmdParams.BuildNewDiscoveryId();
                    try
                    {
                        result = protEE31.ExecuteCommand(EE31Command.Discovery, new DiscoveryCmdParams(discoveryId, busAddr, 0, 100));
                    }
                    catch { }

                    try
                    {
                        result = protEE31.ExecuteCommand(EE31Command.Discovery, new DiscoveryCmdParams(discoveryId, busAddr, 0, 50));
                    }
                    catch { }

                    if (result != null && result.Code == EECmdResultCode.Success)
                    {
                        return(device);
                    }
                }

                return(device);
            }
            else if (config is ScanConfigurationEmulation scanConfigurationEmulation)
            {
                IEECommDevice emulatedDevice = new EECommDeviceEmulation(0, scanConfigurationEmulation.EmulationDevicesSettings.ElementAt(0));
                var           existing       = _foundDevices.FirstOrDefault(x => x.InterfaceType == InterfaceType.Emulation && x.InterfaceId == emulatedDevice.InterfaceId);
                if (existing == null)
                {
                    existing = emulatedDevice;
                }

                return(existing);
            }

            throw new NotImplementedException("Currently it is only possible to get UART or emulated devices.");
        }
Exemplo n.º 5
0
        /// <summary>
        /// Sends a command to the device, expects multiple responses (i.e. broadcast message).
        /// </summary>
        /// <param name="commInterface">The communication interface</param>
        /// <param name="cmd">The command.</param>
        /// <param name="param">The command parameters.</param>
        /// <param name="cmdTimeoutRetries">Number of automatic retries in case of timeout.</param>
        /// <param name="cmdTimeoutMs">Command timeout in milliseconds.</param>
        /// <param name="busAddr">The target bus addr.</param>
        /// <param name="multiResponsesExpected">The multi responses expected.</param>
        /// <param name="responses">The responses.</param>
        /// <param name="rawDataToTx">Raw data bytes to transmit immediately after sending the command frame.</param>
        private void SendCmdMultiResponse(IEECommDevice commInterface, byte cmd, byte[] param, uint cmdTimeoutRetries, uint cmdTimeoutMs,
                                          int busAddr, bool multiResponsesExpected, out IList <EE31CmdResponseData> responses, byte[] rawDataToTx = null)
        {
            lock (__lock_SendCmdMultiResponse)
            {
                responses = new List <EE31CmdResponseData>();

                commInterface.EnsureConnection();

                IList <byte> txBuffer = new List <byte>();

                if (IncludeNetworkAddress || 0 != busAddr)
                {
                    // 16 bit network address
                    UInt16 addr      = (UInt16)busAddr;
                    byte[] flatBytes = BitConverter.GetBytes(addr);
                    if (2 != flatBytes.Length)
                    {
                        throw new ArgumentException("UInt16 must have 2 bytes!");
                    }
                    txBuffer.Add(flatBytes[0]);
                    txBuffer.Add(flatBytes[1]);
                }

                // Command byte
                txBuffer.Add(cmd);

                // Byte count of parameters
                if (null != param)
                {
                    txBuffer.Add((byte)(param.Length));
                }
                else
                {
                    txBuffer.Add(0);
                }

                if (null != param)
                {
                    // Parameter bytes
                    foreach (byte data in param)
                    {
                        txBuffer.Add(data);
                    }
                }

                // Checksum: (BusAddr + Cmd + Param Length + Data 1..Data n) MOD 0x100
                byte checksum = 0;
                foreach (byte by in txBuffer)
                {
                    checksum += by;
                }
                txBuffer.Add(checksum);

                // --- Send command ---
                string bufAsHexChars;
                while (true)
                {
                    while (DateTime.UtcNow.Subtract(timestampLastTx).TotalMilliseconds < 50)
                    {
                        // Force silence
                        Diagnostic.Msg(2, "SendCmdMultiResponse", "Forcing silence before sending cmd...");
                        Thread.Sleep(20);
                    }
                    commInterface.WriteBytes(txBuffer.ToArray(), 0, txBuffer.Count);

                    if (null != rawDataToTx && 0 != rawDataToTx.Length)
                    {
                        // Send raw data bytes to transmit immediately after sending the command frame
                        commInterface.WriteBytes(rawDataToTx, 0, rawDataToTx.Length);
                    }

                    // --- Ensure tx buffer is empty (all sent) ---
                    DateTime timeout = DateTime.UtcNow.AddMilliseconds(1000);
                    while (DateTime.UtcNow <= timeout && commInterface.BytesToWrite > 0)
                    {
                        Thread.Sleep(5);
                    }
                    timestampLastTx = DateTime.UtcNow;

                    // -------------------- DIAGNOSTICS --------------------
                    if (Diagnostic.OutputLevel > 2)
                    {
                        bufAsHexChars = "";
                        foreach (byte by in txBuffer)
                        {
                            bufAsHexChars += string.Format("{0:X2} ", by);
                        }

                        Diagnostic.Msg(3, "SendCmdMultiResponse",
                                       "Cmd " + string.Format("{0:X2}", cmd) + " frame sent: " + bufAsHexChars);
                    }
                    // -------------------- DIAGNOSTICS --------------------

                    byte[]       response;
                    int          rxBusAddr;
                    byte[]       foundFrame;
                    Queue <byte> rxQueue = new Queue <byte>();
                    // Timeout in x msecs
                    timeout = DateTime.UtcNow.AddMilliseconds(cmdTimeoutMs);
                    DateTime lastRxByte = DateTime.UtcNow;
                    bool     checkOnceAfterByteWasReceivedAndSilencePassed = false;
                    while (DateTime.UtcNow <= timeout)
                    {
                        try
                        {
                            if (commInterface.BytesToRead > 0 ||
                                ((DateTime.UtcNow - lastRxByte).TotalMilliseconds > 250 && checkOnceAfterByteWasReceivedAndSilencePassed))
                            {
                                bool useSlidingWindow = false;

                                if (commInterface.BytesToRead > 0)
                                {
                                    byte rxByte = commInterface.ReadByte();
                                    rxQueue.Enqueue(rxByte);

                                    lastRxByte = DateTime.UtcNow;
                                    checkOnceAfterByteWasReceivedAndSilencePassed = true;

                                    // -------------------- DIAGNOSTICS --------------------
                                    if (Diagnostic.OutputLevel > 7)
                                    {
                                        bufAsHexChars = "";
                                        foreach (byte by in rxQueue)
                                        {
                                            bufAsHexChars += string.Format("{0:X2} ", by);
                                        }

                                        Diagnostic.Msg(8, "SendCmdMultiResponse",
                                                       "RxByte: " + string.Format("{0:X2}", rxByte) +
                                                       " => " + bufAsHexChars);
                                    }
                                    // -------------------- DIAGNOSTICS --------------------
                                }
                                else
                                {
                                    // This is the one pass after some period of silence after the
                                    // last received byte
                                    checkOnceAfterByteWasReceivedAndSilencePassed = false;

                                    Diagnostic.Msg(1, "SendCmdMultiResponse", "SendCmdMultiResponse silence passed, try to find packet within possible garbage...");

                                    // Try to find packet within rxQueue using sliding window
                                    useSlidingWindow = true;
                                }

                                EE31Result result = TryDecodeEE31Frame(rxQueue.ToArray(), new byte[] { cmd }, true, useSlidingWindow, out byte rxCmd, out response, out rxBusAddr, out foundFrame);
                                if (EE31Result.Invalid != result)
                                {
                                    // Valid response, add to result/responses/rxBusAddrs lists
                                    EE31CmdResponseData responseData = new EE31CmdResponseData()
                                    {
                                        Result = result, Response = response, RxBusAddr = rxBusAddr, FoundFrame = foundFrame
                                    };
                                    responses.Add(responseData);
                                    rxQueue.Clear();

                                    if (!multiResponsesExpected)
                                    {
                                        // finished!
                                        Diagnostic.Msg(2, "SendCmdMultiResponse", "TryDecodeEE31Frame was successful, finished!");
                                        return;
                                    }

                                    Diagnostic.Msg(2, "SendCmdMultiResponse", "TryDecodeEE31Frame was successful, waiting for more frames...");
                                }
                                // Receive next byte (if any)
                                continue;
                            }
                        }
                        catch (Exception ex)
                        {
                            Diagnostic.Msg(1, "SendCmdMultiResponse", "Exception: " + ex.Message);
                        }

                        Thread.Sleep(5);
                    }

                    // Timeout period has passed; dump bytes in rxBuffer so far...
                    bufAsHexChars = "";
                    foreach (byte by in rxQueue)
                    {
                        bufAsHexChars += string.Format("{0:X2} ", by);
                    }
                    Diagnostic.Msg(1, "SendCmdMultiResponse", "ReceiveCmd Timeout, rxBuffer contents: " + bufAsHexChars);
                    // ... and send command again if nothing received and any cmdTimeoutRetries left
                    if (responses.Count > 0 || cmdTimeoutRetries <= 0)
                    {
                        break;
                    }
                    cmdTimeoutRetries--;
                }

                if (0 == responses.Count)
                {
                    if (0 == cmdTimeoutMs)
                    {
                        // No responses expected, so it is ok to have none...
                        Diagnostic.Msg(2, "SendCmdMultiResponse", "No responses expected, leaving immediately...");

                        return;
                    }

                    // There should have been responses, throw Timeout exception...
                    Diagnostic.Msg(2, "SendCmdMultiResponse", string.Format("No responses for cmd 0x{0:X2} received, throwing TimeoutException!", cmd));

                    throw new TimeoutException(
                              string.Format("EE31 protocol timeout: No response for cmd 0x{0:X2} received!", cmd));
                }

                Diagnostic.Msg(2, "SendCmdMultiResponse", string.Format("{1} responses for cmd 0x{0:X2} successfully received.", cmd, responses.Count));
            }
        }