/// <summary> /// Parse data for specified pid /// </summary> /// <param name="odbPid"></param> /// <param name="data"></param> /// <returns></returns> private Double parseDataForSpecifiedPid(OdbPid odbPid, OdbData data) { int A = -1, B = -1, C = -1, D = -1; int length = data.Data.Length; if (length > 4 || length == 0) { throw new OdbException(OdbError.IncorrectDataLength); } if (length >= 4) { D = Convert.ToInt32(data.Data[3], 16); } if (length >= 3) { C = Convert.ToInt32(data.Data[2], 16); } if (length >= 2) { B = Convert.ToInt32(data.Data[1], 16); } if (length >= 1) { A = Convert.ToInt32(data.Data[0], 16); } return(odbPid.Compute(A, B, C, D)); }
/// <summary> /// Receive data from device /// </summary> /// <param name="what"></param> /// <param name="start"></param> /// <returns></returns> private async Task <OdbResponse> receiveDataFromDevice(OdbPid what, DateTime start) { //await for response await Task.Delay(this.getReponseByPid(what)); //create response OdbResponse odbResponse = new OdbResponse(); odbResponse.Pid = what; try { //reader uint loaded = await reader.LoadAsync(BUFFER_STEP); String response = reader.ReadString(reader.UnconsumedBufferLength); while (loaded == BUFFER_STEP) { loaded = await reader.LoadAsync(BUFFER_STEP); response += reader.ReadString(reader.UnconsumedBufferLength); } odbResponse.Response = this.clearResponse(response, what); odbResponse.IsValid = this.isValidResponse(response, what); } catch { odbResponse.Response = ""; odbResponse.IsValid = false; } odbResponse.Time = DateTime.Now.Subtract(start); return(odbResponse); }
/// <summary> /// Get data for pid /// </summary> /// <param name="pid"></param> /// <returns></returns> public OdbQueryResponse RequestFor(OdbPid pid) { //add new query to databaze if (!queryResponses.ContainsKey(pid)) { OdbQuery newQuery = new OdbQuery(); newQuery.Pid = pid; newQuery.Status = this.checkSupported(newQuery); queryResponses.Add(pid, newQuery); reporter.ReportNewQuery(newQuery); } //read data from query OdbQuery query = queryResponses[pid]; OdbQueryResponse response = new OdbQueryResponse(); if (query.Status == QueryStatus.Complete) { response.Data = query.Data; response.Unit = query.Pid.Units; response.MinValue = query.Pid.MinValue; response.MaxValue = query.Pid.MaxValue; return(response); } return(null); }
/// <summary> /// Get response time what for pid /// </summary> /// <param name="what"></param> /// <returns></returns> private int getReponseByPid(OdbPid what) { if (what.IsElmCommand) { return(500); } return(250); }
/// <summary> /// Clear line /// </summary> /// <param name="what"></param> /// <param name="line"></param> /// <returns></returns> private string clearLine(OdbPid what, String line) { line = line.Replace("\n", " "); line = line.Replace(">", ""); line = line.Replace(what.Pid, ""); line = line.Trim(); return(line); }
/// <summary> /// Get data for pid /// </summary> /// <param name="pid"></param> /// <returns></returns> public void UnregisterQuery(OdbPid pid) { //remove query from databaze if (queryResponses.ContainsKey(pid)) { queryResponses.Remove(pid); reporter.ReportDeleteQuery(pid); } }
/// <summary> /// Send message and check response /// </summary> /// <param name="what"></param> /// <returns></returns> public async Task <OdbResponse> SendAndCheck(OdbPid what) { OdbResponse response = await this.Send(what); if (!response.Response.Contains(what.ExpectedResponse)) { throw new OdbException(OdbError.WrongResponseFromDevice); } return(response); }
/// <summary> /// Get supp /// </summary> /// <param name="what"></param> /// <returns></returns> private async Task registerSupportedPid(OdbPid what) { OdbResponse response = await this.socket.SendAndCheck(what); OdbData data = this.socket.ResolveData(response, what); if (data != null) { this.decodeSupportedPidsAndRegisterIt(what, data); } }
/// <summary> /// Clear response message /// </summary> /// <param name="response"></param> /// <returns></returns> private string clearResponse(string response, OdbPid what) { response = response.Replace("\r", " "); String[] lines = response.Split('\n'); for (int i = lines.Length - 1; i >= 0; i--) { String line = lines[i]; line = this.clearLine(what, line); if (line.Length > 0) { return(line); } } return(this.clearLine(what, lines.Last())); }
/// <summary> /// Check if pid is supported for ecu /// </summary> /// <param name="ecu"></param> /// <param name="pid"></param> /// <returns></returns> public Boolean IsPidSupportedForEcu(Ecu ecu, OdbPid pid) { if (supportedPids.ContainsKey(ecu.EcuId)) { var modes = supportedPids[ecu.EcuId]; if (modes.ContainsKey(OdbPids.ATSP0)) { var pids = modes[OdbPids.ATSP0]; return(pids.Contains(pid.GetPidIdInDecimal())); } if (modes.ContainsKey(pid.Mode)) { var pids = modes[pid.Mode]; return(pids.Contains(pid.GetPidIdInDecimal())); } } return(false); }
/// <summary> /// Load supported PIds /// </summary> /// <returns></returns> private async Task LoadSupportedProtocols(OdbProtocol protocolType = OdbProtocol.Unknown, int protocolNumber = 0) { var selectedProtocol = -1; if (protocolType == OdbProtocol.Unknown) { OdbPid protocol = null; for (selectedProtocol = 0; selectedProtocol <= 9; selectedProtocol++) { protocol = OdbPids.GetPidForProtocolNumber(selectedProtocol); try { OdbResponse response = await this.socket.SendAndCheck(protocol); if (response.IsValid) { break; } } catch { reporter.ReportInfo("Protocol ATSP" + protocol.Description + " is not supported."); } } if (selectedProtocol == 10) { throw new OdbException(OdbError.CouldNotFindCompatibleProtocol); } this.socket.SelectedProtocol = protocol; } else if (protocolType == OdbProtocol.Specified && protocolNumber > 0 && protocolNumber < 10) { OdbPid protocol = OdbPids.GetPidForProtocolNumber(selectedProtocol); await this.socket.SendAndCheck(protocol); this.socket.SelectedProtocol = protocol; } else { throw new OdbException(OdbError.WrongProtocolNumber); } }
/// <summary> /// Register supported pids /// </summary> /// <param name="ecuIdentifier"></param> /// <param name="odbPid"></param> /// <param name="pids"></param> private void RegisterSupportedPids(int ecuIdentifier, OdbPid odbPid, List <int> pids) { if (!supportedPids.ContainsKey(ecuIdentifier)) { supportedPids.Add(ecuIdentifier, new Dictionary <OdbPid, List <int> >()); } Dictionary <OdbPid, List <int> > supportedPidsForEcu = supportedPids[ecuIdentifier]; if (supportedPidsForEcu.ContainsKey(odbPid)) { var pidsSupported = supportedPidsForEcu[odbPid]; supportedPidsForEcu[odbPid] = pidsSupported.Concat(pids).ToList(); } else { supportedPidsForEcu.Add(odbPid, pids); } }
/// <summary> /// Resolve incoming data and setup odb data /// </summary> /// <param name="response"></param> /// <param name="what"></param> /// <returns></returns> public OdbData ResolveData(String response, OdbPid what) { int counter = 0; String[] bytes = response.Split(' '); bytes = this.validateReponseBytes(bytes); OdbData data = OdbPids.GetResponseFormatForProtocolNumber(bytes.Length, what.ByteCount); if (bytes.Length < what.ByteCount) { return(null); } try { data.Protocol = this.SelectedProtocol; for (int i = 0; i < data.Header.Length; i++) { data.Header[i] = bytes[counter]; counter++; } for (int i = 0; i < data.Info.Length; i++) { data.Info[i] = bytes[counter]; counter++; } for (int i = 0; i < data.Data.Length; i++) { data.Data[i] = bytes[counter]; counter++; } for (int i = 0; i < data.Ender.Length; i++) { data.Ender[i] = bytes[counter]; counter++; } } catch { return(null); } return(data); }
/// <summary> /// Send message, return bytes response /// </summary> /// <param name="what"></param> /// <returns></returns> public async Task <OdbResponse> Send(OdbPid what) { if (!this.IsConnected) { throw new OdbException(OdbError.DeviceIsNotConnected); } //timer DateTime start = DateTime.Now; //send try { writer.WriteString(what.Pid + "\r\r"); await writer.StoreAsync(); await writer.FlushAsync(); } catch { this.IsConnected = false; throw new OdbException(OdbError.DeviceIsNotConnected); } //receive data from device OdbResponse odbResponse = await receiveDataFromDevice(what, start); //try again on error reponse while (!odbResponse.IsValid && this.tryCount > 0) { reporter.ReportInfo("Incorrect response '" + odbResponse.Response + "' from device. Try another request. Current try step is " + this.tryCount + "."); odbResponse = await receiveDataFromDevice(what, start); this.tryCount--; } this.tryCount = RESPONSE_TRY_COUNT; //report response to console reporter.ReportResponse(odbResponse); return(odbResponse); }
/// <summary> /// Decode supported pids and register it /// </summary> /// <param name="what"></param> /// <param name="data"></param> private void decodeSupportedPidsAndRegisterIt(OdbPid what, OdbData data) { List <int> pids = new List <int>(); int pid = Convert.ToInt32(what.Pid.Split(' ')[1], 16); for (int i = 0; i < data.Data.Length; i++) { char[] binary = Convert.ToString(Convert.ToInt32(data.Data[i], 16), 2).ToCharArray(); for (int j = 0; j < binary.Length; j++) { pid++; if (binary[j] == '1') { pids.Add(pid); } } } this.RegisterSupportedPids(data.EcuIdentifier(), data.Protocol, pids); }
/// <summary> /// Is valid response from device /// </summary> /// <param name="response"></param> /// <returns></returns> private bool isValidResponse(String response, OdbPid what) { var lowerResponse = response.ToLowerInvariant(); var rightLength = lowerResponse.Trim().Length > 0; var containsError = lowerResponse.Contains("error"); var containsUnknownChars = lowerResponse.Trim() == ">"; var containsNoData = lowerResponse.Contains("no data") || lowerResponse.Contains("?"); //no data is valid response if (containsNoData) { return(true); } //if is data command then validate data length if (what.IsDataCommand && this.ResolveData(response, what) == null) { return(false); } //for normal command return(rightLength && !containsError && !containsUnknownChars); }
/// <summary> /// resolve data /// </summary> /// <param name="response"></param> /// <param name="what"></param> /// <returns></returns> public OdbData ResolveData(OdbResponse response, OdbPid what) { return(this.ResolveData(response.Response, what)); }