1 00:00:01,510 --> 00:00:02,840 All right, folks. 2 00:00:02,840 --> 00:00:07,620 Welcome today to All Aboard the Can Bus or Motorcycle. 3 00:00:07,620 --> 00:00:11,680 Two wires, two wheels, bikes can do, can too. 4 00:00:14,520 --> 00:00:23,860 In today's talk, we will cover who am I, a little bit about myself, the bike and brand. 5 00:00:23,860 --> 00:00:29,520 I feel to completely understand the essence of this project. 6 00:00:29,520 --> 00:00:35,220 The bike's a little bit on the rarer side, so we'll cover a little bit about that. 7 00:00:35,420 --> 00:00:38,920 Why the project inspiration and purpose. 8 00:00:38,980 --> 00:00:46,200 Some of the hurdles that came into play when working with the motorcycle as opposed to a car. 9 00:00:46,460 --> 00:00:54,520 And then the project begins, what I used, what I built, the hardware involved with the project. 10 00:00:54,520 --> 00:01:04,420 I built an engine simulation and I did quite a bit of CSV parsing and data analyzing with a Python script I made. 11 00:01:04,440 --> 00:01:09,320 And then we'll talk a little bit about what's the future of the project. 12 00:01:11,930 --> 00:01:13,430 So who am I? 13 00:01:13,430 --> 00:01:14,250 I'm Derek. 14 00:01:14,270 --> 00:01:17,670 I've been riding motorcycles for about 10 years. 15 00:01:18,550 --> 00:01:23,650 I've been a developer and InfoSec hobbyist for about 15 years. 16 00:01:23,650 --> 00:01:31,150 I currently work as director of IT for a food and beverage automation company. 17 00:01:31,410 --> 00:01:39,030 If you're interested in continuing to follow this project after this talk, you can follow me on Twitter, CanBusDutch. 18 00:01:39,070 --> 00:01:48,770 If you have any questions that aren't answered or you don't get a chance to ask them at the end of the talk, you could email me at CanBusDutch, gmail.com. 19 00:01:48,810 --> 00:01:58,630 And all the code talked about can be found at my github, github.com slash CircuitWorks1. 20 00:01:59,930 --> 00:02:05,390 So this is my bike, an EBR 1190 RX. 21 00:02:07,570 --> 00:02:17,550 Those of you not familiar with EBR or the Buell brand, Eric Buell, the founder, was a Harley engineer who liked racing motorcycles. 22 00:02:18,230 --> 00:02:25,050 They make the only, or they, yeah, they're the only production sport bike made and designed in the USA. 23 00:02:25,430 --> 00:02:30,930 They're the only American-made motorcycle to ever score points in World Superbike. 24 00:02:30,930 --> 00:02:36,010 And they won the 2009 Daytona Superbike Championship without a single DNF. 25 00:02:36,010 --> 00:02:45,190 Those not into power sports, it stands for did not finish, which means no engine failures, and more importantly, no accidents. 26 00:02:45,190 --> 00:02:54,330 They manufactured nearly 140,000 motorcycles in 15 years when acting as a Harley subsidiary. 27 00:02:54,470 --> 00:03:09,070 And in 2009, after Harley-Davidson axed Buell, they came back as Eric Buell Racing and sold 65 bikes in 18 months, garnering $3 million in revenue as a startup. 28 00:03:09,190 --> 00:03:15,330 And sadly, now it's a company teetering on the edge of existence. 29 00:03:17,150 --> 00:03:23,470 So here's a few Buells and EBRs, some a face only a mom could love. 30 00:03:23,470 --> 00:03:30,190 But that top bike there in the top left is the bike that helped them fund EBR. 31 00:03:30,190 --> 00:03:32,330 It's the EBR 1190 RS. 32 00:03:32,330 --> 00:03:36,630 And then you'll see the same bike I have, the EBR 1190 RX. 33 00:03:36,890 --> 00:03:44,070 And then the EBR 1190 SX, which is the same as the RX, just in a different trim. 34 00:03:44,230 --> 00:03:55,030 And then down here, we take a look at the Buell XB9S, which utilizes a Harley-Davidson Sportster power plant. 35 00:03:55,030 --> 00:04:02,090 And then the EBR XB9R, or sorry, the Buell XB9R. 36 00:04:02,090 --> 00:04:06,990 And then finally, the Buell 1125R. 37 00:04:09,210 --> 00:04:18,990 And we can't forget, that is the 2010 Buell Blast, which is kind of an inside joke amongst the Buell community. 38 00:04:19,030 --> 00:04:22,090 So now let's get into it. 39 00:04:22,390 --> 00:04:33,890 So after about six months of owning my EBR 1190 RX, I was on a large group ride where I did about 100 miles in a day. 40 00:04:35,250 --> 00:04:39,550 And on my way back home, my dash fell apart. 41 00:04:40,210 --> 00:04:42,890 Luckily, I didn't lose anything. 42 00:04:42,890 --> 00:04:49,310 My screen there held on by the ribbon to the rest of the display. 43 00:04:49,790 --> 00:04:53,230 And when I got back home, I reassembled it. 44 00:04:53,230 --> 00:04:58,590 But sadly, I started receiving a comm error. 45 00:04:58,710 --> 00:05:11,030 And after about a few months of you know, surfing around the Buell Facebook groups and forums, I started to realize I wasn't the only one. 46 00:05:11,030 --> 00:05:18,090 There was this guy, and this guy, and this guy, and this guy. 47 00:05:18,090 --> 00:05:20,510 Well, you get the point. 48 00:05:21,690 --> 00:05:33,910 So sadly, apart from these comm errors, there was also individuals who had their dash rattle to pieces, just as mine did. 49 00:05:34,010 --> 00:05:45,590 And at the time, the future of EBR was being decided by the courts as they had filed for receivership, which is a similar process to bankruptcy. 50 00:05:45,590 --> 00:05:49,410 And there was zero parts availability. 51 00:05:49,950 --> 00:05:59,730 So because I'm not only stupid, but also ambitious, I decided to look into designing an aftermarket dash. 52 00:05:59,730 --> 00:06:05,750 And that's when I realized it probably wouldn't be as easy as I thought. 53 00:06:05,930 --> 00:06:15,610 The main issue I ran into is that there is no diagnostics standard in the motorcycle industry. 54 00:06:16,090 --> 00:06:23,790 OBD2 is kind of a large plug, hard to fit on a small vehicle, and not really ideal for motorcycles. 55 00:06:24,390 --> 00:06:30,410 Although we will see the OBD2 standard is used on a few manufacturers. 56 00:06:30,450 --> 00:06:37,050 And from what I've been told, that it is becoming a standard in Europe. 57 00:06:38,890 --> 00:06:51,970 So there are universal diagnostic tools, although the bite offset, scaling factor, all of that good stuff is different for every manufacturer. 58 00:06:51,970 --> 00:06:59,430 And in order for these universal tools to obtain that information, the manufacturers charge a lot of money. 59 00:06:59,430 --> 00:07:02,810 So these tools are very expensive. 60 00:07:02,810 --> 00:07:21,230 Not only that, but the likelihood of finding a universal diagnostics tool that works with a bike with only about a thousand of them manufactured in the world is slim to none. 61 00:07:21,230 --> 00:07:22,430 You aren't going to find. 62 00:07:22,430 --> 00:07:26,710 So let's take a look at the... 63 00:07:28,410 --> 00:07:34,170 we'll take a peek into the motorcycle diagnostics port world. 64 00:07:34,170 --> 00:07:41,810 In this slide alone, we have two Kawasaki, two Hondas, two Suzuki connectors. 65 00:07:41,810 --> 00:07:43,270 And there we go. 66 00:07:43,270 --> 00:07:48,110 There we have a four pin Harley diagnostics cable. 67 00:07:48,110 --> 00:07:58,030 And we could see there that Piaggio, Triumph, and Victory all use the vehicle standard OBD2. 68 00:07:58,110 --> 00:08:04,310 And then here we see another Kawasaki connector. 69 00:08:05,790 --> 00:08:12,010 And here we have the Buell diagnostics port. 70 00:08:12,010 --> 00:08:16,690 And then we have another Kawasaki cable. 71 00:08:18,190 --> 00:08:21,450 And this is one of my favorites. 72 00:08:21,690 --> 00:08:33,030 So this MV Agusta four pin cable down here is actually the same connector used on Hondas, but it has a separate pinout. 73 00:08:33,030 --> 00:08:41,050 So if you accidentally use the MV Agusta connector on your Honda, you will fry your ECM. 74 00:08:43,960 --> 00:08:46,840 And then here's another one that kind of grabs my attention. 75 00:08:46,840 --> 00:08:51,540 Down in the left hand corner there, we have the Harley Davidson CAN six pin cable. 76 00:08:51,540 --> 00:08:57,740 If you remember, I just mentioned they had a four pin diagnostics cable and a six pin CAN cable. 77 00:08:57,900 --> 00:09:03,560 And as we all know, CAN is a two wire signal. 78 00:09:03,560 --> 00:09:09,420 So why couldn't they have just jammed the diagnostics and CAN into one cable? 79 00:09:09,420 --> 00:09:10,900 Who knows? 80 00:09:11,520 --> 00:09:18,000 And last but not least, we have the Benelli cable there. 81 00:09:18,000 --> 00:09:24,600 But overall, that's 37 different connectors for about 25 different manufacturers. 82 00:09:24,600 --> 00:09:26,260 Kind of a headache. 83 00:09:27,260 --> 00:09:31,660 But luckily, we have CAN. 84 00:09:32,640 --> 00:09:41,140 Most European and Japanese manufacturers began implementing a CAN bus system on their bikes around 2003. 85 00:09:41,140 --> 00:09:45,080 This includes Ducati, BMW, Honda, Kawasaki. 86 00:09:45,280 --> 00:09:52,200 And the American manufacturers, as with most things when it comes to automotive, were a little bit late to the CAN party. 87 00:09:52,300 --> 00:09:57,320 Buell first implemented a CAN system on the 2008 release of their 1125. 88 00:09:57,800 --> 00:10:03,060 And Harley's first CAN based bike wasn't until 2011. 89 00:10:03,060 --> 00:10:10,620 And it wasn't until 2014, that all Harleys were equipped with CAN bus. 90 00:10:10,620 --> 00:10:17,720 Information was a little bit lacking when it came to the Polaris brands Indian and the now defunct Victory. 91 00:10:17,720 --> 00:10:23,580 But I believe they started using CAN around 2013. 92 00:10:23,820 --> 00:10:29,660 So let's hop into what exactly my ECM comprises of. 93 00:10:29,660 --> 00:10:34,540 The microcontroller is a microtechnology PIC device. 94 00:10:35,400 --> 00:10:45,120 The diagnostics protocol is a single wire variable pulse width, J1850. 95 00:10:45,120 --> 00:10:54,600 And the CAN protocol is 500 kilobits a second, 11-bit IDs, 20-ohm termination, and least significant bit first. 96 00:10:57,310 --> 00:11:03,070 When it came to hardware for my project, I started out with this Seed Studio device. 97 00:11:03,070 --> 00:11:12,770 But after the second one failed me, I navigated over to using the the Cannibal device, which was much more reliable. 98 00:11:13,370 --> 00:11:26,430 And software-wise, I started off using the Seed Studio software, but ended up converting over to Busmaster after I purchased the Cannibal device. 99 00:11:29,330 --> 00:11:47,370 So, after doing quite a few CAN capture sessions and figuring out some of the CAN definitions from reading CAN packets directly from the bike, I was kind of over the idea of spending hours in the hot garage huffing exhaust fumes. 100 00:11:47,370 --> 00:11:51,010 So I thought, why not try some engine simulation? 101 00:11:51,610 --> 00:11:57,970 The most important part for my bike when simulating the engine sensor data is the crankshaft sensor output. 102 00:11:57,990 --> 00:12:10,130 The ECM won't really acknowledge some of the other data if the crankshaft sensor output is not reading correctly. 103 00:12:10,130 --> 00:12:17,350 On my bike, the crankshaft sensor produces two waves, 180 degrees at a phase with each other. 104 00:12:17,350 --> 00:12:26,430 The wave is generated using a Hall sensor and a stepped rotor tone ring surrounding the stator magneto. 105 00:12:26,430 --> 00:12:31,970 There are 34 steps and a timing gap the equivalent to two wavelengths, or two steps. 106 00:12:31,970 --> 00:12:35,010 So, it's essentially 36 steps. 107 00:12:35,010 --> 00:12:36,930 And there we have a picture of it. 108 00:12:36,950 --> 00:12:40,910 You can see the timing gap there, pretty common. 109 00:12:40,990 --> 00:12:43,290 And now let's take a look at it. 110 00:12:43,290 --> 00:12:43,990 There we go. 111 00:12:43,990 --> 00:12:50,790 A few oscilloscope readings of the output, so I know exactly what I'm recreating. 112 00:12:52,950 --> 00:12:55,410 And so, how do we simulate it? 113 00:12:55,410 --> 00:13:01,530 There's 36 steps, one full step every 10 degrees, 360 degrees in a circle . 114 00:13:01,710 --> 00:13:03,470 We pick an RPM. 115 00:13:03,470 --> 00:13:07,030 For math's sake, we'll do 6,000 RPMs. 116 00:13:07,090 --> 00:13:18,090 And then, since we all know RPM is a measurement of minutes and Hertz is a measurement by seconds, we'll have a math equation that looks something like the following. 117 00:13:18,090 --> 00:13:22,710 RPM divided by 60 seconds times 36 steps. 118 00:13:22,710 --> 00:13:32,930 And we get a wavelength of 3.6 kilohertz to simulate the 6,000 RPMs. 119 00:13:33,230 --> 00:13:36,850 So, the code. 120 00:13:36,970 --> 00:13:42,890 What we do is we take the frequency input by the user through the serial monitor. 121 00:13:42,890 --> 00:13:47,530 I did all this using an Arduino Teensy. 122 00:13:47,530 --> 00:13:57,890 And we calculate the time to execute both a 34-wave cycle and a 36-wave cycle in microseconds. 123 00:13:58,170 --> 00:14:04,590 So, we set our variables there, RPM time and RPM restart. 124 00:14:04,690 --> 00:14:09,790 And then, our code logic looks something like this. 125 00:14:09,790 --> 00:14:18,970 If the wave start time is greater than RPM time, then we stop the wave. 126 00:14:18,970 --> 00:14:24,670 And if wave start time greater than RPM restart, we restart the wave. 127 00:14:24,810 --> 00:14:32,370 So, basically, what's happening here is we produce a wave for 34 seconds. 128 00:14:33,010 --> 00:14:38,010 And then, once the time hits greater than 34 seconds, we stop it. 129 00:14:38,550 --> 00:14:43,690 And then, we turn it back on once the time hits greater than 36 seconds. 130 00:14:43,690 --> 00:14:51,950 So, we have those 34 steps with a two-step pause. 131 00:14:52,410 --> 00:14:54,730 And now, let's take a look at what we got. 132 00:14:54,730 --> 00:14:57,370 And there's our oscilloscope output. 133 00:14:57,370 --> 00:15:03,030 We got the 34 steps and then the blank spot, the equivalent two steps. 134 00:15:03,150 --> 00:15:10,730 Now, we'll look into doing the mile per hour, the speed. 135 00:15:11,130 --> 00:15:15,870 The speed sensor simulation is a bit more basic because there's no timing gap. 136 00:15:15,870 --> 00:15:19,050 So, simulate our speed sensor. 137 00:15:20,930 --> 00:15:30,050 We will take a given frequency that was input by the user, again, through the serial monitor. 138 00:15:30,310 --> 00:15:35,570 And we'll turn on and off one of the pins rapidly to generate a square wave. 139 00:15:35,570 --> 00:15:42,530 So, we first calculate the period to complete one wave cycle in microseconds. 140 00:15:43,070 --> 00:15:52,490 And then, we divide that by two to find out how long the pin needs to stay in each state to complete the entire waveform. 141 00:15:53,210 --> 00:15:59,690 And we control it with a non-blocking delay here. 142 00:15:59,810 --> 00:16:07,870 So, you can see there, if the delay timer is less than the speed time divided by two, pin off. 143 00:16:07,870 --> 00:16:10,450 And if it's greater, then pin on. 144 00:16:11,150 --> 00:16:24,450 And if it's greater than... and once we created two, a full waveform there, then we restart the timer and go to town again. 145 00:16:24,450 --> 00:16:28,730 So, there we have it. 146 00:16:29,290 --> 00:16:41,030 And again, this code for the TNC can all be found in my GitHub repository that I gave at the beginning of the talk. 147 00:16:41,350 --> 00:16:48,430 So, now that we got our two waves looking good, we'll play with it a little bit. 148 00:16:48,430 --> 00:17:07,610 So, aside from the speed and RPM, I also programmed in a few switches so that I could pop back forth the things such as the neutral switch and the gas light and a few other things. 149 00:17:07,610 --> 00:17:12,650 So, we'll watch it and give it a try here. 150 00:17:18,060 --> 00:17:20,420 So, oil pressure true. 151 00:17:20,420 --> 00:17:25,180 And you could see up there, sorry, I forgot to point it out, but the oil pressure light went there. 152 00:17:25,180 --> 00:17:28,100 And now we'll change our neutral switch to false. 153 00:17:28,560 --> 00:17:29,560 Boom. 154 00:17:32,460 --> 00:17:36,840 And then low fuel set to true. 155 00:17:40,040 --> 00:17:50,140 And one thing about the low fuel, as it says right here, it has to remain true for 20 seconds before the ECM flips the low fuel bit to true. 156 00:17:50,140 --> 00:17:54,920 So, it'll pop on any second there. 157 00:17:59,380 --> 00:18:00,260 And there we go. 158 00:18:00,260 --> 00:18:00,960 Low fuel. 159 00:18:00,960 --> 00:18:03,600 You see the fuel trip flipped over there. 160 00:18:07,120 --> 00:18:08,560 And here's the fun part. 161 00:18:08,560 --> 00:18:11,280 RPM frequency 1001. 162 00:18:15,840 --> 00:18:20,440 And we got a little bit of RPM going there and speed frequency 300. 163 00:18:22,000 --> 00:18:24,480 And now we got a little bit of speed going there. 164 00:18:24,480 --> 00:18:31,240 And if you'll notice in a second, the fuel trip odometer goes up to one, the end. 165 00:18:31,820 --> 00:18:35,120 So, success. 166 00:18:39,440 --> 00:18:41,260 What the heck happened here? 167 00:18:42,360 --> 00:18:43,180 Okay. 168 00:18:43,180 --> 00:18:50,960 So, let me switch back into presentation mode. 169 00:18:50,960 --> 00:18:53,320 So, I... 170 00:18:54,220 --> 00:18:59,460 once I did that, I started capturing sessions like crazy. 171 00:18:59,460 --> 00:19:02,060 I was capturing everything to a CSV. 172 00:19:03,080 --> 00:19:13,960 And , you know, clearly, they, you know, all this data in only one set of eyes. 173 00:19:13,960 --> 00:19:20,600 You know, you don't want to go through all that without some software analyzing it. 174 00:19:20,600 --> 00:19:28,400 So, I created a Python script that compares two CSVs that were created using the CAN software. 175 00:19:29,340 --> 00:19:35,040 In the example I'm about to show, I have two CSVs. 176 00:19:35,040 --> 00:19:39,380 One is where I set the oil pressure to true. 177 00:19:39,380 --> 00:19:45,540 And the second is where I set the oil pressure to false. 178 00:19:50,110 --> 00:19:51,650 So, oops. 179 00:19:52,210 --> 00:20:01,550 So, a little bit about my parser here, my Python script. 180 00:20:02,210 --> 00:20:12,470 Out of the 15 populated columns used by my software, we only use nine of them. 181 00:20:12,470 --> 00:20:16,850 It's the frame ID and then the eight bytes. 182 00:20:17,810 --> 00:20:18,390 So, 183 00:20:22,820 --> 00:20:33,100 basically, what the Python script does is it looks at the number of times each ID appears and the number of times a hex value appears in each given ID. 184 00:20:33,640 --> 00:20:48,280 And then compares that to allow us to have in our outputs the difference in hex value appearances, the increase and decrease percentage of hex value appearances, and appearance of a new hex value in a given ID. 185 00:20:48,380 --> 00:20:55,800 And I also programmed it to convert the hex value to binary. 186 00:20:55,800 --> 00:21:03,580 So, if we take a look here, this output shows the number of times a hex value appears in a given ID. 187 00:21:03,780 --> 00:21:10,980 If its appearance account was zero in either of the CAN capture session, the line will be highlighted in red. 188 00:21:16,100 --> 00:21:25,520 The line will be highlighted in red if the number of hex value appearances is equal to the number of appearances of its given ID. 189 00:21:26,340 --> 00:21:39,720 So, meaning that in one CAN capture session, the hex value appeared zero times and in the other one it appeared 100% of the time. 190 00:21:39,720 --> 00:21:44,320 So, if we take a look here, we have that happen four times in this one. 191 00:21:44,360 --> 00:22:01,400 There is hex value 19 and 99 which appeared in ID 202 100% of the time while appearing in one CAN capture session while appearing zero times in the other one. 192 00:22:01,400 --> 00:22:16,560 And then we have down here hex value 20 and hex value 60 which appeared in ID 451 100% of the time in one file and zero percent of the time in the other. 193 00:22:16,840 --> 00:22:42,580 And I can confirm that after figuring this out, I was able to verify that an ID 202 byte A bit 7 is the low oil warning light and ID 451 byte H bit 6 is an oil pressure True, false, bit. 194 00:22:45,120 --> 00:22:50,240 So, we can see... so, let's go on. 195 00:22:50,240 --> 00:23:08,400 Again, this, which we'll call it, this Python script is available at my GitHub account to take a look at and analyze your own CSVs. 196 00:23:08,960 --> 00:23:10,200 And now we'll look. 197 00:23:10,200 --> 00:23:28,460 Now that I have the... now that I've reversed a whole bunch using the Python script and, you know, I was able to trigger all types of ECM settings to reverse, I developed my first prototype here. 198 00:23:29,100 --> 00:23:36,040 This project was used with a... I'll wait and let it go. 199 00:24:30,920 --> 00:24:32,180 All right. 200 00:24:32,180 --> 00:24:47,200 So, that was developed using a Nextion display and a ESP32 with some... with a CAN input on it. 201 00:24:47,460 --> 00:25:03,660 And, you know, originally I was going to make this from the ground up, but, I don't know, I just decided when everything's exposed to the elements, like on a motorcycle, it probably wasn't the best route to go. 202 00:25:03,660 --> 00:25:16,580 So, I ended up purchasing an AIM MXS 1.2 Strata, which so far I've loved and highly recommend. 203 00:25:16,580 --> 00:25:23,080 I haven't actually put it on the bike yet, but here's a little video of what I got going. 204 00:25:23,080 --> 00:25:25,900 We're going to let the bike warm up. 205 00:25:26,620 --> 00:25:31,080 You'll see the light over here for the engine temperature. 206 00:25:31,080 --> 00:25:39,740 We'll go from blue to green when the engine is warm, and then I'll give it a few revs to show off. 207 00:26:36,200 --> 00:26:38,700 All right, there we go. 208 00:26:38,700 --> 00:26:42,340 So, what's next for the project? 209 00:26:42,340 --> 00:26:50,360 Aside from finishing the development of the dash, you know, I'd really like to stretch my Python script a little bit further. 210 00:26:50,360 --> 00:26:58,120 Right now, all the IDs to my bike are hard programmed into the Python script. 211 00:26:58,120 --> 00:27:08,140 Ideally, you know, this Python script would be able to look at the ID column, grab all the individual IDs that are in it, and then start analyzing then. 212 00:27:08,920 --> 00:27:18,340 You know, I spend a lot of time as a front-end developer, and I'd also like to make the Python script output a little bit prettier. 213 00:27:18,460 --> 00:27:29,080 I think some data visualization that I've started playing with, you know, would really spice things up a bit and kind of make things easier to point out. 214 00:27:29,160 --> 00:27:31,260 Some byte annotation. 215 00:27:31,860 --> 00:27:39,100 Right now, the Python script only parses data based on the hex values and the IDs. 216 00:27:39,100 --> 00:27:51,880 So, you could end up with some confusion on, you know, if you're getting hex value changes in different bytes in the same ID and stuff like that. 217 00:27:51,880 --> 00:28:05,160 And then, I'd also like to implement some bit flip search, which, you know, would help things with, like, the ground triggers or ground switches and stuff like that that are in the 218 00:28:09,150 --> 00:28:10,890 dash and stuff. 219 00:28:10,890 --> 00:28:18,750 So, you know, so anyways, that's about it. 220 00:28:19,190 --> 00:28:24,550 You know, I want to give some shout-outs and some thanks. 221 00:28:24,770 --> 00:28:26,570 Thanks to the Buell community. 222 00:28:26,570 --> 00:28:29,470 There's really nothing like it. 223 00:28:29,530 --> 00:28:36,550 Thanks to the man, the myth, the legend himself, Eric Buell, and those involved with Buell Motorcycles and EBR. 224 00:28:36,810 --> 00:28:49,350 And, you know, even though you guys probably hate me, I want to say thanks to Tim Blumenberg at IDS, who is the company that developed the ECM, and Bill Melvin, who currently owns EBR. 225 00:28:49,750 --> 00:28:56,030 And then, some of my gearhead friends that I wouldn't have been able to do this without. 226 00:28:56,130 --> 00:28:59,870 Jacob, Zach, Rob Weaver, Leland. 227 00:29:01,450 --> 00:29:04,150 You know, it couldn't have been done without everyone. 228 00:29:04,150 --> 00:29:04,990 Thanks. 229 00:29:06,810 --> 00:29:07,250 you