private void NrDictAdd(byte deviceAddr, bool enableLogging)
        {
            int retries;

            if (NrDict.TryGetValue(deviceAddr, out retries))
            {
                NrDict.Remove(deviceAddr);
                retries++;
                if (retries <= ParRetryNr)
                {
                    if (enableLogging)
                    {
                        EdiabasProtected.LogFormat(EdiabasNet.EdLogLevel.Ifh, "NR({0:X02}) count={1}", deviceAddr, retries);
                    }
                    NrDict.Add(deviceAddr, retries);
                }
                else
                {
                    if (enableLogging)
                    {
                        EdiabasProtected.LogFormat(EdiabasNet.EdLogLevel.Ifh, "*** NR({0:X02}) exceeded", deviceAddr);
                    }
                }
            }
            else
            {
                if (enableLogging)
                {
                    EdiabasProtected.LogFormat(EdiabasNet.EdLogLevel.Ifh, "NR({0:X02}) added", deviceAddr);
                }
                NrDict.Add(deviceAddr, 0);
            }
        }
        protected EdiabasNet.ErrorCodes ObdTrans(byte[] sendData, int sendDataLength, ref byte[] receiveData, out int receiveLength)
        {
            receiveLength = 0;
            if (TcpDiagStream == null)
            {
                return(EdiabasNet.ErrorCodes.EDIABAS_IFH_0019);
            }

            EdiabasNet.ErrorCodes errorCode = EdiabasNet.ErrorCodes.EDIABAS_ERR_NONE;
            UInt32 retries   = CommRepeatsProtected;
            string retryComm = EdiabasProtected.GetConfigProperty("RetryComm");

            if (retryComm != null)
            {
                if (EdiabasNet.StringToValue(retryComm) == 0)
                {
                    retries = 0;
                }
            }
            for (int i = 0; i < retries + 1; i++)
            {
                errorCode = ParTransmitFunc(sendData, sendDataLength, ref receiveData, out receiveLength);
                if (errorCode == EdiabasNet.ErrorCodes.EDIABAS_ERR_NONE)
                {
                    return(errorCode);
                }
                if (errorCode == EdiabasNet.ErrorCodes.EDIABAS_IFH_0003)
                {   // interface error
                    break;
                }
            }
            return(errorCode);
        }
 public override bool ReceiveFrequent(out byte[] receiveData)
 {
     receiveData = null;
     if (CommParameterProtected == null)
     {
         EdiabasProtected.SetError(EdiabasNet.ErrorCodes.EDIABAS_IFH_0006);
         return(false);
     }
     receiveData = ByteArray0;
     return(true);
 }
 private void NrDictRemove(byte deviceAddr, bool enableLogging)
 {
     if (NrDict.ContainsKey(deviceAddr))
     {
         if (enableLogging)
         {
             EdiabasProtected.LogFormat(EdiabasNet.EdLogLevel.Ifh, "NR({0:X02}) removed", deviceAddr);
         }
         NrDict.Remove(deviceAddr);
     }
 }
        public override bool InterfaceDisconnect()
        {
            EdiabasProtected?.LogString(EdiabasNet.EdLogLevel.Ifh, "Disconnect");
            bool result = true;

            try
            {
                if (TcpDiagStream != null)
                {
                    TcpDiagStream.Close();
                    TcpDiagStream = null;
                }
            }
            catch (Exception)
            {
                result = false;
            }

            try
            {
                if (TcpDiagClient != null)
                {
                    TcpDiagClient.Close();
                    TcpDiagClient = null;
                }
            }
            catch (Exception)
            {
                result = false;
            }

            if (!TcpControlDisconnect())
            {
                result = false;
            }

            try
            {
                if (UdpSocket != null)
                {
                    UdpSocket.Close();
                    UdpSocket = null;
                }
            }
            catch (Exception)
            {
                result = false;
            }
            TcpHostIp         = null;
            ReconnectRequired = false;
            return(result);
        }
        public override bool TransmitData(byte[] sendData, out byte[] receiveData)
        {
            receiveData = null;
            if (CommParameterProtected == null)
            {
                EdiabasProtected.SetError(EdiabasNet.ErrorCodes.EDIABAS_IFH_0006);
                return(false);
            }
            EdiabasNet.ErrorCodes cachedErrorCode;
            byte[] cachedResponse;
            if (ReadCachedTransmission(sendData, out cachedResponse, out cachedErrorCode))
            {
                if (cachedErrorCode != EdiabasNet.ErrorCodes.EDIABAS_ERR_NONE)
                {
                    EdiabasProtected.SetError(cachedErrorCode);
                    return(false);
                }
                receiveData = cachedResponse;
                return(true);
            }
            if (ReconnectRequired)
            {
                InterfaceDisconnect();
                if (!InterfaceConnect())
                {
                    ReconnectRequired = true;
                    EdiabasProtected.SetError(EdiabasNet.ErrorCodes.EDIABAS_IFH_0003);
                    return(false);
                }
            }
            int recLength;

            EdiabasNet.ErrorCodes errorCode = ObdTrans(sendData, sendData.Length, ref RecBuffer, out recLength);
            if (errorCode != EdiabasNet.ErrorCodes.EDIABAS_ERR_NONE)
            {
                if (errorCode == EdiabasNet.ErrorCodes.EDIABAS_IFH_0003)
                {
                    ReconnectRequired = true;
                }
                CacheTransmission(sendData, null, errorCode);
                EdiabasProtected.SetError(errorCode);
                return(false);
            }
            receiveData = new byte[recLength];
            Array.Copy(RecBuffer, receiveData, recLength);
            CacheTransmission(sendData, receiveData, EdiabasNet.ErrorCodes.EDIABAS_ERR_NONE);
            return(true);
        }
        public override bool InterfaceConnect()
        {
            if (TcpDiagClient != null)
            {
                return(true);
            }
            try
            {
                EdiabasProtected.LogString(EdiabasNet.EdLogLevel.Ifh, "Connect");
                TcpHostIp = null;
                if (RemoteHostProtected.StartsWith(AutoIp, StringComparison.OrdinalIgnoreCase))
                {
                    List <IPAddress> detectedVehicles = DetectedVehicles(RemoteHostProtected, 1);
                    if ((detectedVehicles == null) || (detectedVehicles.Count < 1))
                    {
                        return(false);
                    }
                    TcpHostIp = detectedVehicles[0];
                    UdpSocket.Close();
                    EdiabasProtected.LogString(EdiabasNet.EdLogLevel.Ifh, string.Format("Received: IP={0}", TcpHostIp));
                }
                else
                {
                    TcpHostIp = IPAddress.Parse(RemoteHostProtected);
                }

                TcpDiagClient      = new TcpClientWithTimeout(TcpHostIp, DiagnosticPort, ConnectTimeout).Connect();
                TcpDiagStream      = TcpDiagClient.GetStream();
                TcpDiagRecLen      = 0;
                LastTcpDiagRecTime = DateTime.MinValue.Ticks;
                TcpDiagRecQueue.Clear();
                StartReadTcpDiag(6);
                EdiabasProtected.LogString(EdiabasNet.EdLogLevel.Ifh, "Connected");
                ReconnectRequired = false;
            }
            catch (Exception ex)
            {
                EdiabasProtected.LogString(EdiabasNet.EdLogLevel.Ifh, "InterfaceConnect exception: " + EdiabasNet.GetExceptionText(ex));
                InterfaceDisconnect();
                return(false);
            }
            return(true);
        }
        protected bool SendData(byte[] sendData, int length, bool enableLogging)
        {
            if (TcpDiagStream == null)
            {
                return(false);
            }
            try
            {
                lock (TcpDiagStreamRecLock)
                {
                    TcpDiagStreamRecEvent.Reset();
                    TcpDiagRecQueue.Clear();
                }

                byte targetAddr = sendData[1];
                byte sourceAddr = sendData[2];
                if (sourceAddr == 0xF1)
                {
                    sourceAddr = (byte)TesterAddress;
                }
                int dataOffset = 3;
                int dataLength = sendData[0] & 0x3F;
                if (dataLength == 0)
                {   // with length byte
                    if (sendData[3] == 0)
                    {
                        dataLength = (sendData[4] << 8) | sendData[5];
                        dataOffset = 6;
                    }
                    else
                    {
                        dataLength = sendData[3];
                        dataOffset = 4;
                    }
                }
                int payloadLength = dataLength + 2;
                DataBuffer[0] = (byte)((payloadLength >> 24) & 0xFF);
                DataBuffer[1] = (byte)((payloadLength >> 16) & 0xFF);
                DataBuffer[2] = (byte)((payloadLength >> 8) & 0xFF);
                DataBuffer[3] = (byte)(payloadLength & 0xFF);
                DataBuffer[4] = 0x00;   // Payoad type: Diag message
                DataBuffer[5] = 0x01;
                DataBuffer[6] = sourceAddr;
                DataBuffer[7] = targetAddr;
                Array.Copy(sendData, dataOffset, DataBuffer, 8, dataLength);
                int sendLength = dataLength + 8;
                lock (TcpDiagStreamSendLock)
                {
                    TcpDiagStream.Write(DataBuffer, 0, sendLength);
                }

                // wait for ack
                int recLen = ReceiveTelegram(AckBuffer, 5000);
                if (recLen < 0)
                {
                    if (enableLogging)
                    {
                        EdiabasProtected.LogString(EdiabasNet.EdLogLevel.Ifh, "*** No ack received");
                    }
                    return(false);
                }
                if ((recLen < 6) || (recLen > sendLength) || (AckBuffer[5] != 0x02))
                {
                    if (enableLogging)
                    {
                        EdiabasProtected.LogData(EdiabasNet.EdLogLevel.Ifh, AckBuffer, 0, recLen, "*** Ack frame invalid");
                    }
                    return(false);
                }
                AckBuffer[4] = DataBuffer[4];
                AckBuffer[5] = DataBuffer[5];
                for (int i = 4; i < recLen; i++)
                {
                    if (AckBuffer[i] != DataBuffer[i])
                    {
                        if (enableLogging)
                        {
                            EdiabasProtected.LogData(EdiabasNet.EdLogLevel.Ifh, AckBuffer, 0, recLen, "*** Ack data invalid");
                        }
                        return(false);
                    }
                }
            }
            catch (Exception)
            {
                return(false);
            }
            return(true);
        }
        public List <IPAddress> DetectedVehicles(string remoteHostConfig, int maxVehicles = -1)
        {
            if (!remoteHostConfig.StartsWith(AutoIp, StringComparison.OrdinalIgnoreCase))
            {
                return(null);
            }
            // ReSharper disable once UseObjectOrCollectionInitializer
            UdpSocket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
#if !WindowsCE
            UdpSocket.EnableBroadcast = true;
#endif
            IPEndPoint ipUdp = new IPEndPoint(IPAddress.Any, 0);
            UdpSocket.Bind(ipUdp);
            lock (UdpRecListLock)
            {
                UdpRecIpListList = new List <IPAddress>();
            }
            UdpMaxResponses = maxVehicles;
            StartUdpListen();

            bool broadcastSend = false;
#if !WindowsCE
            string configData = remoteHostConfig.Remove(0, AutoIp.Length);
            if ((configData.Length > 0) && (configData[0] == ':'))
            {
                string adapterName = configData.StartsWith(":all", StringComparison.OrdinalIgnoreCase) ? string.Empty : configData.Remove(0, 1);

                System.Net.NetworkInformation.NetworkInterface[] adapters = System.Net.NetworkInformation.NetworkInterface.GetAllNetworkInterfaces();
                foreach (System.Net.NetworkInformation.NetworkInterface adapter in adapters)
                {
                    if (adapter.OperationalStatus == System.Net.NetworkInformation.OperationalStatus.Up)
                    {
                        System.Net.NetworkInformation.IPInterfaceProperties properties = adapter.GetIPProperties();
                        if (properties.UnicastAddresses != null)
                        {
                            foreach (System.Net.NetworkInformation.UnicastIPAddressInformation ipAddressInfo in properties.UnicastAddresses)
                            {
                                if (ipAddressInfo.Address.AddressFamily == AddressFamily.InterNetwork)
                                {
                                    if ((adapterName.Length == 0) || (adapter.Name.StartsWith(adapterName, StringComparison.OrdinalIgnoreCase)))
                                    {
                                        try
                                        {
                                            byte[] ipBytes   = ipAddressInfo.Address.GetAddressBytes();
                                            byte[] maskBytes = ipAddressInfo.IPv4Mask.GetAddressBytes();
                                            for (int i = 0; i < ipBytes.Length; i++)
                                            {
                                                ipBytes[i] |= (byte)(~maskBytes[i]);
                                            }
                                            IPAddress broadcastAddress = new IPAddress(ipBytes);
                                            EdiabasProtected?.LogString(EdiabasNet.EdLogLevel.Ifh, string.Format("Sending: '{0}': Ip={1} Mask={2} Broadcast={3}",
                                                                                                                 adapter.Name, ipAddressInfo.Address, ipAddressInfo.IPv4Mask, broadcastAddress));
                                            IPEndPoint ipUdpIdent = new IPEndPoint(broadcastAddress, ControlPort);
                                            UdpSocket.SendTo(UdpIdentReq, ipUdpIdent);
                                            broadcastSend = true;
                                        }
                                        catch (Exception)
                                        {
                                            EdiabasProtected?.LogString(EdiabasNet.EdLogLevel.Ifh, "Broadcast failed");
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            }
            else
#endif
            {
                try
                {
#if Android || WindowsCE
                    IPEndPoint ipUdpIdent = new IPEndPoint(IPAddress.Broadcast, ControlPort);
#else
                    IPEndPoint ipUdpIdent = new IPEndPoint(IPAddress.Parse("169.254.255.255"), ControlPort);
#endif
                    EdiabasProtected?.LogString(EdiabasNet.EdLogLevel.Ifh, string.Format("Sending to: {0}", ipUdpIdent.Address));
                    UdpSocket.SendTo(UdpIdentReq, ipUdpIdent);
                    broadcastSend = true;
                }
                catch (Exception)
                {
                    EdiabasProtected?.LogString(EdiabasNet.EdLogLevel.Ifh, "Broadcast failed");
                }
            }
            if (!broadcastSend)
            {
                EdiabasProtected?.LogString(EdiabasNet.EdLogLevel.Ifh, "No broadcast send");
                InterfaceDisconnect();
                return(null);
            }

            UdpEvent.WaitOne(1000, false);
            if (UdpRecIpListList.Count == 0)
            {
                EdiabasProtected?.LogString(EdiabasNet.EdLogLevel.Ifh, "No answer received");
                InterfaceDisconnect();
                return(null);
            }
            UdpSocket.Close();
            List <IPAddress> ipList;
            lock (UdpRecListLock)
            {
                ipList           = UdpRecIpListList;
                UdpRecIpListList = null;
            }
            return(ipList);
        }
        private EdiabasNet.ErrorCodes TransKwp2000(byte[] sendData, int sendDataLength, ref byte[] receiveData, out int receiveLength, bool enableLogging)
        {
            receiveLength = 0;

            if (sendDataLength > 0)
            {
                NrDict.Clear();
                int sendLength = TelLengthBmwFast(sendData);
                if (enableLogging)
                {
                    EdiabasProtected.LogData(EdiabasNet.EdLogLevel.Ifh, sendData, 0, sendLength, "Send");
                }

                if (!SendData(sendData, sendLength, enableLogging))
                {
                    if (enableLogging)
                    {
                        EdiabasProtected.LogString(EdiabasNet.EdLogLevel.Ifh, "*** Sending failed");
                    }
                    return(EdiabasNet.ErrorCodes.EDIABAS_IFH_0003);
                }
            }

            for (; ;)
            {
                int timeout = (NrDict.Count > 0) ? ParTimeoutNr : ParTimeoutStd;
                //if (enableLogging) EdiabasProtected.LogFormat(EdiabasNet.EdLogLevel.Ifh, "Timeout: {0}", timeout);
                if (!ReceiveData(receiveData, timeout))
                {
                    if (enableLogging)
                    {
                        EdiabasProtected.LogString(EdiabasNet.EdLogLevel.Ifh, "*** No data received");
                    }
                    return(EdiabasNet.ErrorCodes.EDIABAS_IFH_0009);
                }

                int recLength = TelLengthBmwFast(receiveData);
                EdiabasProtected.LogData(EdiabasNet.EdLogLevel.Ifh, receiveData, 0, recLength + 1, "Resp");

                int dataLen   = receiveData[0] & 0x3F;
                int dataStart = 3;
                if (dataLen == 0)
                {   // with length byte
                    if (receiveData[3] == 0)
                    {
                        dataLen    = (receiveData[4] << 8) | receiveData[5];
                        dataStart += 3;
                    }
                    else
                    {
                        dataLen = receiveData[3];
                        dataStart++;
                    }
                }
                if ((dataLen == 3) && (receiveData[dataStart] == 0x7F) && (receiveData[dataStart + 2] == 0x78))
                {   // negative response 0x78
                    NrDictAdd(receiveData[2], enableLogging);
                }
                else
                {
                    NrDictRemove(receiveData[2], enableLogging);
                    break;
                }
                if (NrDict.Count == 0)
                {
                    break;
                }
            }

            receiveLength = TelLengthBmwFast(receiveData) + 1;
            return(EdiabasNet.ErrorCodes.EDIABAS_ERR_NONE);
        }