[00:01.510 --> 00:07.620] All right, folks. Welcome today to All Aboard the Can Bus or Motorcycle. [00:07.620 --> 00:11.680] Two wires, two wheels, bikes can do, can too. [00:14.520 --> 00:21.800] In today's talk, we will cover who am I, a little bit about myself, [00:22.650 --> 00:29.520] the bike and brand. I feel to completely understand the essence of this project. [00:29.520 --> 00:35.220] The bike's a little bit on the rarer side, so we'll cover a little bit about that. [00:35.420 --> 00:41.680] Why the project inspiration and purpose. Some of the hurdles that came into play when [00:42.900 --> 00:49.400] working with the motorcycle as opposed to a car. And then the project begins, what I used, [00:49.400 --> 00:56.160] what I built, the hardware involved with the project. I built an engine simulation [00:56.940 --> 01:04.420] and I did quite a bit of CSV parsing and data analyzing with a Python script I made. [01:04.440 --> 01:09.320] And then we'll talk a little bit about what's the future of the project. [01:11.930 --> 01:17.670] So who am I? I'm Derek. I've been riding motorcycles for about 10 years. [01:18.550 --> 01:23.650] I've been a developer and InfoSec hobbyist for about 15 years. [01:23.650 --> 01:31.150] I currently work as director of IT for a food and beverage automation company. [01:31.410 --> 01:37.150] If you're interested in continuing to follow this project after this talk, you can follow me on [01:37.150 --> 01:42.730] Twitter, CanBusDutch. If you have any questions that aren't answered or you don't get a chance [01:42.730 --> 01:50.330] to ask them at the end of the talk, you could email me at CanBusDutch, gmail.com. And all the [01:50.330 --> 01:58.630] code talked about can be found at my github, github.com slash CircuitWorks1. [01:59.930 --> 02:12.790] So this is my bike, an EBR 1190 RX. Those of you not familiar with EBR or the Buell brand, [02:12.790 --> 02:17.550] Eric Buell, the founder, was a Harley engineer who liked racing motorcycles. [02:18.230 --> 02:23.910] They make the only, or they, yeah, they're the only production sport bike made and designed in [02:23.910 --> 02:31.410] the USA. They're the only American-made motorcycle to ever score points in World Superbike. And they [02:31.410 --> 02:37.870] won the 2009 Daytona Superbike Championship without a single DNF. Those not into power sports, [02:37.870 --> 02:43.470] it stands for did not finish, which means no engine failures, and more importantly, [02:43.470 --> 02:52.770] no accidents. They manufactured nearly 140,000 motorcycles in 15 years when acting as a Harley [02:52.770 --> 03:01.270] subsidiary. And in 2009, after Harley-Davidson axed Buell, they came back as Eric Buell Racing [03:01.270 --> 03:10.430] and sold 65 bikes in 18 months, garnering $3 million in revenue as a startup. And sadly, [03:10.430 --> 03:15.330] now it's a company teetering on the edge of existence. [03:17.150 --> 03:25.350] So here's a few Buells and EBRs, some a face only a mom could love. But that top bike there in the [03:25.350 --> 03:33.230] top left is the bike that helped them fund EBR. It's the EBR 1190 RS. And then you'll see the [03:33.230 --> 03:42.350] same bike I have, the EBR 1190 RX. And then the EBR 1190 SX, which is the same as the RX, [03:42.350 --> 03:52.450] just in a different trim. And then down here, we take a look at the Buell XB9S, which utilizes a [03:52.450 --> 04:02.690] Harley-Davidson Sportster power plant. And then the EBR XB9R, or sorry, the Buell XB9R. And then [04:02.690 --> 04:15.690] finally, the Buell 1125R. And we can't forget, that is the 2010 Buell Blast, which is kind of [04:15.690 --> 04:25.830] an inside joke amongst the Buell community. So now let's get into it. So after about six months of [04:25.830 --> 04:33.890] owning my EBR 1190 RX, I was on a large group ride where I did about 100 miles in a day. [04:35.250 --> 04:42.890] And on my way back home, my dash fell apart. Luckily, I didn't lose anything. [04:42.890 --> 04:51.990] My screen there held on by the ribbon to the rest of the display. And when I got back home, [04:51.990 --> 05:02.690] I reassembled it. But sadly, I started receiving a comm error. And after about a few months of [05:03.890 --> 05:10.370] you know, surfing around the Buell Facebook groups and forums, I started to realize I wasn't the only [05:10.370 --> 05:20.510] one. There was this guy, and this guy, and this guy, and this guy. Well, you get the point. [05:21.690 --> 05:29.250] So sadly, apart from these comm errors, there was also individuals who [05:30.150 --> 05:38.270] had their dash rattle to pieces, just as mine did. And at the time, the future of EBR was being [05:38.270 --> 05:44.350] decided by the courts as they had filed for receivership, which is a similar process to [05:44.350 --> 05:54.190] bankruptcy. And there was zero parts availability. So because I'm not only stupid, but also ambitious, [05:54.190 --> 06:02.970] I decided to look into designing an aftermarket dash. And that's when I realized it probably [06:02.970 --> 06:11.690] wouldn't be as easy as I thought. The main issue I ran into is that there is no diagnostics [06:11.690 --> 06:20.390] standard in the motorcycle industry. OBD2 is kind of a large plug, hard to fit on a small vehicle, [06:20.390 --> 06:28.850] and not really ideal for motorcycles. Although we will see the OBD2 standard is used on a few [06:28.850 --> 06:37.050] manufacturers. And from what I've been told, that it is becoming a standard in Europe. [06:38.890 --> 06:48.870] So there are universal diagnostic tools, although the bite offset, scaling factor, [06:48.870 --> 06:54.290] all of that good stuff is different for every manufacturer. And in order for these universal [06:54.290 --> 07:00.250] tools to obtain that information, the manufacturers charge a lot of money. So these tools [07:00.930 --> 07:10.650] are very expensive. Not only that, but the likelihood of finding a universal diagnostics tool [07:10.650 --> 07:18.470] that works with a bike with only about a thousand of them manufactured in the world [07:19.330 --> 07:26.710] is slim to none. You aren't going to find. So let's take a look at the... [07:28.410 --> 07:35.130] we'll take a peek into the motorcycle diagnostics port world. In this slide alone, [07:35.130 --> 07:44.730] we have two Kawasaki, two Hondas, two Suzuki connectors. And there we go. There we have a [07:44.730 --> 07:52.470] four pin Harley diagnostics cable. And we could see there that Piaggio, Triumph, and Victory [07:52.790 --> 08:04.310] all use the vehicle standard OBD2. And then here we see another Kawasaki connector. [08:05.790 --> 08:16.690] And here we have the Buell diagnostics port. And then we have another Kawasaki cable. [08:18.190 --> 08:25.310] And this is one of my favorites. So this MV Agusta four pin cable down here [08:25.310 --> 08:33.970] is actually the same connector used on Hondas, but it has a separate pinout. So if you accidentally [08:33.970 --> 08:45.340] use the MV Agusta connector on your Honda, you will fry your ECM. And then here's another one [08:45.340 --> 08:49.500] that kind of grabs my attention. Down in the left hand corner there, we have the Harley Davidson [08:49.500 --> 08:55.400] CAN six pin cable. If you remember, I just mentioned they had a four pin diagnostics cable [08:55.400 --> 09:05.200] and a six pin CAN cable. And as we all know, CAN is a two wire signal. So why couldn't they [09:05.200 --> 09:13.560] have just jammed the diagnostics and CAN into one cable? Who knows? And last but not least, [09:13.560 --> 09:22.160] we have the Benelli cable there. But overall, that's 37 different connectors for about 25 [09:22.160 --> 09:31.660] different manufacturers. Kind of a headache. But luckily, we have CAN. [09:32.640 --> 09:39.260] Most European and Japanese manufacturers began implementing a CAN bus system on [09:39.260 --> 09:47.380] their bikes around 2003. This includes Ducati, BMW, Honda, Kawasaki. And the American manufacturers, [09:47.380 --> 09:52.200] as with most things when it comes to automotive, were a little bit late to the CAN party. [09:52.300 --> 10:00.320] Buell first implemented a CAN system on the 2008 release of their 1125. And Harley's first [10:00.320 --> 10:08.740] CAN based bike wasn't until 2011. And it wasn't until 2014, that all Harleys were equipped with [10:09.220 --> 10:15.840] CAN bus. Information was a little bit lacking when it came to the Polaris brands Indian and [10:15.840 --> 10:26.380] the now defunct Victory. But I believe they started using CAN around 2013. So let's hop [10:26.380 --> 10:34.540] into what exactly my ECM comprises of. The microcontroller is a microtechnology PIC device. [10:35.400 --> 10:46.040] The diagnostics protocol is a single wire variable pulse width, J1850. And the CAN protocol [10:46.040 --> 10:54.600] is 500 kilobits a second, 11-bit IDs, 20-ohm termination, and least significant bit first. [10:57.310 --> 11:03.070] When it came to hardware for my project, I started out with this Seed Studio device. [11:03.070 --> 11:10.270] But after the second one failed me, I navigated over to using the the Cannibal device, which [11:10.270 --> 11:20.570] was much more reliable. And software-wise, I started off using the Seed Studio software, but [11:21.570 --> 11:26.430] ended up converting over to Busmaster after I purchased the Cannibal device. [11:29.330 --> 11:38.250] So, after doing quite a few CAN capture sessions and figuring out some of the CAN definitions from [11:38.250 --> 11:44.290] reading CAN packets directly from the bike, I was kind of over the idea of spending hours in [11:44.290 --> 11:51.010] the hot garage huffing exhaust fumes. So I thought, why not try some engine simulation? [11:51.610 --> 11:56.410] The most important part for my bike when simulating the engine sensor data is the [11:56.410 --> 12:06.370] crankshaft sensor output. The ECM won't really acknowledge some of the other data if the crankshaft [12:06.370 --> 12:14.690] sensor output is not reading correctly. On my bike, the crankshaft sensor produces two waves, [12:14.690 --> 12:22.010] 180 degrees at a phase with each other. The wave is generated using a Hall sensor and a stepped [12:22.010 --> 12:29.750] rotor tone ring surrounding the stator magneto. There are 34 steps and a timing gap the equivalent [12:29.750 --> 12:35.870] to two wavelengths, or two steps. So, it's essentially 36 steps. And there we have a [12:35.870 --> 12:43.530] picture of it. You can see the timing gap there, pretty common. And now let's take a look at it. [12:43.530 --> 12:50.790] There we go. A few oscilloscope readings of the output, so I know exactly what I'm recreating. [12:52.950 --> 13:00.930] And so, how do we simulate it? There's 36 steps, one full step every 10 degrees, 360 degrees in a [13:00.930 --> 13:10.270] circle. We pick an RPM. For math's sake, we'll do 6,000 RPMs. And then, since we all know RPM is a [13:10.270 --> 13:16.510] measurement of minutes and Hertz is a measurement by seconds, we'll have a math equation that looks [13:16.510 --> 13:25.930] something like the following. RPM divided by 60 seconds times 36 steps. And we get a wavelength [13:25.930 --> 13:39.330] of 3.6 kilohertz to simulate the 6,000 RPMs. So, the code. What we do is we take the frequency [13:39.330 --> 13:47.930] input by the user through the serial monitor. I did all this using an Arduino Teensy. And [13:50.110 --> 13:57.890] we calculate the time to execute both a 34-wave cycle and a 36-wave cycle in microseconds. [13:58.170 --> 14:07.550] So, we set our variables there, RPM time and RPM restart. And then, our code logic [14:07.550 --> 14:15.930] looks something like this. If the wave start time is greater than RPM time, [14:16.710 --> 14:24.670] then we stop the wave. And if wave start time greater than RPM restart, we restart the wave. [14:24.810 --> 14:32.370] So, basically, what's happening here is we produce a wave for 34 seconds. [14:33.010 --> 14:38.010] And then, once the time hits greater than 34 seconds, we stop it. [14:38.550 --> 14:43.990] And then, we turn it back on once the time hits greater than 36 seconds. So, [14:43.990 --> 14:54.890] we have those 34 steps with a two-step pause. And now, let's take a look at what we got. And [14:54.890 --> 15:01.370] there's our oscilloscope output. We got the 34 steps and then the blank spot, the equivalent [15:01.370 --> 15:12.810] two steps. Now, we'll look into doing the mile per hour, the speed. The speed sensor simulation [15:12.810 --> 15:21.090] is a bit more basic because there's no timing gap. So, simulate our speed sensor. We [15:23.370 --> 15:30.050] will take a given frequency that was input by the user, again, through the serial monitor. [15:30.310 --> 15:36.450] And we'll turn on and off one of the pins rapidly to generate a square wave. So, [15:36.450 --> 15:42.530] we first calculate the period to complete one wave cycle in microseconds. [15:43.070 --> 15:50.110] And then, we divide that by two to find out how long the pin needs to stay in each state [15:50.110 --> 15:59.690] to complete the entire waveform. And we control it with a non-blocking delay here. [15:59.810 --> 16:07.270] So, you can see there, if the delay timer is less than the speed time divided by two, [16:07.270 --> 16:16.870] pin off. And if it's greater, then pin on. And if it's greater than... and once we created two, [16:17.770 --> 16:24.670] a full waveform there, then we restart the timer and go to town again. So, [16:26.030 --> 16:34.670] there we have it. And again, this code for the TNC can all be found in my [16:35.590 --> 16:43.910] GitHub repository that I gave at the beginning of the talk. So, now that we got our two waves [16:43.910 --> 16:53.590] looking good, we'll play with it a little bit. So, aside from the speed and RPM, I also programmed [16:53.590 --> 17:03.350] in a few switches so that I could pop back forth the things such as the neutral switch and [17:04.290 --> 17:12.650] the gas light and a few other things. So, we'll watch it and give it a try here. [17:18.060 --> 17:23.240] So, oil pressure true. And you could see up there, sorry, I forgot to point it out, [17:23.240 --> 17:29.560] but the oil pressure light went there. And now we'll change our neutral switch to false. Boom. [17:32.460 --> 17:36.840] And then low fuel set to true. [17:40.040 --> 17:46.060] And one thing about the low fuel, as it says right here, it has to remain true for 20 seconds [17:46.060 --> 17:54.920] before the ECM flips the low fuel bit to true. So, it'll pop on any second there. [17:59.380 --> 18:03.600] And there we go. Low fuel. You see the fuel trip flipped over there. [18:07.120 --> 18:11.280] And here's the fun part. RPM frequency 1001. [18:15.840 --> 18:20.440] And we got a little bit of RPM going there and speed frequency 300. [18:22.000 --> 18:26.240] And now we got a little bit of speed going there. And if you'll notice in a second, [18:26.240 --> 18:41.260] the fuel trip odometer goes up to one, the end. So, success. What the heck happened here? [18:42.360 --> 18:53.320] Okay. So, let me switch back into presentation mode. So, I... [18:54.220 --> 19:02.060] once I did that, I started capturing sessions like crazy. I was capturing everything to a CSV. [19:03.080 --> 19:13.960] And, you know, clearly, they, you know, all this data in only one set of eyes. [19:13.960 --> 19:21.640] You know, you don't want to go through all that without some software analyzing it. So, [19:21.640 --> 19:28.400] I created a Python script that compares two CSVs that were created using the CAN software. [19:29.340 --> 19:39.380] In the example I'm about to show, I have two CSVs. One is where I set the oil pressure to true. [19:39.380 --> 19:53.610] And the second is where I set the oil pressure to false. So, oops. So, a little bit about [19:53.610 --> 20:09.150] my parser here, my Python script. Out of the 15 populated columns used by my software, [20:09.750 --> 20:18.390] we only use nine of them. It's the frame ID and then the eight bytes. So, [20:22.820 --> 20:29.440] basically, what the Python script does is it looks at the number of times each ID appears and [20:29.440 --> 20:35.880] the number of times a hex value appears in each given ID. And then compares that to allow us to [20:35.880 --> 20:42.240] have in our outputs the difference in hex value appearances, the increase and decrease percentage [20:42.240 --> 20:49.840] of hex value appearances, and appearance of a new hex value in a given ID. And I also programmed it [20:49.840 --> 20:58.580] to convert the hex value to binary. So, if we take a look here, [20:58.580 --> 21:04.540] this output shows the number of times a hex value appears in a given ID. If its appearance [21:04.540 --> 21:10.980] account was zero in either of the CAN capture session, the line will be highlighted in red. [21:16.100 --> 21:22.200] The line will be highlighted in red if the number of hex value appearances is equal to [21:22.200 --> 21:33.980] the number of appearances of its given ID. So, meaning that in one CAN capture session, [21:33.980 --> 21:39.960] the hex value appeared zero times and in the other one it appeared 100% of the time. So, [21:39.960 --> 21:46.960] if we take a look here, we have that happen four times in this one. There is hex value 19 [21:47.920 --> 21:58.800] and 99 which appeared in ID 202 100% of the time while appearing in one CAN capture session while [21:58.800 --> 22:07.160] appearing zero times in the other one. And then we have down here hex value 20 and hex value 60 [22:07.160 --> 22:16.560] which appeared in ID 451 100% of the time in one file and zero percent of the time in the other. [22:16.840 --> 22:27.500] And I can confirm that after figuring this out, I was able to verify that [22:28.060 --> 22:40.580] an ID 202 byte A bit 7 is the low oil warning light and ID 451 byte H bit 6 is an oil pressure [22:40.580 --> 22:55.160] True, false, bit. So, we can see... so, let's go on. Again, this, which we'll call it, this [22:55.160 --> 23:08.400] Python script is available at my GitHub account to take a look at and analyze your own CSVs. [23:08.960 --> 23:16.340] And now we'll look. Now that I have the... now that I've reversed a whole bunch using the Python script [23:16.960 --> 23:24.140] and, you know, I was able to trigger all types of ECM settings to reverse, [23:24.140 --> 23:36.040] I developed my first prototype here. This project was used with a... I'll wait and let it go. [24:30.920 --> 24:47.200] All right. So, that was developed using a Nextion display and a ESP32 with some... with a CAN input on it. [24:47.460 --> 24:56.480] And, you know, originally I was going to make this from the ground up, but, I don't know, I just [24:56.480 --> 25:01.960] decided when everything's exposed to the elements, like on a motorcycle, it probably wasn't the [25:02.460 --> 25:14.320] best route to go. So, I ended up purchasing an AIM MXS 1.2 Strata, which so far I've loved [25:14.320 --> 25:21.780] and highly recommend. I haven't actually put it on the bike yet, but here's a little video of [25:21.780 --> 25:29.260] what I got going. We're going to let the bike warm up. You'll see the light over here [25:29.260 --> 25:32.500] for the engine temperature. We'll go from blue to green [25:33.740 --> 25:39.740] when the engine is warm, and then I'll give it a few revs to show off. [26:36.200 --> 26:44.120] All right, there we go. So, what's next for the project? Aside from finishing the development of [26:44.120 --> 26:51.520] the dash, you know, I'd really like to stretch my Python script a little bit further. Right now, [26:51.520 --> 26:59.640] all the IDs to my bike are hard programmed into the Python script. Ideally, you know, [26:59.640 --> 27:05.300] this Python script would be able to look at the ID column, grab all the individual IDs that are in [27:05.300 --> 27:12.360] it, and then start analyzing then. You know, I spend a lot of time as a front-end developer, [27:12.360 --> 27:19.160] and I'd also like to make the Python script output a little bit prettier. I think some [27:19.160 --> 27:25.640] data visualization that I've started playing with, you know, would really spice things up a bit and [27:25.640 --> 27:34.920] kind of make things easier to point out. Some byte annotation. Right now, the Python script [27:34.920 --> 27:43.500] only parses data based on the hex values and the IDs. So, you could end up with some confusion on, [27:43.500 --> 27:51.260] you know, if you're getting hex value changes in different bytes in the same ID and stuff like [27:51.260 --> 27:56.600] that. And then, I'd also like to implement some bit flip search, which, you know, would help [27:56.600 --> 28:05.160] things with, like, the ground triggers or ground switches and stuff like that that are in the [28:09.150 --> 28:23.330] dash and stuff. So, you know, so anyways, that's about it. You know, I want to give some shout-outs [28:23.330 --> 28:30.430] and some thanks. Thanks to the Buell community. There's really nothing like it. Thanks to the [28:30.430 --> 28:36.550] man, the myth, the legend himself, Eric Buell, and those involved with Buell Motorcycles and EBR. [28:36.810 --> 28:42.350] And, you know, even though you guys probably hate me, I want to say thanks to Tim Blumenberg at IDS, [28:42.350 --> 28:50.430] who is the company that developed the ECM, and Bill Melvin, who currently owns EBR. And then, [28:50.430 --> 28:57.010] some of my gearhead friends that I wouldn't have been able to do this without. Jacob, [28:57.010 --> 29:04.990] Zach, Rob Weaver, Leland. You know, it couldn't have been done without everyone. Thanks. [29:06.810 --> 29:07.250] you