/// <summary> /// Set the amount of time that we'll wait for a message to arrive. /// </summary> public override async Task SetTimeout(TimeoutScenario scenario) { if (this.currentTimeout == scenario) { return; } int milliseconds = this.GetVpwTimeoutMilliseconds(scenario); // Adding some more just in case... milliseconds += 20; this.Logger.AddDebugMessage("Setting timeout for " + scenario + ", " + milliseconds.ToString() + " ms."); // The port timeout needs to be considerably longer than the device timeout, // otherwise you get "STOPPED" or "NO DATA" somewhat randomly. (I mostly saw // this when sending the tool-present messages, but that might be coincidence.) // // 100 was not enough // 150 seems like enough // Consider 200 if STOPPED / NO DATA is still a problem. this.Port.SetTimeout(milliseconds + 150); // I briefly tried hard-coding timeout values for the AT ST command, // but that's a recipe for failure. If the port timeout is shorter // than the device timeout, reads will consistently fail. int parameter = Math.Min(Math.Max(1, (milliseconds / 4)), 99); string value = parameter.ToString("00"); await this.SendAndVerify("AT ST " + value, "OK"); }
/// <summary> /// Not yet implemented. /// </summary> public override Task <TimeoutScenario> SetTimeout(TimeoutScenario scenario) { TimeoutScenario previousScenario = this.currentTimeoutScenario; this.currentTimeoutScenario = scenario; return(Task.FromResult(previousScenario)); }
/// <summary> /// Send a tool-present message. /// </summary> private async Task SendNotification() { this.logger.AddDebugMessage("Sending 'test device present' notification."); Message message = this.protocol.CreateTestDevicePresentNotification(); TimeoutScenario originalScenario = await this.device.SetTimeout(TimeoutScenario.Minimum); await this.device.SendMessage(message); await this.device.SetTimeout(originalScenario); }
/// <summary> /// Estimate timeouts. The code above seems to do a pretty good job, but this is easier to experiment with. /// </summary> protected int __GetVpwTimeoutMilliseconds(TimeoutScenario scenario) { switch (scenario) { case TimeoutScenario.ReadProperty: return(100); case TimeoutScenario.ReadMemoryBlock: return(2500); case TimeoutScenario.SendKernel: return(1000); default: throw new NotImplementedException("Unknown timeout scenario " + scenario); } }
/// <summary> /// Calculates the time required for the given scenario at the current VPW speed. /// </summary> protected int GetVpwTimeoutMilliseconds(TimeoutScenario scenario) { int packetSize; switch (scenario) { case TimeoutScenario.ReadProperty: // Approximate number of bytes in a get-VIN or get-OSID response. packetSize = 50; break; case TimeoutScenario.ReadCrc: // These packets are actually only 15 bytes, but the ReadProperty timeout wasn't // enough for the AllPro at 4x. Still not sure why. So this is a bit of a hack. // TODO: Figure out why the AllPro needs a hack to receive CRC values at 4x. packetSize = 1000; break; case TimeoutScenario.ReadMemoryBlock: // Adding 20 bytes to account for the 'read request accepted' // message that comes before the read payload. packetSize = 20 + this.MaxReceiveSize; // Not sure why this is necessary, but AllPro 2k reads won't work without it. //packetSize = (int) (packetSize * 1.1); packetSize = (int)(packetSize * 2.5); break; case TimeoutScenario.SendKernel: packetSize = this.MaxSendSize + 20; break; case TimeoutScenario.Maximum: return(0xFF * 4); default: throw new NotImplementedException("Unknown timeout scenario " + scenario); } int bitsPerByte = 9; // 8N1 serial double bitsPerSecond = this.speed == VpwSpeed.Standard ? 10.4 : 41.6; double milliseconds = (packetSize * bitsPerByte) / bitsPerSecond; // Add 10% just in case. return((int)(milliseconds * 1.1)); }
/// <summary> /// Set the amount of time that we'll wait for a message to arrive. /// </summary> public override async Task <TimeoutScenario> SetTimeout(TimeoutScenario scenario) { if (this.currentTimeoutScenario == scenario) { return(this.currentTimeoutScenario); } int milliseconds = this.implementation.GetTimeoutMilliseconds(scenario, this.Speed); this.Logger.AddDebugMessage("Setting timeout for " + scenario + ", " + milliseconds.ToString() + " ms."); // The port timeout needs to be considerably longer than the device timeout, // otherwise you get "STOPPED" or "NO DATA" somewhat randomly. (I mostly saw // this when sending the tool-present messages, but that might be coincidence.) // // Consider increasing if STOPPED / NO DATA is still a problem. this.Port.SetTimeout(milliseconds + 1000); // This code is so problematic that I've left it here as a warning. The app is // unable to receive the response to the erase command if this code is enabled. // //if (this.implementation is ScanToolDeviceImplementation) //{ // TimeoutScenario old = this.currentTimeoutScenario; // this.currentTimeoutScenario = scenario; // return old; //} // I briefly tried hard-coding timeout values for the AT ST command, // but that's a recipe for failure. If the port timeout is shorter // than the device timeout, reads will consistently fail. int parameter = Math.Min(Math.Max(1, (milliseconds / 4)), 255); string value = parameter.ToString("X2"); await this.implementation.SendAndVerify("AT ST " + value, "OK"); TimeoutScenario result = this.currentTimeoutScenario; this.currentTimeoutScenario = scenario; this.implementation.TimeoutScenario = scenario; return(result); }
/// <summary> /// Calculates the time required for the given scenario at the current VPW speed. /// </summary> protected int GetVpwTimeoutMilliseconds(TimeoutScenario scenario) { int packetSize; switch (scenario) { case TimeoutScenario.ReadProperty: // Approximate number of bytes in a get-VIN or get-OSID response. packetSize = 20; break; case TimeoutScenario.ReadMemoryBlock: // Adding 20 bytes to account for the 'read request accepted' // message that comes before the read payload. packetSize = 20 + this.MaxReceiveSize; // Not sure why this is necessary, but AllPro 2k reads won't work without it. //packetSize = (int) (packetSize * 1.1); packetSize = (int)(packetSize * 2.2); break; case TimeoutScenario.SendKernel: packetSize = this.MaxSendSize + 20; break; default: throw new NotImplementedException("Unknown timeout scenario " + scenario); } int bitsPerByte = 9; // 8N1 serial double bitsPerSecond = this.speed == VpwSpeed.Standard ? 10.4 : 41.6; double milliseconds = (packetSize * bitsPerByte) / bitsPerSecond; // Add 10% just in case. return((int)(milliseconds * 1.1)); }
/// <summary> /// Not needed. /// </summary> public override Task SetTimeout(TimeoutScenario scenario) { return(Task.FromResult(0)); }
/// <summary> /// Set the timeout period to wait for responses to incoming messages. /// </summary> public abstract Task SetTimeout(TimeoutScenario scenario);
/// <summary> /// Does everything required to switch to VPW 4x /// </summary> public async Task <bool> VehicleSetVPW4x(VpwSpeed newSpeed, ToolPresentNotifier notifier) { if (!device.Supports4X) { if (newSpeed == VpwSpeed.FourX) { // where there is no support only report no switch to 4x logger.AddUserMessage("This interface does not support VPW 4x"); } return(true); } // Configure the vehicle bus when switching to 4x if (newSpeed == VpwSpeed.FourX) { logger.AddUserMessage("Attempting switch to VPW 4x"); await device.SetTimeout(TimeoutScenario.ReadProperty); // The list of modules may not be useful after all, but // checking for an empty list indicates an uncooperative // module on the VPW bus. List <byte> modules = await this.RequestHighSpeedPermission(notifier); if (modules == null) { // A device has refused the switch to high speed mode. return(false); } Message broadcast = this.protocol.CreateBeginHighSpeed(DeviceId.Broadcast); await this.device.SendMessage(broadcast); // Check for any devices that refused to switch to 4X speed. // These responses usually get lost, so this code might be pointless. Message response = null; while ((response = await this.device.ReceiveMessage()) != null) { Response <bool> refused = this.protocol.ParseHighSpeedRefusal(response); if (refused.Status != ResponseStatus.Success) { // This should help ELM devices receive responses. await notifier.ForceNotify(); continue; } if (refused.Value == false) { // TODO: Add module number. this.logger.AddUserMessage("Module refused high-speed switch."); return(false); } } } else { logger.AddUserMessage("Reverting to VPW 1x"); } // Request the device to change await device.SetVpwSpeed(newSpeed); TimeoutScenario scenario = newSpeed == VpwSpeed.Standard ? TimeoutScenario.ReadProperty : TimeoutScenario.ReadMemoryBlock; await device.SetTimeout(scenario); return(true); }
/// <summary> /// Not yet implemented. /// </summary> public override Task <TimeoutScenario> SetTimeout(TimeoutScenario scenario) { return(Task.FromResult(this.currentTimeoutScenario)); }
/// <summary> /// Change the device's timeout. /// </summary> public async Task <TimeoutScenario> SetDeviceTimeout(TimeoutScenario scenario) { return(await this.device.SetTimeout(scenario)); }
/// <summary> /// Get the time required for the given scenario. /// </summary> public virtual int GetTimeoutMilliseconds(TimeoutScenario scenario, VpwSpeed speed) { // This base class is only instantiated for device-independent initialization. return(250); }
/// <summary> /// Change the device's timeout. /// </summary> public async Task SetDeviceTimeout(TimeoutScenario scenario) { await this.device.SetTimeout(scenario); }
/// <summary> /// Get the time required for the given scenario. /// </summary> public override int GetTimeoutMilliseconds(TimeoutScenario scenario, VpwSpeed speed) { int milliseconds; if (speed == VpwSpeed.Standard) { switch (scenario) { case TimeoutScenario.Minimum: milliseconds = 0; break; case TimeoutScenario.ReadProperty: milliseconds = 25; break; case TimeoutScenario.ReadCrc: milliseconds = 100; break; case TimeoutScenario.ReadMemoryBlock: milliseconds = 250; break; case TimeoutScenario.EraseMemoryBlock: milliseconds = 1000; break; case TimeoutScenario.WriteMemoryBlock: milliseconds = 200; break; case TimeoutScenario.SendKernel: milliseconds = 500; break; case TimeoutScenario.DataLogging1: milliseconds = 25; break; case TimeoutScenario.DataLogging2: milliseconds = 40; break; case TimeoutScenario.DataLogging3: milliseconds = 60; break; case TimeoutScenario.Maximum: return(1020); default: throw new NotImplementedException("Unknown timeout scenario " + scenario); } } else { switch (scenario) { case TimeoutScenario.Minimum: milliseconds = 0; break; // The app doesn't currently do this in 4X mode, so this is only a guess. case TimeoutScenario.ReadProperty: milliseconds = 12; break; case TimeoutScenario.ReadCrc: milliseconds = 100; break; case TimeoutScenario.ReadMemoryBlock: milliseconds = 50; break; case TimeoutScenario.EraseMemoryBlock: milliseconds = 1000; break; case TimeoutScenario.WriteMemoryBlock: milliseconds = 170; break; case TimeoutScenario.SendKernel: milliseconds = 10; break; case TimeoutScenario.DataLogging1: milliseconds = 7; break; case TimeoutScenario.DataLogging2: milliseconds = 10; break; case TimeoutScenario.DataLogging3: milliseconds = 15; break; case TimeoutScenario.Maximum: return(1020); default: throw new NotImplementedException("Unknown timeout scenario " + scenario); } } return(milliseconds); }
/// <summary> /// Get the time required for the given scenario. /// </summary> public override int GetTimeoutMilliseconds(TimeoutScenario scenario, VpwSpeed speed) { int milliseconds; if (speed == VpwSpeed.Standard) { switch (scenario) { case TimeoutScenario.Minimum: milliseconds = 0; break; case TimeoutScenario.ReadProperty: milliseconds = 25; break; case TimeoutScenario.ReadCrc: milliseconds = 100; break; case TimeoutScenario.ReadMemoryBlock: milliseconds = 110; break; case TimeoutScenario.EraseMemoryBlock: milliseconds = 1000; break; case TimeoutScenario.WriteMemoryBlock: milliseconds = 800; // 125 works, added some for safety break; case TimeoutScenario.SendKernel: milliseconds = 500; break; case TimeoutScenario.DataLogging1: milliseconds = 25; break; case TimeoutScenario.DataLogging2: milliseconds = 40; break; case TimeoutScenario.DataLogging3: milliseconds = 60; break; case TimeoutScenario.Maximum: return(1020); default: throw new NotImplementedException("Unknown timeout scenario " + scenario); } } else { throw new NotImplementedException("Since when did ScanTool devices support 4x?"); } return(milliseconds); }