15 | Antus
16 | -
17 | He and Dimented24x7 created the first free tool for reading and writing (LS1Flash) and he contributed enormously to this one.
18 |
19 |
20 |
21 | Dimented24x7
22 | -
23 | For his work on LS1Flash, for sharing his disassembly of a 411 operating system, and for the first free definition of a 411 operating system's calibration data.
24 |
25 |
26 |
27 | NSFW
28 | -
29 | Tried to write PCM Hammer despite knowing far too little about the hardware side of things... Was rescued by everyone else listed here.
30 |
31 |
32 |
33 | PeteS
34 | -
35 | He speaks J1850 VPW like a native, and tortures PCMs for sadistic pleasure. His troubleshooting and testing has been invaluable.
36 |
37 |
38 |
39 | Tazzi
40 | -
41 | His code made it possible for PCM Hammer to support J2534 devices.
42 |
43 |
44 |
Tazzi and PeteS are also working on custom hardware that should provide high speed reading and writing at a low price - that's the "DVI" that you see in the list of supported interfaces. Keep an eye out for updates.
45 |
46 |
47 | And last but not least, thanks to the whole car-hacking community - to everyone who has looked under their hoods or into their OBD2 messages, and posted about it on the internet. And especially to everyone who has sent us words of encouragement along the way. It's always nice to be reminded that there are plenty more people out there who are just as stoked about this as we are!
48 |
49 |
50 |
51 | Mikebb203
52 | -
53 | Modified PCM Hammer to IPC Hammer. Only possible due to the great work of all the others working on PCM Hammer.
54 |
55 |
56 |
57 |
58 |
59 |
--------------------------------------------------------------------------------
/IPCHammer/packages.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/IPCHammer/start.txt:
--------------------------------------------------------------------------------
1 | Thanks for using IPC Hammer.
--------------------------------------------------------------------------------
/IPCLibrary/Configuration.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Configuration;
4 | using System.Linq;
5 | using System.Text;
6 | using System.Threading.Tasks;
7 |
8 | namespace PcmHacking
9 | {
10 | ///
11 | /// Reads and writes configuration settings.
12 | ///
13 | ///
14 | /// Access to underlying configuration storage is implemented separately,
15 | /// so that it can be ported to different systems or tested easily.
16 | ///
17 | public static class Configuration
18 | {
19 | ///
20 | /// The code that actually reads and writes individual configuration values.
21 | ///
22 | private static ConfigurationAccessor accessor;
23 |
24 | ///
25 | /// Allows abstracting the storage for configuration settings.
26 | ///
27 | public abstract class ConfigurationAccessor
28 | {
29 | public abstract string Read(string keyName);
30 | public abstract void Write(string keyName, string value);
31 | }
32 |
33 | ///
34 | /// Configurations setting key names.
35 | ///
36 | public class Constants
37 | {
38 | public const string DeviceCategory = "DeviceCategory";
39 |
40 | public const string SerialPort = "SerialPort";
41 |
42 | public const string SerialPortDeviceType = "SerialPortDeviceType";
43 |
44 | public const string J2534DeviceType = "J2534DeviceType";
45 |
46 | public const string DeviceCategorySerial = "Serial";
47 |
48 | public const string DeviceCategoryJ2534 = "J2534";
49 |
50 | public const string Enable4xReadWrite = "Enable4xReadWrite";
51 | }
52 |
53 | ///
54 | /// Device category (Serial, J2534, etc)
55 | ///
56 | public static string DeviceCategory
57 | {
58 | get
59 | {
60 | return Read(Constants.DeviceCategory);
61 | }
62 |
63 | set
64 | {
65 | Write(Constants.DeviceCategory, value);
66 | }
67 | }
68 |
69 | ///
70 | /// Serial port name.
71 | ///
72 | public static string SerialPort
73 | {
74 | get
75 | {
76 | return Read(Constants.SerialPort);
77 | }
78 |
79 | set
80 | {
81 | Write(Constants.SerialPort, value);
82 | }
83 | }
84 |
85 | ///
86 | /// Serial device type.
87 | ///
88 | public static string SerialPortDeviceType
89 | {
90 | get
91 | {
92 | return Read(Constants.SerialPortDeviceType);
93 | }
94 |
95 | set
96 | {
97 | Write(Constants.SerialPortDeviceType, value);
98 | }
99 | }
100 |
101 | ///
102 | /// J2534 device type.
103 | ///
104 | public static string J2534DeviceType
105 | {
106 | get
107 | {
108 | return Read(Constants.J2534DeviceType);
109 | }
110 |
111 | set
112 | {
113 | Write(Constants.J2534DeviceType, value);
114 | }
115 | }
116 |
117 | ///
118 | /// J2534 device type.
119 | ///
120 | public static bool Enable4xReadWrite
121 | {
122 | get
123 | {
124 | string raw = Read(Constants.Enable4xReadWrite);
125 | bool result;
126 | if (bool.TryParse(raw, out result))
127 | {
128 | return result;
129 | }
130 |
131 | return true;
132 | }
133 |
134 | set
135 | {
136 | Write(Constants.Enable4xReadWrite, value.ToString());
137 | }
138 | }
139 |
140 | ///
141 | /// Set the configuration accessor to use for this process.
142 | ///
143 | public static void SetAccessor(ConfigurationAccessor accessor)
144 | {
145 | Configuration.accessor = accessor;
146 | }
147 |
148 | ///
149 | /// Read a single configuration setting.
150 | ///
151 | public static string Read(string key)
152 | {
153 | return accessor.Read(key);
154 | }
155 |
156 | ///
157 | /// Write a single configuration setting.
158 | ///
159 | public static void Write(string key, string value)
160 | {
161 | accessor.Write(key, value);
162 | }
163 | }
164 | }
165 |
--------------------------------------------------------------------------------
/IPCLibrary/Devices/MockDevice.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.IO;
4 | using System.Linq;
5 | using System.Text;
6 | using System.Threading.Tasks;
7 |
8 | namespace PcmHacking
9 | {
10 | ///
11 | /// This class provides a way to test most of the app without any interface hardware.
12 | ///
13 | public class MockDevice : Device
14 | {
15 | ///
16 | /// Device ID string to use in the Device Picker form, and in interal device-type comparisons.
17 | ///
18 | public const string DeviceType = "Mock Serial Device";
19 |
20 | ///
21 | /// The mock port.
22 | ///
23 | private IPort port;
24 |
25 | ///
26 | /// Constructor.
27 | ///
28 | public MockDevice(IPort port, ILogger logger) : base(logger)
29 | {
30 | this.port = port;
31 | }
32 |
33 | ///
34 | /// Not actually necessary for this device type, but since we need to implement IDisposable...
35 | ///
36 | protected override void Dispose(bool disposing)
37 | {
38 | }
39 |
40 | ///
41 | /// Initialize the device. It's just a no-op for this device type.
42 | ///
43 | public override Task Initialize()
44 | {
45 | return Task.FromResult(true);
46 | }
47 |
48 | ///
49 | /// Not needed.
50 | ///
51 | public override Task SetTimeout(TimeoutScenario scenario)
52 | {
53 | return Task.FromResult(this.currentTimeoutScenario);
54 | }
55 |
56 | ///
57 | /// Send a message, do not expect a response.
58 | ///
59 | public override Task SendMessage(Message message)
60 | {
61 | StringBuilder builder = new StringBuilder();
62 | this.Logger.AddDebugMessage("Sending message " + message.GetBytes().ToHex());
63 | this.port.Send(message.GetBytes());
64 | return Task.FromResult(true);
65 | }
66 |
67 | ///
68 | /// Try to read an incoming message from the device.
69 | ///
70 | ///
71 | protected async override Task Receive()
72 | {
73 | //List incoming = new List(5000);
74 | byte[] incoming = new byte[5000];
75 | int count = await this.port.Receive(incoming, 0, incoming.Length);
76 | if(count > 0)
77 | {
78 | byte[] sized = new byte[count];
79 | Buffer.BlockCopy(incoming, 0, sized, 0, count);
80 | base.Enqueue(new Message(sized));
81 | }
82 |
83 | return;
84 | }
85 |
86 | ///
87 | /// Set the interface to low (false) or high (true) speed
88 | ///
89 | ///
90 | /// The caller must also tell the PCM to switch speeds
91 | ///
92 | protected override Task SetVpwSpeedInternal(VpwSpeed newSpeed)
93 | {
94 | if (newSpeed == VpwSpeed.Standard)
95 | {
96 | this.Logger.AddDebugMessage("Setting VPW 1X");
97 | }
98 | else
99 | {
100 | this.Logger.AddDebugMessage("Setting VPW 4X");
101 | }
102 |
103 | return Task.FromResult(true);
104 | }
105 |
106 | ///
107 | /// Purse any messages in the incoming-message buffer.
108 | ///
109 | public override void ClearMessageBuffer()
110 | {
111 | this.port.DiscardBuffers();
112 | }
113 | }
114 | }
115 |
--------------------------------------------------------------------------------
/IPCLibrary/Devices/SerialDevice.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 | using System.Threading.Tasks;
6 |
7 | namespace PcmHacking
8 | {
9 | ///
10 | /// Base class for serial-port devices.
11 | ///
12 | public abstract class SerialDevice : Device
13 | {
14 | ///
15 | /// The serial port this device will use.
16 | ///
17 | protected IPort Port { get; private set; }
18 |
19 | ///
20 | /// Constructor.
21 | ///
22 | public SerialDevice(IPort port, ILogger logger) : base(logger)
23 | {
24 | this.Port = port;
25 | }
26 |
27 | ///
28 | /// Disposer.
29 | ///
30 | protected override void Dispose(bool disposing)
31 | {
32 | if (disposing)
33 | {
34 | if (this.Port != null)
35 | {
36 | this.Port.Dispose();
37 | }
38 | }
39 | }
40 |
41 | ///
42 | /// Save configuration settings to app.config.
43 | ///
44 | public void UpdateAppConfiguration()
45 | {
46 | Configuration.DeviceCategory = Configuration.Constants.DeviceCategorySerial;
47 | Configuration.SerialPort = this.Port.ToString();
48 | Configuration.SerialPortDeviceType = this.GetDeviceType();
49 | }
50 |
51 | ///
52 | /// Generate a descriptive string for this device and the port that it is using.
53 | ///
54 | public override string ToString()
55 | {
56 | return this.GetDeviceType() + " on " + this.Port.ToString();
57 | }
58 |
59 | ///
60 | /// Return a descriptive string for this type of hardware.
61 | ///
62 | public abstract string GetDeviceType();
63 | }
64 | }
65 |
--------------------------------------------------------------------------------
/IPCLibrary/Logging/LogFileWriter.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.IO;
4 | using System.Text;
5 | using System.Threading.Tasks;
6 |
7 | namespace PcmHacking
8 | {
9 | ///
10 | /// Writes .csv files of log data.
11 | ///
12 | public class LogFileWriter
13 | {
14 | private StreamWriter writer;
15 | private DateTime startTime;
16 |
17 | ///
18 | /// Constructor.
19 | ///
20 | public LogFileWriter(StreamWriter writer)
21 | {
22 | this.writer = writer;
23 | }
24 |
25 | ///
26 | /// Call this once to write the file header.
27 | ///
28 | public async Task WriteHeader(IEnumerable columnNames)
29 | {
30 | this.startTime = DateTime.Now;
31 | string text = string.Join(", ", columnNames);
32 | await this.writer.WriteAsync("Clock Time, Elapsed Time, ");
33 | await this.writer.WriteLineAsync(text);
34 | }
35 |
36 | ///
37 | /// Call this to write each new row to the file.
38 | ///
39 | public void WriteLine(IEnumerable values)
40 | {
41 | lock (this.writer)
42 | {
43 | this.writer.Write(DateTime.Now.ToString("u"));
44 | this.writer.Write(", ");
45 | this.writer.Write(DateTime.Now.Subtract(this.startTime).ToString());
46 | this.writer.Write(", ");
47 | this.writer.WriteLine(string.Join(", ", values));
48 | }
49 | }
50 | }
51 | }
52 |
--------------------------------------------------------------------------------
/IPCLibrary/Logging/LogProfileReader.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.IO;
4 | using System.Text;
5 | using System.Threading.Tasks;
6 | using Newtonsoft.Json;
7 |
8 | namespace PcmHacking
9 | {
10 | public class LogProfileReader
11 | {
12 | private Stream stream;
13 |
14 | public LogProfileReader(Stream stream)
15 | {
16 | this.stream = stream;
17 | }
18 |
19 | public async Task ReadAsync()
20 | {
21 | using (StreamReader reader = new StreamReader(stream))
22 | {
23 | string json = await reader.ReadToEndAsync();
24 | return JsonConvert.DeserializeObject(json, new UnsignedHexValueConverter());
25 | }
26 | }
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/IPCLibrary/Logging/LogProfileWriter.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.IO;
4 | using System.Text;
5 | using System.Threading.Tasks;
6 | using Newtonsoft.Json;
7 |
8 | namespace PcmHacking
9 | {
10 | public class LogProfileWriter
11 | {
12 | private Stream stream;
13 |
14 | public LogProfileWriter(Stream stream)
15 | {
16 | this.stream = stream;
17 | }
18 |
19 | public async Task WriteAsync(LogProfile profile)
20 | {
21 | using (StreamWriter writer = new StreamWriter(stream))
22 | {
23 | string json = JsonConvert.SerializeObject(profile, new UnsignedHexValueConverter());
24 | await writer.WriteLineAsync(json);
25 | }
26 | }
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/IPCLibrary/Logging/LogProfileXmlReader.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.IO;
4 | using System.Text;
5 | using System.Threading.Tasks;
6 | using System.Xml.Serialization;
7 |
8 | namespace PcmHacking
9 | {
10 | public class LogProfileXmlReader
11 | {
12 | private Stream stream;
13 |
14 | public LogProfileXmlReader(Stream stream)
15 | {
16 | this.stream = stream;
17 | }
18 |
19 | public LogProfile Read()
20 | {
21 | XmlSerializer serializer = new XmlSerializer(typeof(LogProfile));
22 | return (LogProfile) serializer.Deserialize(this.stream);
23 | }
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/IPCLibrary/Logging/LogProfileXmlWriter.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.IO;
4 | using System.Text;
5 | using System.Threading.Tasks;
6 | using System.Xml.Serialization;
7 | using Newtonsoft.Json;
8 |
9 | namespace PcmHacking
10 | {
11 | public class LogProfileXmlWriter
12 | {
13 | private Stream stream;
14 |
15 | public LogProfileXmlWriter(Stream stream)
16 | {
17 | this.stream = stream;
18 | }
19 |
20 | public void Write(LogProfile profile)
21 | {
22 | XmlSerializer serializer = new XmlSerializer(typeof(LogProfile));
23 | serializer.Serialize(stream, profile);
24 | }
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/IPCLibrary/Logging/Logger.cs:
--------------------------------------------------------------------------------
1 | //#define FAST_LOGGING
2 |
3 | using System;
4 | using System.Collections.Generic;
5 | using System.IO;
6 | using System.Linq;
7 | using System.Text;
8 | using System.Threading.Tasks;
9 |
10 | namespace PcmHacking
11 | {
12 | ///
13 | /// Requests log data from the Vehicle.
14 | ///
15 | public class Logger
16 | {
17 | private readonly Vehicle vehicle;
18 | private readonly LogProfileAndMath profileAndMath;
19 | private DpidCollection dpids;
20 |
21 | #if FAST_LOGGING
22 | private DateTime lastRequestTime;
23 | #endif
24 |
25 | ///
26 | /// Constructor.
27 | ///
28 | public Logger(Vehicle vehicle, LogProfileAndMath profileAndMath, MathValueConfiguration mathValueConfiguration)
29 | {
30 | this.vehicle = vehicle;
31 | this.profileAndMath = profileAndMath;
32 | }
33 |
34 | ///
35 | /// Invoke this once to begin a logging session.
36 | ///
37 | public async Task StartLogging()
38 | {
39 | this.dpids = await this.vehicle.ConfigureDpids(this.profileAndMath.Profile);
40 |
41 | if (this.dpids == null)
42 | {
43 | return false;
44 | }
45 |
46 | int scenario = ((int)TimeoutScenario.DataLogging1 - 1);
47 | scenario += this.profileAndMath.Profile.ParameterGroups.Count;
48 | await this.vehicle.SetDeviceTimeout((TimeoutScenario)scenario);
49 |
50 | #if FAST_LOGGING
51 | if (!await this.vehicle.RequestDpids(this.dpids))
52 | {
53 | return false;
54 | }
55 |
56 | this.lastRequestTime = DateTime.Now;
57 | #endif
58 | return true;
59 | }
60 |
61 | ///
62 | /// Invoke this repeatedly to get each row of data from the PCM.
63 | ///
64 | ///
65 | public async Task> GetNextRow()
66 | {
67 | LogRowParser row = new LogRowParser(this.profileAndMath.Profile);
68 |
69 | #if FAST_LOGGING
70 | // if (DateTime.Now.Subtract(lastRequestTime) > TimeSpan.FromSeconds(2))
71 | {
72 | await this.vehicle.ForceSendToolPresentNotification();
73 | }
74 | #endif
75 | #if !FAST_LOGGING
76 | if (!await this.vehicle.RequestDpids(this.dpids))
77 | {
78 | return null;
79 | }
80 | #endif
81 |
82 | while (!row.IsComplete)
83 | {
84 |
85 | RawLogData rawData = await this.vehicle.ReadLogData();
86 | if (rawData == null)
87 | {
88 | return null;
89 | }
90 |
91 | row.ParseData(rawData);
92 | }
93 |
94 | DpidValues dpidValues = row.Evaluate();
95 |
96 | IEnumerable mathValues = this.profileAndMath.MathValueProcessor.GetMathValues(dpidValues);
97 |
98 | return dpidValues
99 | .Select(x => x.Value.ValueAsString)
100 | .Concat(mathValues)
101 | .ToArray();
102 | }
103 | }
104 | }
105 |
--------------------------------------------------------------------------------
/IPCLibrary/Logging/MathValueConfiguration.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.IO;
4 | using System.Xml.Serialization;
5 |
6 | namespace PcmHacking
7 | {
8 | public class MathValue
9 | {
10 | [XmlAttribute]
11 | public string Name { get; set; }
12 |
13 | [XmlAttribute]
14 | public string Units { get; set; }
15 |
16 | [XmlAttribute]
17 | public string XParameter { get; set; }
18 |
19 | [XmlAttribute]
20 | public string XConversion { get; set; }
21 |
22 | [XmlAttribute]
23 | public string YParameter { get; set; }
24 |
25 | [XmlAttribute]
26 | public string YConversion { get; set; }
27 |
28 | [XmlAttribute]
29 | public string Formula { get; set; }
30 |
31 | [XmlAttribute]
32 | public string Format { get; set; }
33 | }
34 |
35 | public class MathValueConfiguration
36 | {
37 | [XmlElement("MathValue")]
38 | public List MathValues;
39 | }
40 |
41 | public class MathValueConfigurationLoader
42 | {
43 | private readonly ILogger logger;
44 |
45 | public MathValueConfiguration Configuration { get; private set; }
46 |
47 | public MathValueConfigurationLoader(ILogger logger)
48 | {
49 | this.logger = logger;
50 | }
51 |
52 | public bool Initialize()
53 | {
54 | try
55 | {
56 | using (Stream stream = File.OpenRead("MathValues.configuration"))
57 | {
58 | XmlSerializer serializer = new XmlSerializer(typeof(MathValueConfiguration));
59 | this.Configuration = (MathValueConfiguration)serializer.Deserialize(stream);
60 | return true;
61 | }
62 | }
63 | catch (Exception exception)
64 | {
65 | this.logger.AddUserMessage("Unable to load math-value configuration.");
66 | this.logger.AddDebugMessage(exception.ToString());
67 | return false;
68 | }
69 | }
70 | }
71 | }
72 |
--------------------------------------------------------------------------------
/IPCLibrary/Logging/MathValueProcessor.cs:
--------------------------------------------------------------------------------
1 | using DynamicExpresso;
2 | using System;
3 | using System.Collections.Generic;
4 | using System.Linq;
5 | using System.Text;
6 |
7 | namespace PcmHacking
8 | {
9 | public class MathValueAndDependencies
10 | {
11 | public MathValue MathValue { get; private set; }
12 | public ProfileParameter XParameter { get; private set; }
13 | public Conversion XConversion { get; private set; }
14 | public ProfileParameter YParameter { get; private set; }
15 | public Conversion YConversion { get; private set; }
16 |
17 | public MathValueAndDependencies(
18 | MathValue mathValue,
19 | ProfileParameter xParameter,
20 | Conversion xConversion,
21 | ProfileParameter yParameter,
22 | Conversion yConversion)
23 | {
24 | this.MathValue = mathValue;
25 | this.XParameter = xParameter;
26 | this.XConversion = xConversion;
27 | this.YParameter = yParameter;
28 | this.YConversion = yConversion;
29 | }
30 | }
31 |
32 | public class MathValueProcessor
33 | {
34 | private readonly LogProfile profile;
35 | private List mathValues;
36 |
37 | public MathValueProcessor(LogProfile profile, MathValueConfiguration mathValueConfiguration)
38 | {
39 | this.profile = profile;
40 | this.mathValues = new List();
41 |
42 | foreach (MathValue mathValue in mathValueConfiguration.MathValues)
43 | {
44 | ProfileParameter xParameter = null;
45 | Conversion xConversion = null;
46 | ProfileParameter yParameter = null;
47 | Conversion yConversion = null;
48 |
49 | foreach (ProfileParameter parameter in this.profile.AllParameters)
50 | {
51 | // TODO: Find the parameter in a configuration file that contains all parameters and conversions,
52 | // pick the appropriate conversion even if it's not what the user chose for this log profile.
53 | if (parameter.Name == mathValue.XParameter)
54 | {
55 | xParameter = parameter;
56 | xConversion = parameter.Conversion;
57 | }
58 |
59 | if (parameter.Name == mathValue.YParameter)
60 | {
61 | yParameter = parameter;
62 | yConversion = parameter.Conversion;
63 | }
64 | }
65 |
66 | if ((xParameter != null) &&
67 | (xConversion != null) &&
68 | (yParameter != null) &&
69 | (yConversion != null))
70 | {
71 | MathValueAndDependencies valueAndDependencies = new MathValueAndDependencies(
72 | mathValue,
73 | xParameter,
74 | xConversion,
75 | yParameter,
76 | yConversion);
77 |
78 | this.mathValues.Add(valueAndDependencies);
79 | }
80 | }
81 | }
82 |
83 | public IEnumerable GetHeaders()
84 | {
85 | return this.mathValues.Select(x => x.MathValue.Name);
86 | }
87 |
88 | public IEnumerable GetMathValues()
89 | {
90 | return this.mathValues.Select(x => x.MathValue);
91 | }
92 |
93 | public IEnumerable GetMathValues(DpidValues dpidValues)
94 | {
95 | List result = new List();
96 | foreach(MathValueAndDependencies value in this.mathValues)
97 | {
98 | double xParameterValue = dpidValues[value.XParameter].RawValue;
99 | Interpreter xConverter = new Interpreter();
100 | xConverter.SetVariable("x", xParameterValue);
101 | double xConverted = xConverter.Eval(value.XConversion.Expression);
102 |
103 | double yParameterValue = dpidValues[value.YParameter].RawValue;
104 | Interpreter yConverter = new Interpreter();
105 | xConverter.SetVariable("x", yParameterValue);
106 | double YConverted = xConverter.Eval(value.YConversion.Expression);
107 |
108 | Interpreter finalConverter = new Interpreter();
109 | finalConverter.SetVariable("x", xConverted);
110 | finalConverter.SetVariable("y", YConverted);
111 | double converted = finalConverter.Eval(value.MathValue.Formula);
112 | result.Add(converted.ToString(value.MathValue.Format));
113 | }
114 |
115 | return result;
116 | }
117 | }
118 | }
119 |
--------------------------------------------------------------------------------
/IPCLibrary/Logging/ProfileAndMath.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 |
6 | namespace PcmHacking
7 | {
8 | public class LogProfileAndMath
9 | {
10 | private readonly LogProfile profile;
11 | private readonly MathValueConfiguration mathValueConfiguration;
12 | private readonly MathValueProcessor mathValueProcessor;
13 |
14 | public LogProfile Profile
15 | {
16 | get
17 | {
18 | return this.profile;
19 | }
20 | }
21 |
22 | public MathValueProcessor MathValueProcessor
23 | {
24 | get
25 | {
26 | return this.mathValueProcessor;
27 | }
28 | }
29 |
30 | public LogProfileAndMath(LogProfile profile, MathValueConfiguration mathValueConfiguration)
31 | {
32 | this.profile = profile;
33 | this.mathValueConfiguration = mathValueConfiguration;
34 | this.mathValueProcessor = new MathValueProcessor(
35 | this.profile,
36 | this.mathValueConfiguration);
37 | }
38 |
39 | public IEnumerable GetColumnNames()
40 | {
41 | return this.profile.GetParameterNames().Concat(this.mathValueProcessor.GetHeaders());
42 | }
43 | }
44 | }
45 |
--------------------------------------------------------------------------------
/IPCLibrary/Messages/BlockId.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 | using System.Threading.Tasks;
6 |
7 | namespace PcmHacking
8 | {
9 | public class BlockId
10 | {
11 | public const byte Vin1 = 0x01; // 5 bytes of VIN
12 | public const byte Vin2 = 0x02; // 6 bytes of VIN
13 | public const byte Vin3 = 0x03; // 6 bytes of VIN
14 | public const byte HardwareID = 0x08; // Hardware ID
15 | public const byte Serial1 = 0x05; // 4 bytes of Serial
16 | public const byte Serial2 = 0x06; // 4 bytes of Serial
17 | public const byte Serial3 = 0x07; // 4 bytes of Serial
18 | public const byte CalibrationID = 0x0B; // Calibration ID
19 | public const byte OperatingSystemID = 0x0A; // Operating System ID aka OSID
20 | public const byte EngineCalID = 0xFF; // Engine Segment Calibration ID
21 | public const byte EngineDiagCalID = 0x0C; // Engine Diagnostic Calibration ID
22 | public const byte TransCalID = 0x0D; // Transmission Segment Calibration ID
23 | public const byte TransDiagID = 0x0E; // Transmission Diagnostic Calibration ID
24 | public const byte FuelCalID = 0x0F; // Fuel Segment Calibration ID
25 | public const byte SystemCalID = 0x10; // System Segment Calibration ID
26 | public const byte SpeedCalID = 0x11; // Speed Calibration ID
27 | public const byte BCC = 0x14; // Broad Cast Code
28 | public const byte OilLifePerc = 0x6D; // Oil Life Remaining Percent
29 | public const byte OperatingSystemLvl = 0x93; // Operating System Level
30 | public const byte EngineCalLvl = 0x94; // Engine Segment Calibration Level
31 | public const byte EngineDiagCalLvl = 0x95; // Engine Diagnostic Calibration Level
32 | public const byte TransCalLvl = 0x96; // Transmission Segment Calibration Level
33 | public const byte TransDiagLvl = 0x97; // Transmission Diagnostic Calibration Level
34 | public const byte BootSector = 0x98; // Fuel Segment Calibration Level
35 | public const byte SystemCalLvl = 0x99; // System Segment Calibration Level
36 | public const byte SpeedCalLvl = 0x9A; // Speed Calibration Level
37 | public const byte MEC = 0xA0; // Manufacturers Enable Counter
38 | }
39 |
40 | public class BlockIdIPC
41 | {
42 | public const byte SpeedoCal = 0x90;
43 | public const byte TachCal = 0x91;
44 | public const byte FuelCal = 0x92;
45 | public const byte CoolantTempCal = 0x93;
46 | public const byte VoltCal = 0x94;
47 | public const byte OilCal = 0x95;
48 | public const byte TransTempCal = 0x97;
49 | public const byte Options = 0x9A;
50 | public const byte Options99 = 0x80;
51 |
52 |
53 | }
54 |
55 |
56 | }
57 |
--------------------------------------------------------------------------------
/IPCLibrary/Messages/Message.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Diagnostics;
4 | using System.Linq;
5 | using System.Text;
6 | using System.Threading.Tasks;
7 |
8 | namespace PcmHacking
9 | {
10 | ///
11 | /// Message is a thin wrapper around an array of bytes.
12 | ///
13 | ///
14 | /// I'll admit that this might be overkill as opposed to just passing around byte arrays.
15 | /// But the ToString method makes messages easier to view in the debugger.
16 | ///
17 | public class Message
18 | {
19 | ///
20 | /// The message content.
21 | ///
22 | private byte[] message;
23 |
24 | ///
25 | /// When the message was created.
26 | ///
27 | private ulong timestamp;
28 |
29 | ///
30 | /// Error code, if applicable.
31 | ///
32 | private ulong error;
33 |
34 | ///
35 | /// Returns the length of the message.
36 | ///
37 | public int Length
38 | {
39 | get
40 | {
41 | return this.message.Length;
42 | }
43 | }
44 |
45 | ///
46 | /// Get the Nth byte of the message.
47 | ///
48 | public byte this[int index]
49 | {
50 | get
51 | {
52 | return this.message[index];
53 | }
54 | }
55 |
56 | ///
57 | /// Constructor.
58 | ///
59 | public Message(byte[] message)
60 | {
61 | this.message = message;
62 | }
63 |
64 | ///
65 | /// Constructor.
66 | ///
67 | public Message(byte[] message, ulong timestamp, ulong error)
68 | {
69 | this.message = message;
70 | this.timestamp = timestamp;
71 | this.error = error;
72 | }
73 |
74 | ///
75 | /// When the message was created or recevied.
76 | ///
77 | public ulong TimeStamp
78 | {
79 | get { return this.timestamp; }
80 | set { this.timestamp = value; }
81 | }
82 |
83 | ///
84 | /// The error associated with creating or receiving this message.
85 | ///
86 | public ulong Error
87 | {
88 | get { return this.error; }
89 | set { this.error = value; }
90 | }
91 |
92 | ///
93 | /// Get the raw bytes.
94 | ///
95 | ///
96 | [DebuggerStepThrough]
97 | public byte[] GetBytes()
98 | {
99 | return this.message;
100 | }
101 |
102 | ///
103 | /// Generate a descriptive string for this message.
104 | ///
105 | ///
106 | /// This is the most valuable thing - it makes messages easy to view in the debugger.
107 | ///
108 | public override string ToString()
109 | {
110 | return string.Join(" ", Array.ConvertAll(message, b => b.ToString("X2")));
111 | }
112 | }
113 | }
114 |
--------------------------------------------------------------------------------
/IPCLibrary/Messages/Protocol.Misc.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Text;
4 |
5 | namespace PcmHacking
6 | {
7 | public partial class Protocol
8 | {
9 | ///
10 | /// Tell the bus that a test device is present.
11 | ///
12 | public Message CreateTestDevicePresentNotification()
13 | {
14 | byte[] bytes = new byte[] { Priority.Physical0High, DeviceId.Broadcast, DeviceId.Tool, Mode.TestDevicePresent };
15 | return new Message(bytes);
16 | }
17 |
18 | ///
19 | /// Create a broadcast message telling all modules to clear diagnostic trouble codes.
20 | ///
21 | public Message CreateClearDiagnosticTroubleCodesRequest()
22 | {
23 | byte[] bytes = new byte[] { Priority.Functional0, 0x6A, DeviceId.Tool, Mode.ClearDiagnosticTroubleCodes };
24 | return new Message(bytes);
25 | }
26 |
27 | ///
28 | /// Create a broadcast message telling all modules to clear diagnostic information.
29 | ///
30 | public Message CreateClearDiagnosticInformationRequest()
31 | {
32 | byte[] bytes = new byte[] { Priority.Physical0High, DeviceId.Broadcast, DeviceId.Tool, Mode.ClearDiagnosticInformation };
33 | return new Message(bytes);
34 | }
35 |
36 | ///
37 | /// Create a broadcast message telling all devices to disable normal message transmission (disable chatter)
38 | ///
39 | public Message CreateDisableNormalMessageTransmission()
40 | {
41 | byte[] Bytes = new byte[] { Priority.Physical0, DeviceId.Broadcast, DeviceId.Tool, Mode.SilenceBus, SubMode.Null };
42 | return new Message(Bytes);
43 | }
44 |
45 | ///
46 | /// Create a broadcast message telling all devices to disable normal message transmission (disable chatter)
47 | ///
48 | public Message CreateDisableNormalMessageTransmissionOK()
49 | {
50 | byte[] bytes = new byte[] { Priority.Physical0, DeviceId.Tool, DeviceId.Pcm, Mode.SilenceBus + Mode.Response, SubMode.Null };
51 | return new Message(bytes);
52 | }
53 |
54 | ///
55 | /// Create a broadcast message telling all devices to clear their DTCs
56 | ///
57 | public Message ClearDTCs()
58 | {
59 | byte[] bytes = new byte[] { Priority.Functional0, 0x6A, DeviceId.Tool, Mode.ClearDiagnosticTroubleCodes };
60 | return new Message(bytes);
61 | }
62 |
63 | ///
64 | /// PCM Response to Clear DTCs
65 | ///
66 | public Message ClearDTCsOK()
67 | {
68 | byte[] bytes = new byte[] { Priority.Functional0Low, 0x6B, DeviceId.Pcm, Mode.ClearDiagnosticTroubleCodes + Mode.Response };
69 | return new Message(bytes);
70 | }
71 |
72 | public Response ParseRecoveryModeBroadcast(Message message)
73 | {
74 | Response rc = this.DoSimpleValidation(message, 0x6C, 0x62, 0x01);
75 | if (!rc.Value) rc = this.DoSimpleValidation(message, 0x6C, 0xA2, 0x00);
76 | return rc;
77 | }
78 | }
79 | }
80 |
--------------------------------------------------------------------------------
/IPCLibrary/Messages/Protocol.Security.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Text;
4 |
5 | namespace PcmHacking
6 | {
7 | public partial class Protocol
8 | {
9 | class Security
10 | {
11 | public const byte Denied = 0x33; // Security Access Denied
12 | public const byte Allowed = 0x34; // Security Access Allowed
13 | public const byte Invalid = 0x35; // Invalid Key
14 | public const byte TooMany = 0x36; // Exceed Number of Attempts
15 | public const byte Delay = 0x37; // Required Time Delay Not Expired
16 | }
17 |
18 |
19 | ///
20 | /// Create a request to retrieve a 'seed' value from the PCM
21 | ///
22 | public Message CreateSeedRequest()
23 | {
24 | byte[] Bytes = new byte[] { Priority.Physical0, DeviceId.Pcm, DeviceId.Tool, Mode.Seed, SubMode.GetSeed };
25 | return new Message(Bytes);
26 | }
27 |
28 |
29 | ///
30 | /// Parse the response to a seed request.
31 | ///
32 | public Response ParseSeed(byte[] response)
33 | {
34 | ResponseStatus status;
35 | UInt16 result = 0;
36 |
37 | byte[] unlocked = { Priority.Physical0, 0x70, DeviceId.Pcm, Mode.Seed + Mode.Response, 0x01, 0x37 };
38 | byte[] seed = new byte[] { Priority.Physical0, DeviceId.Tool, DeviceId.Pcm, Mode.Seed + Mode.Response, 0x01, };
39 |
40 | if (TryVerifyInitialBytes(response, unlocked, out status))
41 | {
42 | status = ResponseStatus.Success;
43 | return Response.Create(ResponseStatus.Success, result);
44 | }
45 |
46 | if (!TryVerifyInitialBytes(response, seed, out status))
47 | {
48 | return Response.Create(ResponseStatus.Error, result);
49 | }
50 |
51 | // Let's not reverse endianess
52 | result = (UInt16)((response[5] << 8) | response[6]);
53 |
54 | return Response.Create(ResponseStatus.Success, result);
55 | }
56 |
57 | ///
58 | /// Create a request to send a 'key' value to the PCM
59 | ///
60 | public Message CreateUnlockRequest(UInt16 Key)
61 | {
62 | byte KeyHigh = (byte)((Key & 0xFF00) >> 8);
63 | byte KeyLow = (byte)(Key & 0xFF);
64 | byte[] Bytes = new byte[] { Priority.Physical0, DeviceId.Pcm, DeviceId.Tool, Mode.Seed, SubMode.SendKey, KeyHigh, KeyLow };
65 | return new Message(Bytes);
66 | }
67 |
68 | ///
69 | /// Determine whether we were able to unlock the PCM.
70 | ///
71 | public Response ParseUnlockResponse(byte[] unlockResponse, out string errorMessage)
72 | {
73 | if (unlockResponse.Length < 6)
74 | {
75 | errorMessage = $"Unlock response truncated, expected 6 bytes, got {unlockResponse.Length} bytes.";
76 | return Response.Create(ResponseStatus.UnexpectedResponse, false);
77 | }
78 |
79 | byte unlockCode = unlockResponse[5];
80 |
81 | switch (unlockCode)
82 | {
83 | case Security.Allowed:
84 | errorMessage = null;
85 | return Response.Create(ResponseStatus.Success, true);
86 |
87 | case Security.Denied:
88 | errorMessage = $"The IPC refused to unlock";
89 | return Response.Create(ResponseStatus.Error, false);
90 |
91 | case Security.Invalid:
92 | errorMessage = $"The IPC didn't accept the unlock key value";
93 | return Response.Create(ResponseStatus.Error, false);
94 |
95 | case Security.TooMany:
96 | errorMessage = $"The IPC did not accept the key - too many attempts";
97 | return Response.Create(ResponseStatus.Error, false);
98 |
99 | case Security.Delay:
100 | errorMessage = $"The IPC is enforcing timeout lock";
101 | return Response.Create(ResponseStatus.Timeout, false);
102 |
103 | default:
104 | errorMessage = $"Unknown unlock response code: 0x{unlockCode:X2}";
105 | return Response.Create(ResponseStatus.UnexpectedResponse, false);
106 | }
107 | }
108 |
109 | ///
110 | /// Indicates whether or not the reponse indicates that the PCM is unlocked.
111 | ///
112 | public bool IsUnlocked(byte[] response)
113 | {
114 | ResponseStatus status;
115 | byte[] unlocked = { Priority.Physical0, DeviceId.Tool, DeviceId.Pcm, Mode.Seed + Mode.Response, 0x01, 0x34 };
116 |
117 | if (TryVerifyInitialBytes(response, unlocked, out status))
118 | {
119 | return true;
120 | }
121 |
122 | return false;
123 | }
124 | }
125 | }
126 |
--------------------------------------------------------------------------------
/IPCLibrary/Messages/Protocol.Speed.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Text;
4 |
5 | namespace PcmHacking
6 | {
7 | public partial class Protocol
8 | {
9 | public class HighSpeedPermissionResult
10 | {
11 | public bool IsValid { get; set; }
12 | public byte DeviceId { get; set; }
13 | public bool PermissionGranted { get; set; }
14 | }
15 |
16 | ///
17 | /// Create a request for a module to test VPW speed switch to 4x is OK
18 | ///
19 | public Message CreateHighSpeedPermissionRequest(byte deviceId)
20 | {
21 | return new Message(new byte[] { Priority.Physical0, deviceId, DeviceId.Tool, Mode.HighSpeedPrepare });
22 | }
23 |
24 | ///
25 | /// Create a request for a specific module to switch to VPW 4x
26 | ///
27 | public Message CreateBeginHighSpeed(byte deviceId)
28 | {
29 | return new Message(new byte[] { Priority.Physical0, deviceId, DeviceId.Tool, Mode.HighSpeed });
30 | }
31 |
32 | ///
33 | /// Parse the response to a request for permission to switch to 4X mode.
34 | ///
35 | public HighSpeedPermissionResult ParseHighSpeedPermissionResponse(Message message)
36 | {
37 | byte[] actual = message.GetBytes();
38 | byte[] granted = new byte[] { Priority.Physical0, DeviceId.Tool, DeviceId.Pcm, Mode.HighSpeedPrepare + Mode.Response };
39 |
40 | // Priority
41 | if (actual[0] != granted[0])
42 | {
43 | return new HighSpeedPermissionResult() { IsValid = false };
44 | }
45 |
46 | // Destination
47 | if (actual[1] != granted[1])
48 | {
49 | return new HighSpeedPermissionResult() { IsValid = false };
50 | }
51 |
52 | // Source
53 | byte moduleId = actual[2];
54 |
55 | // Permission granted?
56 | if (actual[3] == Mode.HighSpeedPrepare + Mode.Response)
57 | {
58 | return new HighSpeedPermissionResult() { IsValid = true, DeviceId = moduleId, PermissionGranted = true };
59 | }
60 |
61 | if ((actual[3] == Mode.Rejected) || (actual[3] == 0x7F))
62 | {
63 | return new HighSpeedPermissionResult() { IsValid = true, DeviceId = moduleId, PermissionGranted = false };
64 | }
65 |
66 | return new HighSpeedPermissionResult() { IsValid = false };
67 | }
68 |
69 | public Response ParseHighSpeedRefusal(Message message)
70 | {
71 | byte[] actual = message.GetBytes();
72 | byte[] refusal = new byte[] { Priority.Physical0, DeviceId.Tool, DeviceId.Broadcast, Mode.HighSpeedPrepare + Mode.Response };
73 |
74 | // Priority
75 | if (actual[0] != refusal[0])
76 | {
77 | return Response.Create(ResponseStatus.UnexpectedResponse, false);
78 | }
79 |
80 | // Destination
81 | if (actual[1] != refusal[1])
82 | {
83 | return Response.Create(ResponseStatus.UnexpectedResponse, false);
84 | }
85 |
86 | // Source
87 | byte moduleId = refusal[2];
88 |
89 | if ((actual[3] == Mode.Rejected) || (actual[3] == 0x7F))
90 | {
91 | if (actual[4] == Mode.HighSpeed)
92 | {
93 | return Response.Create(ResponseStatus.Success, true);
94 | }
95 | }
96 |
97 | return Response.Create(ResponseStatus.UnexpectedResponse, false);
98 | }
99 | }
100 | }
101 |
--------------------------------------------------------------------------------
/IPCLibrary/Messages/Protocol.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Text;
4 |
5 | namespace PcmHacking
6 | {
7 | ///
8 | /// This class is responsible for generating and parsing the messages that the app exchanges with the PCM.
9 | ///
10 | ///
11 | /// The messages generated by this class are byte-for-byte exactly what the PCM
12 | /// receives, with the exception of the CRC byte at the end. CRC bytes must be
13 | /// added by the currently-selected Device class if the actual device doesn't add
14 | /// the CRC byte automatically.
15 | ///
16 | /// Some devices will require these messages to be translated according to the specific
17 | /// device's protocol - that too is the job of the currently-selected Device class.
18 | ///
19 | public partial class Protocol
20 | {
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/IPCLibrary/Misc/AwayMode.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Runtime.InteropServices;
4 | using System.Text;
5 |
6 | namespace PcmHacking
7 | {
8 | public class AwayMode : IDisposable
9 | {
10 | [FlagsAttribute]
11 | public enum EXECUTION_STATE : uint
12 | {
13 | ES_SYSTEM_REQUIRED = 0x00000001,
14 | ES_DISPLAY_REQUIRED = 0x00000002,
15 | // Legacy flag, should not be used.
16 | // ES_USER_PRESENT = 0x00000004,
17 | ES_AWAYMODE_REQUIRED = 0x00000040,
18 | ES_CONTINUOUS = 0x80000000,
19 | }
20 |
21 | [DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
22 | private static extern EXECUTION_STATE SetThreadExecutionState(EXECUTION_STATE esFlags);
23 |
24 | private EXECUTION_STATE previousState;
25 |
26 | public AwayMode()
27 | {
28 | this.previousState = SetThreadExecutionState(
29 | EXECUTION_STATE.ES_CONTINUOUS
30 | | EXECUTION_STATE.ES_DISPLAY_REQUIRED
31 | | EXECUTION_STATE.ES_SYSTEM_REQUIRED
32 | | EXECUTION_STATE.ES_AWAYMODE_REQUIRED);
33 | }
34 |
35 | #region IDisposable Support
36 | private bool disposedValue = false; // To detect redundant calls
37 |
38 | protected virtual void Dispose(bool disposing)
39 | {
40 | if (!disposedValue)
41 | {
42 | if (disposing)
43 | {
44 | // TODO: dispose managed state (managed objects).
45 | }
46 |
47 | SetThreadExecutionState(this.previousState);
48 |
49 | disposedValue = true;
50 | }
51 | }
52 |
53 | ///
54 | /// Override finalizer to ensure that 'away mode' is released even if Dispose is not called.
55 | ///
56 | ~AwayMode()
57 | {
58 | // Do not change this code. Put cleanup code in Dispose(bool disposing) above.
59 | Dispose(false);
60 | }
61 |
62 | // This code added to correctly implement the disposable pattern.
63 | public void Dispose()
64 | {
65 | // Do not change this code. Put cleanup code in Dispose(bool disposing) above.
66 | Dispose(true);
67 | GC.SuppressFinalize(this);
68 | }
69 |
70 | #endregion
71 | }
72 | }
73 |
--------------------------------------------------------------------------------
/IPCLibrary/Misc/Crc.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Text;
4 |
5 | namespace PcmHacking
6 | {
7 | ///
8 | /// From https://barrgroup.com/Embedded-Systems/How-To/CRC-Calculation-C-Code
9 | ///
10 | public class Crc
11 | {
12 | private static UInt32[] crcTable;
13 | private const int WIDTH = 8 * 4;
14 | private const UInt32 TOPBIT = 0x80000000;
15 | private const UInt32 POLYNOMIAL = 0x04C11DB7;
16 |
17 | public Crc()
18 | {
19 | if (crcTable == null)
20 | {
21 | crcTable = new UInt32[256];
22 | UInt32 remainder;
23 |
24 | /*
25 | * Compute the remainder of each possible dividend.
26 | */
27 | for (int dividend = 0; dividend < 256; ++dividend)
28 | {
29 | /*
30 | * Start with the dividend followed by zeros.
31 | */
32 | remainder = (UInt32)(dividend << (WIDTH - 8));
33 |
34 | /*
35 | * Perform modulo-2 division, a bit at a time.
36 | */
37 | for (int bit = 8; bit > 0; --bit)
38 | {
39 | /*
40 | * Try to divide the current data bit.
41 | */
42 | if ((remainder & TOPBIT) != 0)
43 | {
44 | remainder = (remainder << 1) ^ POLYNOMIAL;
45 | }
46 | else
47 | {
48 | remainder = (remainder << 1);
49 | }
50 | }
51 |
52 | /*
53 | * Store the result into the table.
54 | */
55 | crcTable[dividend] = remainder;
56 | }
57 | }
58 | }
59 |
60 | public UInt32 GetCrc(byte[] buffer, UInt32 start, UInt32 length)
61 | {
62 | byte data;
63 | UInt32 remainder = 0;
64 |
65 | for (UInt32 index = start; index < start + length; index++)
66 | {
67 | /*
68 | * Divide the message by the polynomial, a byte at a time.
69 | */
70 | data = (byte)(buffer[index] ^ (remainder >> (WIDTH - 8)));
71 | remainder = crcTable[data] ^ (remainder << 8);
72 | }
73 |
74 | /*
75 | * The final remainder is the CRC.
76 | */
77 | return (remainder);
78 | }
79 | }
80 | }
81 |
--------------------------------------------------------------------------------
/IPCLibrary/Misc/Exceptions.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Text;
4 |
5 | namespace PcmHacking
6 | {
7 | public class DataTruncatedException : Exception
8 | {
9 | public DataTruncatedException(string message = "Data Truncated"): base (message)
10 | {
11 | }
12 | }
13 |
14 | public class UnsupportedFormatException: Exception
15 | {
16 | public UnsupportedFormatException(string message = "Data format not supported."): base(message)
17 | {
18 | }
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/IPCLibrary/Misc/ILogger.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 | using System.Threading.Tasks;
6 |
7 | namespace PcmHacking
8 | {
9 | ///
10 | /// This interface allows other classes to send user-friendly status messages and
11 | /// developer-oriented debug messages to the UI.
12 | ///
13 | public interface ILogger
14 | {
15 | ///
16 | /// Add a message to the 'results' pane of the UI.
17 | ///
18 | ///
19 | /// These messages should be things that end users will understand.
20 | /// They should describe major operations, not sequences of bytes.
21 | ///
22 | void AddUserMessage(string message);
23 |
24 | ///
25 | /// Add a message to the 'debug' pane of the UI.
26 | ///
27 | /// These should be things that we can use to diagnose errors.
28 | /// Feel free to include raw sequences of bytes.
29 | void AddDebugMessage(string message);
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/IPCLibrary/Misc/Response.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 | using System.Threading.Tasks;
6 |
7 | namespace PcmHacking
8 | {
9 | ///
10 | /// These values indicate what went wrong when we were trying to recevie a response from the ECU.
11 | ///
12 | public enum ResponseStatus
13 | {
14 | ///
15 | /// Unspecified error type - try to avoid using this.
16 | ///
17 | Error = 0,
18 |
19 | ///
20 | /// Successful response.
21 | ///
22 | Success = 1,
23 |
24 | ///
25 | /// Response was shorter than expected.
26 | ///
27 | Truncated = 2,
28 |
29 | ///
30 | /// Response contained data that differs from what was expected.
31 | ///
32 | UnexpectedResponse = 3,
33 |
34 | ///
35 | /// No response was received before the timeout expired.
36 | ///
37 | Timeout = 4,
38 |
39 | ///
40 | /// The operation was cancelled by the user.
41 | ///
42 | Cancelled = 5,
43 |
44 | ///
45 | /// The request was refused.
46 | ///
47 | Refused = 6,
48 | }
49 |
50 | ///
51 | /// See the Response[T] class below. This one just contains Response-
52 | /// related methods that can be called without requiring explicit
53 | /// generic parameters.
54 | ///
55 | public class Response
56 | {
57 | ///
58 | /// Create a response with the given status and value.
59 | ///
60 | ///
61 | /// This just makes the calling code simpler because you don't have to specify T explicitly.
62 | ///
63 | public static Response Create(ResponseStatus status, T value, int retryCount = -1)
64 | {
65 | return new Response(status, value, retryCount);
66 | }
67 | }
68 |
69 | ///
70 | /// Response objects contain response data, or an error status and placeholder data.
71 | ///
72 | ///
73 | /// The idea here is to make it easy to communicate values and errors from
74 | /// low-level code up to the UI, using a single object.
75 | ///
76 | public class Response
77 | {
78 | ///
79 | /// Indicates success or gives us some idea of what went wrong.
80 | ///
81 | public ResponseStatus Status { get; private set; }
82 |
83 | ///
84 | /// Indicates how many times the operation had to be retried.
85 | ///
86 | public int RetryCount { get; private set; }
87 |
88 | ///
89 | /// The value that came from the PCM.
90 | ///
91 | ///
92 | /// Lower-level code operates on byte arrays, but higher level code can
93 | /// operate on strings or integers or other data types.
94 | ///
95 | /// If the Status property is not 'Success' then the value of this
96 | /// property should be null, zero, empty string, etc.
97 | ///
98 | public T Value { get; private set; }
99 |
100 | ///
101 | /// Create a Response object with the given status and value.
102 | ///
103 | public Response(ResponseStatus status, T value, int retryCount = -1)
104 | {
105 | this.Status = status;
106 | this.Value = value;
107 | this.RetryCount = retryCount;
108 | }
109 |
110 | ///
111 | /// This is the string that appears when you hover the mouse over something in the debugger.
112 | ///
113 | public override string ToString()
114 | {
115 | return string.Format("{0} {1}", this.Status, this.Value?.ToString());
116 | }
117 | }
118 | }
119 |
--------------------------------------------------------------------------------
/IPCLibrary/Misc/ToolPresentNotifier.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 | using System.Threading.Tasks;
6 |
7 | namespace PcmHacking
8 | {
9 | ///
10 | /// Send VPW "tool present" messages to keep the PCM in a state receptive to reading and writing.
11 | ///
12 | public class ToolPresentNotifier
13 | {
14 | ///
15 | /// Provides access to the Results and Debug panes.
16 | ///
17 | ILogger logger;
18 |
19 | ///
20 | /// Generates VPW messages.
21 | ///
22 | Protocol protocol;
23 |
24 | ///
25 | /// The device to send messages with.
26 | ///
27 | Device device;
28 |
29 | ///
30 | /// When the last message was sent.
31 | ///
32 | DateTime lastNotificationTime = DateTime.MinValue;
33 |
34 | ///
35 | /// Constructor.
36 | ///
37 | public ToolPresentNotifier(Device device, Protocol protocol, ILogger logger)
38 | {
39 | this.logger = logger;
40 | this.protocol = protocol;
41 | this.device = device;
42 | }
43 |
44 | ///
45 | /// Send a tool-present message, if the time is right.
46 | ///
47 | ///
48 | public async Task Notify()
49 | {
50 | // Tool present / 3F is required every 2.5 seconds.
51 | //
52 | // This timer ensures we won't call it more often than every 2 seconds,
53 | // but there is no upper bound because other code could spend lots of
54 | // time between calls to this code.
55 | //
56 | // Consider reducing this to 1.5 seconds if 2 seconds isn't fast enough.
57 | if(DateTime.Now > this.lastNotificationTime + TimeSpan.FromSeconds(2))
58 | {
59 | await this.SendNotification();
60 | this.lastNotificationTime = DateTime.Now;
61 | }
62 | }
63 |
64 | ///
65 | /// Send a tool-present message, even if not much time has passed. This is to aid in polling.
66 | ///
67 | ///
68 | public async Task ForceNotify()
69 | {
70 | await this.SendNotification();
71 | }
72 |
73 | ///
74 | /// Send a tool-present message.
75 | ///
76 | private async Task SendNotification()
77 | {
78 | this.logger.AddDebugMessage("Sending 'test device present' notification.");
79 | Message message = this.protocol.CreateTestDevicePresentNotification();
80 | TimeoutScenario originalScenario = await this.device.SetTimeout(TimeoutScenario.Minimum);
81 | await this.device.SendMessage(message);
82 | await this.device.SetTimeout(originalScenario);
83 | }
84 | }
85 | }
86 |
--------------------------------------------------------------------------------
/IPCLibrary/PcmLibrary.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | netstandard2.0
5 | PcmHacking
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
--------------------------------------------------------------------------------
/IPCLibrary/Ports/IPort.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.IO;
4 | using System.Linq;
5 | using System.Text;
6 | using System.Threading.Tasks;
7 |
8 | namespace PcmHacking
9 | {
10 | ///
11 | /// The IPort implementations encapsulate the differences between serial
12 | /// ports, J2534 passthrough devices, and whatever else we end up using.
13 | ///
14 | public interface IPort : IDisposable
15 | {
16 | ///
17 | /// Open the port.
18 | ///
19 | Task OpenAsync(PortConfiguration configuration);
20 |
21 | ///
22 | /// Send a sequence of bytes.
23 | ///
24 | Task Send(byte[] buffer);
25 |
26 | ///
27 | /// Receive a buffer of bytes.
28 | ///
29 | Task Receive(byte[] buffer, int offset, int count);
30 |
31 | ///
32 | /// Discard anything in the input and output buffers.
33 | ///
34 | Task DiscardBuffers();
35 |
36 | ///
37 | /// Indicates the number of bytes waiting in the receive queue.
38 | ///
39 | Task GetReceiveQueueSize();
40 |
41 | ///
42 | /// Sets the timeout for incoming messages;
43 | ///
44 | void SetTimeout(int milliseconds);
45 | }
46 |
47 | public class PortConfiguration
48 | {
49 | }
50 |
51 | public class SerialPortConfiguration : PortConfiguration
52 | {
53 | public int BaudRate { get; set; }
54 | public int Timeout { get; set; }
55 | }
56 | }
57 |
--------------------------------------------------------------------------------
/IPCLibrary/Ports/MockAvt852.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 | using System.Threading.Tasks;
6 |
7 | namespace PcmHacking
8 | {
9 | ///
10 | /// This class is just here to enable testing without any actual interface hardware.
11 | ///
12 | ///
13 | /// Eventually the Receive method should return simulated VPW responses.
14 | ///
15 | class MockAvt852 : IPort
16 | {
17 | public const string PortName = "Mock AVT 852";
18 |
19 | private byte[] responseBuffer;
20 |
21 | private int sentSoFar;
22 |
23 | private ILogger logger;
24 |
25 | public MockAvt852(ILogger logger)
26 | {
27 | // this.pcm = new MockPcm(logger);
28 | this.logger = logger;
29 | }
30 |
31 | ///
32 | /// This returns the string that appears in the drop-down list.
33 | ///
34 | public override string ToString()
35 | {
36 | return PortName;
37 | }
38 |
39 | ///
40 | /// Pretend to open a port.
41 | ///
42 | Task IPort.OpenAsync(PortConfiguration configuration)
43 | {
44 | return Task.CompletedTask;
45 | }
46 |
47 | ///
48 | /// Pretend to close a port.
49 | ///
50 | public void Dispose()
51 | {
52 | }
53 |
54 | ///
55 | /// Send bytes to the mock PCM.
56 | ///
57 | Task IPort.Send(byte[] buffer)
58 | {
59 | this.logger.AddDebugMessage("MockAvt852 received: " + buffer.ToHex());
60 |
61 | if (Utility.CompareArrays(buffer, AvtDevice.AVT_RESET.GetBytes()))
62 | {
63 | responseBuffer = AvtDevice.AVT_852_IDLE.GetBytes();
64 | }
65 | else if(Utility.CompareArrays(buffer, AvtDevice.AVT_REQUEST_MODEL.GetBytes()))
66 | {
67 | responseBuffer = new byte[] { 0x93, 0x28, 0x08, 0x52 };
68 | }
69 | else if(Utility.CompareArrays(buffer, AvtDevice.AVT_REQUEST_FIRMWARE.GetBytes()))
70 | {
71 | responseBuffer = new byte[] { 0x92, 0x04, 0x15 };
72 | }
73 | else if(Utility.CompareArrays(buffer, AvtDevice.AVT_ENTER_VPW_MODE.GetBytes()))
74 | {
75 | responseBuffer = AvtDevice.AVT_VPW.GetBytes();
76 | }
77 |
78 | this.sentSoFar = 0;
79 |
80 | return Task.CompletedTask;
81 | }
82 |
83 | ///
84 | /// Receive bytes from the mock PCM.
85 | ///
86 | Task IPort.Receive(byte[] buffer, int offset, int count)
87 | {
88 | int sent = 0;
89 | for (int index = 0; index < count; index++)
90 | {
91 | buffer[offset+index] = this.responseBuffer[this.sentSoFar];
92 | this.sentSoFar++;
93 | sent++;
94 | }
95 |
96 | this.logger.AddDebugMessage("MockAvt852 sending: " + this.responseBuffer.ToHex());
97 |
98 | return Task.FromResult(sent);
99 | }
100 |
101 | ///
102 | /// Discard anything in the input and output buffers.
103 | ///
104 | public Task DiscardBuffers()
105 | {
106 | return Task.FromResult(0);
107 | }
108 |
109 | ///
110 | /// Sets the read timeout.
111 | ///
112 | public void SetTimeout(int milliseconds)
113 | {
114 | }
115 |
116 | ///
117 | /// Indicates the number of bytes waiting in the queue.
118 | ///
119 | Task IPort.GetReceiveQueueSize()
120 | {
121 | // return Task.FromResult(0);
122 | throw new NotImplementedException();
123 | }
124 | }
125 | }
126 |
--------------------------------------------------------------------------------
/IPCLibrary/Ports/MockPort.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 | using System.Threading.Tasks;
6 |
7 | namespace PcmHacking
8 | {
9 | ///
10 | /// This class is just here to enable testing without any actual interface hardware.
11 | ///
12 | ///
13 | /// Eventually the Receive method should return simulated VPW responses.
14 | ///
15 | public class MockPort : IPort
16 | {
17 | public const string PortName = "Mock Port";
18 |
19 | private MockPcm pcm;
20 |
21 | public MockPort(ILogger logger)
22 | {
23 | this.pcm = new MockPcm(logger);
24 | }
25 |
26 | ///
27 | /// This returns the string that appears in the drop-down list.
28 | ///
29 | public override string ToString()
30 | {
31 | return PortName;
32 | }
33 |
34 | ///
35 | /// Pretend to open a port.
36 | ///
37 | Task IPort.OpenAsync(PortConfiguration configuration)
38 | {
39 | return Task.CompletedTask;
40 | }
41 |
42 | ///
43 | /// Pretend to close a port.
44 | ///
45 | public void Dispose()
46 | {
47 | }
48 |
49 | ///
50 | /// Send bytes to the mock PCM.
51 | ///
52 | Task IPort.Send(byte[] buffer)
53 | {
54 | this.pcm.ResetCommunications();
55 |
56 | foreach(byte b in buffer)
57 | {
58 | this.pcm.Push(b);
59 | }
60 |
61 | this.pcm.EndOfData();
62 |
63 | return Task.CompletedTask;
64 | }
65 |
66 | ///
67 | /// Receive bytes from the mock PCM.
68 | ///
69 | Task IPort.Receive(byte[] buffer, int offset, int count)
70 | {
71 | byte[] responseBuffer = this.pcm.GetResponse();
72 |
73 | int index = 0;
74 | for(; index < count && index < responseBuffer.Length; index++)
75 | {
76 | buffer[offset + index] = responseBuffer[index];
77 | }
78 |
79 | return Task.FromResult(index);
80 | }
81 |
82 | ///
83 | /// Discard anything in the input and output buffers.
84 | ///
85 | public Task DiscardBuffers()
86 | {
87 | return Task.FromResult(0);
88 | }
89 |
90 | ///
91 | /// Sets the read timeout.
92 | ///
93 | public void SetTimeout(int milliseconds)
94 | {
95 | }
96 |
97 | ///
98 | /// Indicates the number of bytes waiting in the queue.
99 | ///
100 | Task IPort.GetReceiveQueueSize()
101 | {
102 | // return Task.FromResult(0);
103 | throw new NotImplementedException();
104 | }
105 | }
106 | }
107 |
--------------------------------------------------------------------------------
/IPCLibrary/Properties/launchSettings.json:
--------------------------------------------------------------------------------
1 | {
2 | "profiles": {
3 | "PcmLibrary": {
4 | "commandName": "Project"
5 | }
6 | }
7 | }
--------------------------------------------------------------------------------
/IPCLibraryWindowsForms/Devices/DeviceFactory.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 | using System.Threading.Tasks;
6 |
7 | namespace PcmHacking
8 | {
9 | public class DeviceFactory
10 | {
11 | ///
12 | /// This might not really need to be async. If the J2534 stuff doesn't need it, then this doesn't need it either.
13 | ///
14 | public static Device CreateDeviceFromConfigurationSettings(ILogger logger)
15 | {
16 | switch(Configuration.DeviceCategory)
17 | {
18 | case Configuration.Constants.DeviceCategorySerial:
19 | return CreateSerialDevice(Configuration.SerialPort, Configuration.SerialPortDeviceType, logger);
20 |
21 | case Configuration.Constants.DeviceCategoryJ2534:
22 | return CreateJ2534Device(Configuration.J2534DeviceType, logger);
23 |
24 | default:
25 | return null;
26 | }
27 | }
28 |
29 | public static Device CreateSerialDevice(string serialPortName, string serialPortDeviceType, ILogger logger)
30 | {
31 | try
32 | {
33 | IPort port;
34 | if (string.Equals(MockPort.PortName, serialPortName))
35 | {
36 | port = new MockPort(logger);
37 | }
38 | else if (string.Equals(HttpPort.PortName, serialPortName))
39 | {
40 | port = new HttpPort(logger);
41 | }
42 | else
43 | {
44 | port = new StandardPort(serialPortName);
45 | }
46 |
47 | Device device;
48 | switch (serialPortDeviceType)
49 | {
50 | case OBDXProDevice.DeviceType:
51 | device = new OBDXProDevice(port, logger);
52 | break;
53 |
54 | case AvtDevice.DeviceType:
55 | device = new AvtDevice(port, logger);
56 | break;
57 | case AvtDevice2.DeviceType:
58 | device = new AvtDevice2(port, logger);
59 | break;
60 | case MockDevice.DeviceType:
61 | device = new MockDevice(port, logger);
62 | break;
63 |
64 | case ElmDevice.DeviceType:
65 | device = new ElmDevice(port, logger);
66 | break;
67 |
68 | default:
69 | device = null;
70 | break;
71 | }
72 |
73 | if (device == null)
74 | {
75 | return null;
76 | }
77 |
78 | return device;
79 | }
80 | catch (Exception exception)
81 | {
82 | logger.AddUserMessage($"Unable to create {serialPortDeviceType} on {serialPortName}.");
83 | logger.AddDebugMessage(exception.ToString());
84 | return null;
85 | }
86 | }
87 |
88 | public static Device CreateJ2534Device(string deviceType, ILogger logger)
89 | {
90 | foreach(var device in J2534DeviceFinder.FindInstalledJ2534DLLs(logger))
91 | {
92 | if (device.Name == deviceType)
93 | {
94 | return new J2534Device(device, logger);
95 | }
96 | }
97 |
98 | return null;
99 | }
100 | }
101 | }
102 |
--------------------------------------------------------------------------------
/IPCLibraryWindowsForms/Devices/J2534.dll:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mikebb203/IPC-Hammer/5e637eda58719271c5707a588a7cd8978085d21c/IPCLibraryWindowsForms/Devices/J2534.dll
--------------------------------------------------------------------------------
/IPCLibraryWindowsForms/Devices/J2534DeviceFinder.cs:
--------------------------------------------------------------------------------
1 | using J2534;
2 | using Microsoft.Win32;
3 | using System;
4 | using System.Collections.Generic;
5 | using System.Linq;
6 | using System.Text;
7 | using System.Threading.Tasks;
8 |
9 | namespace PcmHacking
10 | {
11 | class J2534DeviceFinder
12 | {
13 | private const string PASSTHRU_REGISTRY_PATH = "Software\\PassThruSupport.04.04";
14 | private const string PASSTHRU_REGISTRY_PATH_6432 = "Software\\Wow6432Node\\PassThruSupport.04.04";
15 |
16 | ///
17 | /// Find all installed J2534 DLLs
18 | ///
19 | public static List FindInstalledJ2534DLLs(ILogger logger)
20 | {
21 | List installedDLLs = new List();
22 |
23 | try
24 | {
25 | RegistryKey myKey = Registry.LocalMachine.OpenSubKey(PASSTHRU_REGISTRY_PATH, false);
26 | if ((myKey == null))
27 | {
28 | myKey = Registry.LocalMachine.OpenSubKey(PASSTHRU_REGISTRY_PATH_6432, false);
29 | if ((myKey == null))
30 | {
31 | return installedDLLs;
32 | }
33 |
34 | }
35 |
36 | string[] devices = myKey.GetSubKeyNames();
37 | foreach (string device in devices)
38 | {
39 | J2534.J2534Device tempDevice = new J2534.J2534Device();
40 | RegistryKey deviceKey = myKey.OpenSubKey(device);
41 | if ((deviceKey == null))
42 | {
43 | continue; //Skip device... its empty
44 | }
45 |
46 | tempDevice.Vendor = (string)deviceKey.GetValue("Vendor", "");
47 | tempDevice.Name = (string)deviceKey.GetValue("Name", "");
48 | tempDevice.ConfigApplication = (string)deviceKey.GetValue("ConfigApplication", "");
49 | tempDevice.FunctionLibrary = (string)deviceKey.GetValue("FunctionLibrary", "");
50 | tempDevice.CAN = (int)(deviceKey.GetValue("CAN", 0));
51 | tempDevice.ISO14230 = (int)(deviceKey.GetValue("ISO14230", 0));
52 | tempDevice.ISO15765 = (int)(deviceKey.GetValue("ISO15765", 0));
53 | tempDevice.ISO9141 = (int)(deviceKey.GetValue("ISO9141", 0));
54 | tempDevice.J1850PWM = (int)(deviceKey.GetValue("J1850PWM", 0));
55 | tempDevice.J1850VPW = (int)(deviceKey.GetValue("J1850VPW", 0));
56 | tempDevice.SCI_A_ENGINE = (int)(deviceKey.GetValue("SCI_A_ENGINE", 0));
57 | tempDevice.SCI_A_TRANS = (int)(deviceKey.GetValue("SCI_A_TRANS", 0));
58 | tempDevice.SCI_B_ENGINE = (int)(deviceKey.GetValue("SCI_B_ENGINE", 0));
59 | tempDevice.SCI_B_TRANS = (int)(deviceKey.GetValue("SCI_B_TRANS", 0));
60 | installedDLLs.Add(tempDevice);
61 | }
62 | return installedDLLs;
63 | }
64 | catch (Exception exception)
65 | {
66 | logger.AddDebugMessage("Error occured while finding installed J2534 devices");
67 | logger.AddDebugMessage(exception.ToString());
68 | return installedDLLs;
69 | }
70 | }
71 | }
72 | }
73 |
--------------------------------------------------------------------------------
/IPCLibraryWindowsForms/MainFormBase.Designer.cs:
--------------------------------------------------------------------------------
1 | namespace PcmHacking
2 | {
3 | using System.Windows.Forms;
4 |
5 | partial class MainFormBase : Form
6 | {
7 | ///
8 | /// Required designer variable.
9 | ///
10 | private System.ComponentModel.IContainer components = null;
11 |
12 | ///
13 | /// Clean up any resources being used.
14 | ///
15 | /// true if managed resources should be disposed; otherwise, false.
16 | protected override void Dispose(bool disposing)
17 | {
18 | if (disposing && (components != null))
19 | {
20 | components.Dispose();
21 | }
22 | base.Dispose(disposing);
23 | }
24 |
25 | #region Windows Form Designer generated code
26 |
27 | ///
28 | /// Required method for Designer support - do not modify
29 | /// the contents of this method with the code editor.
30 | ///
31 | private void InitializeComponent()
32 | {
33 | this.components = new System.ComponentModel.Container();
34 | this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
35 | this.ClientSize = new System.Drawing.Size(800, 450);
36 | this.Text = "MainFormBase";
37 | }
38 |
39 | #endregion
40 | }
41 | }
--------------------------------------------------------------------------------
/IPCLibraryWindowsForms/PcmLibraryWindowsForms.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Debug
6 | AnyCPU
7 | {4ADB5D87-D4D5-4D12-8681-A9E2D4C52DF6}
8 | Library
9 | Properties
10 | IPCLibraryWindowsForms
11 | PcmLibraryWindowsForms
12 | v4.8
13 | 512
14 | true
15 |
16 |
17 |
18 | true
19 | full
20 | false
21 | bin\Debug\
22 | DEBUG;TRACE
23 | prompt
24 | 4
25 |
26 |
27 | pdbonly
28 | true
29 | bin\Release\
30 | TRACE
31 | prompt
32 | 4
33 |
34 |
35 |
36 | False
37 | Devices\J2534.dll
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 | Form
59 |
60 |
61 | DevicePicker.cs
62 |
63 |
64 | Form
65 |
66 |
67 | MainFormBase.cs
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 | DevicePicker.cs
81 |
82 |
83 |
84 |
85 | {0b317c5a-e078-4a96-8e7a-00601bca1429}
86 | IPCLibrary
87 |
88 |
89 |
90 |
--------------------------------------------------------------------------------
/IPCLibraryWindowsForms/Ports/StandardPort.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.IO.Ports;
4 | using System.Linq;
5 | using System.Text;
6 | using System.Threading.Tasks;
7 |
8 | namespace PcmHacking
9 | {
10 | ///
11 | /// This class is responsible for sending and receiving data over a serial port.
12 | /// I would have called it 'SerialPort' but that name was already taken...
13 | ///
14 | class StandardPort : IPort
15 | {
16 | private string name;
17 | private SerialPort port;
18 |
19 | ///
20 | /// This is an experiment that did not end well the first time, but I still think it should work.
21 | ///
22 | // private Action