 So yeah, I guess we'll get started. It's about five minutes after time. So as you guys probably saw from the previous talk about the game, et cetera, I recognize a lot of faces here. This is a more in-depth look at the badge and how you script it and kind of what the APIs are that are there, et cetera. So we saw this slide in my last presentation, right? I mean, not much to it, but the jumpers were the score, the seven-segment display, and then the OBD2 port is of interest. And you guys don't have to memorize this by any means. I mean, on carhackingvillage.com, all these presentations, the SDK, Pawn Help documentation, everything's available there for download. But I did want to just kind of run through, as far as what the jumpers are on the side, just so you can kind of get a scope of what the badge's capabilities might be. So I guess starting in the upper left-hand corner, that's the UART interface. All of these different positions on the jumper as well, you can see in the silkscreen on the badge kind of guides where all these things are as well. So the FTDI connector, which is just the standard USB to TTL UART connector that you can buy basically anywhere, goes up there. That's for the host port, which we'll talk about a little bit later. Down from that is the first output that you can control through the scripting language. Below that are the four inputs that can also be read and trigger events in the scripting language. So just some general-purpose input outputs to whatever you want to interface to. But the last four segments are basically how you select what OBD2 interface pins you want to use. So by default, the badge is populated such as using high-speed CAN. The micro only has one CAN controller, but we support three different CAN interfaces on the OBD2. So the jumpers are the way to basically tell the badge which CAN channel you want to listen to. So the first two you could have either the purple or the light blue, it's one or the other. So if they're up on the purple one, you're going to use a single-wire CAN transceiver. So that comes out, I believe, on pin one. And now you can talk over the GM stuff. If it's in the blue position, then you're using dual-wire CAN. So what that's going to do is that's going to route the CAN channels or the CAN lines from the micro out to the dual-wire CAN transceiver. The bottom jumpers basically select which dual-wire CAN interface do you want to use on the OBD2 connector. By default, the bottom ones are populated because we're using HS CAN on pins 6 and 14. But if you're on a forward and you want to look at the medium-speed body bus and see things going on in there or do other things, instead of populating on position D, you can populate on position C. So it's flexible. I mean, you can't, obviously, you can't control this in software. But as somebody pointed out, with a little bit extra hardware and using the GP outputs, you could easily do some sort of MUX-D-MUX thing there to switch this dynamically with the script. So this is basically what I just talked about, right? But I put it in here just for reference when you go back through these slides later. So what is PON? So PON is the scripting language that I chose to put on the badge. And these are kind of like the highlights from it, right? So it is C-like, which we'll see. And it's compiled, but it's interpreted on the device. The language is really designed for scripting embedded targets. However, I have heard things that is used in the desktop world as well. I think it's used as part of the Half-Life 2 engine, the Half-Life engine, to do scripting for mods, et cetera. So as you search the internet for PON, you'll come across IDEs that are out there. Those are kind of really set up for Team Fortress and stuff like that, so they kind of have their hooks in there. But some of those IDEs, I mean, you could use to do this with as well, right? You just have to know the APIs that are specific to this badge, which we'll talk about. I think interpreted language is allowed for safe. PON is very fast and efficient updates to the embedded system, safe in the sense that there really aren't any types, right? So you don't have to worry about stuff like that. All the details as far as how to set up the CAN controller and send messages in and out and handle interrupts, all that's taken care of for you. So what you get in this PON environment is a very high-level mechanism for sending, receiving messages and doing other things that embedded systems typically do. I think it's easier to write than traditional, but a programming paradigm is for the reasons I just talked about, right? So as you'll see, some of these scripts that do some meaningful things are usually about six lines, tens lines long, right? And you can get a lot done. PON is open source. It was created by this gentleman, which I'm sure I'll pronounce his name wrong, Theadmir. And I have the link here as well for future reference. If you go to this website, you'll see all of his documentation, which is excellent. He did a great job documenting his creation, talking about how to use it, examples. The documentation is absolutely great. It's more than just like an API document would read it. He gives a lot of motivations for the choices he made, and he talks about compromises that he made when he designed this language. So I think the documentation is absolutely perfect. Just some high-level differences. And as you guys and gals dive into PON, this is just stuff that I listed here off the top of my head. But I mean, one of the big things, semicolons are optional at the end of statements in PON. If you put them there just out of habit, which I do, it doesn't hurt anything. You don't have to have them there. There's really only one type, and that's kind of referred to as a cell. On this target, it's a 32-bit quantity, right? So if you make an array, every element in the array is 32-bits long. The tag itself has the capability to, I'll look back through here, but it's about 20k worth of RAM that's allocated towards the PON side of things. And I felt like with that, you can do a lot with that. Even though there are four bytes in size and you might have bigger arrays, you should still be able to get a lot of stuff done. There are some new keywords, which we'll touch upon. It does support structured data, but not in the traditional, like, struct fashion that C does it. It basically uses named elements and arrays. So you can assign tags to array positions. So when you look at the code, it does kind of look like how you would get at C structure elements, but it's a little bit different how you have to set it up. There's no linking phase with the PON compiler. So if you have a script that spans multiple files, you have to pull them all together using includes. No function prototypes. And in this implementation, the badge implementation, there's no dynamic memory. So if you globally allocate an array, if you're going to use it across functions, if canned messages are coming in, you can use that data there. But once that function returns, that data is gone unless you copied it someplace else, et cetera, et cetera. So when we look at what PON is with the badge, by its PON by itself, it's basically the language, the interpreter, the compiler, and some standard libraries that support core operations. That's part of the PON package that you can download. It's freeware, et cetera. But really where PON shines is you can easily extend PON with these native extensions. And this is what's been added for the badge. So there are things, there are extensions that you can get to that look just like function calls, for the most part, that allow you to do things like sending canned messages and setting timers and doing stuff like that. The way I like to think of it is the badge provides this library of things you can do. And PON is the thing that glues the application. It's the application that glues it all together. So QCM is, I put this in here because you'll see references to QCM on the badge itself. There's a rev and there's a part number, stuff like that. For lack of a better terminology, a while ago, I just came up with this idea like these quick can module, which is kind of, I don't really like it too much, I guess. But it's, it works. It's just an acronym. And this badge is actually a mini version of this product suite that I have. The more advanced versions of these things, and you could talk to me about them if you're interested in them. Add things like Wi-Fi and multiple can interfaces so you can do easily can gateway functionality, runs three times faster. So if you're gatewaying can messages, like it's literally microseconds of delay between messages passing through back and forth. The badge, you could use two badges to kind of do that, but it won't be as fast. And it won't be as feature-rich as some of these other things. So the classic place that everybody starts, Hello World. So this is a fully compilable Hello World script. And basically, you can see that it looks like C, right? There's a main. And they use brackets to denote blocks. And they have a built-in function that's called printf that's just like C, no semicolons. And basically what this does is it calls this native extension called QCM console enable. What that does is that, and I'll talk about it here in the next slide a little bit more, but it basically allows the script to output through the UR port, right? Because by default, the UR port is set to reprogram scripts. Well, you got to tell the engine, I want to take control of it so the scripts can do that. And then just to clean up at the end, we disable it, that's optional. So as I mentioned, scripts control the port's destiny. So if you want to do UR-based IO with the scripts, you've got to tell the QCM system, I'm going to use a UR port, and that's how you do it with the QCM console enable. But the big thing is once you call that enable call, it's not going to pay attention. The badge is not going to pay attention to scripts trying to be loaded onto it anymore because the script itself has control of the UR port. So what happens if you call enable, but you never call disable, can you never program the badge again? Not the case. So there's up in the top corner of the badge, there's a jumper that up in the top right-hand corner, select script clear when present, which is also switch input. So when that jumper is closed and the module, if you just like tweak the battery so it resets, it will not run the script and stay in loading mode. So if you have like a script that's blocking access to be able to be reloaded, this is the way to recover it. Right, it's just an easy way. The rest of QCM modules have a switch on them, which is a little bit more convenient because you just apply power while you're holding the switch and then it'll just default into the loader mode. So I mentioned before, and I've mentioned it to several of you guys, you know, the SDK is out there. Basically, the SDK in itself consists of two utilities. This compiler, the PON compiler, and this loader, the thing that allows you to load scripts onto the badge. It has some PON include files, which are where all of these QCM extensions live, right? It has several examples, which will go through some excerpts from those. And there is some documentation that's in there as well from the PON website that talks about, there's a great getting started guide for PON, and then there's like the language reference guide. They're both really good to come up to speed quickly on the language. You know, there's no fancy IDE right now besides the ones that might be for some other implementation of PON. So, you know, use your favorite text editor, create scripts, you know, maybe someday there'll be a specific IDE for it. But for now, it's just as simple on a command line. And I can give demos of this back at the village. I didn't bring my stuff here to do it. But, you know, in the SDK, I'm gonna invoke this thing called PONCC, and I'm gonna pass it a script that's hello world dot P. All the PON stuff ends with a dot P. At least that's the extension that I've always used. And when you run that, now you result, the resulting file that comes out is this hello world dot AMX, which that is the compiled PON binary that's gonna be sent to the module or to the badge. So, once you have this AMX thing, there's the second utility, this QCM loader utility, which you'll see in the SDK. And as I mentioned, we'll give examples of it where we call it and we basically give it the hello world dot AMX and you run that, you'll see output that says loaded it to the badge and kaboom, you're good. There is one option, it's this dash C option. It's mainly there for convenience. So, when you have the dash C option there, basically what that does, it keeps the, in the QCM loader utility, it keeps the port open so that if you're using printfs, it just is there. That way you don't have to like load the script and then, you know, once that's done, open up a different program like Terra Term or some other serial terminal program to CIO. It'll just do it right there. So it's kind of convenient. So we'll get a little bit further into like pawn fundamentals here. I really like how pawn handles this concept of event handling. Basically, you know, when you look at an embedded system, you know, you have interrupt handlers, you have things that are always, the application is always responding to stimulus. The user pressed a button, a message received, something changed, a timer expired, et cetera, et cetera. You know, traditionally, I mean, you could either pull for them or you can set up, you know, interrupt handlers and you can have all this logic to do this stuff. The nice thing about pawn is it has this built-in concept of these event handlers, things that will seemingly be called asynchronously when these types of events occur. They look a lot like functions, but they just have a special name and we'll see here what they look like. So just keep this event handler thing in the back of your mind. You're gonna see some here coming up in these examples, this next one. So, you know, there are basically, you know, a core set of functionality that is exposed to pawn. The first one, the first fundamental one is timers. In the embedded system, you gotta have a timer, right? I gotta send a message every 250 milliseconds. I have to change the GPIO port pin every 500 milliseconds. I gotta get an event, wait one second and do something else, right? So, the badge supports five timers. Two modes. You can either be a one-time timer or it can repeat over and over again. And the way the code looks, again, you'll see the main, but you see this other function up here now. It's called timer zero and the SDK talks about, you know, the special names for these things. But what this says is, if we look at the main first, we call this function called timer start. We tell it we wanna start timer zero. We tell it the number of milliseconds and then the last thing is, do you want it to just be a one-time timer or do you want it to go off all the time? You know, so when 250 milliseconds goes by, it restarts itself and you'll get an event, you'll get an event, you'll get an event. So what this says and how this is gonna work is, you know, the second you call QCM timer start, that timer's gonna start and that event handler at timer zero is gonna run when that timer expires, right? So think of them as like event handlers are, they're your functions that have a specific name that seemingly get called somehow, right? The system calls them when these events occur. So very simply when the timer expires, you have inside of timer zero, it prints timer expired, right? Very, very straightforward, I think. When we start looking at GPIO, this is the other core functionality, right? So we're gonna have timers, we're gonna have GPIO, we're gonna have CAN, right? GPIO, the badge has four output channels and it has six input channels. When we look at like output functionality, they can be driven higher low from the scripts. Inputs, there are two ways you can read inputs. You can either pull for them, right? Through a function to say, hey, give me the state of this input or you can set up those event handlers that I was talking about to where you specify, hey, I wanna be, I want an event every time this GPIO goes from low to high or do you want an event every time it goes from high to low or any time it changes, right? You can call these event handlers or the event handler be called. They aren't debounced so if you're trying to do stuff with your hand, right? You're gonna see a lot of events come out, right? But that's kind of intentional because I want the GPIOs to respond as fast as possible to be as flexible as possible. So if we look at another quick example here, again, I always start with these scripts, I just look at main first because main's gonna run and once main falls off the end, the pawn is kind of in this idle state waiting for events, right? So typically a lot of the example scripts you'll see in the SDK, all main does is it sets up what you want set up and then everything else is handled by event handlers. Now main can stick around, you can call a built-in routine called sleep inside of like a wow loop or something like that so that it allows the other stuff to do what it needs to do. But what's happening here is there's this call way at the bottom to say, let's configure this GPIO handler and what handler do we wanna configure? Well, we wanna configure this input OBD2, right? And we just wanna know any time we get an event. So event all means any time it goes from low to high or any time it goes from high to low, right? And what we'll see here is every time you plug in the OBD2 connector, that event's gonna be called, when you unplug the OBD2 connector, that event's gonna be called, right? And all this event handler does up here, this at GPIO input OBD2 is it does the pull mechanism, right? So if let's get the input OBD2, if that's high, well, we know there's a voltage there and it's plugged in. If it's low, well, we know somebody unplugged it, right? So all the inputs you can set up this way, right? So like if you wanted to watch all six inputs that are available, you'd have six inputs, the six handlers up here to do what you need and you'd have six GPIO configure handler calls down there to set them up the way you wanna set them up. So when we talk about the UART that the script can do, we've already seen printf, right, that output stuff, but there's also an event handler there to process data received on UART. So it is buffered and basically the way that it works is you basically just define in your script, you just have this at host, Rx, the event handler, the native stuff will see that and it will just say anything I receive on UART, I'm gonna direct to this. So, you domain, we enable the console because we have to and then this routine here, basically we get past the data that we got and we get past the size, right? The data is an array up to 16 bytes and data size of course tells us how many bytes we got and all this does is it just prints out what we received in hexadecimal format. Excuse me. So we get into can interfaces. Three ways to get can messages. So we can tell the system we're interested in a specific can ID. Excuse me. That's the recommended approach because it filters out a lot of messages coming through, right? Like if you look at a high speed HS can bus over OBD2, you might see a flood of messages. So that leads me to the next one. You can also set this up to receive all the messages on some vehicles that might be a problem for the reason I just mentioned. Other vehicles have a gateway between the OBD2 connector and the actual internal bus. In that case, it wouldn't be a problem turning on all received messages because you really aren't gonna be getting that much stuff back. Then of course you can use both. That's the third way. You could have some of their specific IDs and you could have some that you could have the catch all handler that catches everything else, right? So when we look at this, again, starting with main, there's a function. When you look in the SDK, you'll see it. It's called QCM candidate. We tell it the bar rate. Okay, well we wanna open up the CAN channel at 500 kilobits per second. And then just like what we saw with the GPIOs, there's another call that's CAN configure RX handler. It looks like the GPIO configure handler. We tell it what handler we wanna use. In this case, it's handler number zero. Hence why we have the event handler up there that ends with zero, CANRX zero. There are, I believe there are eight. You can have up to eight handlers, eight or 10. I'll have to look at the documentation. But what this is saying is, okay, well let's set up this CAN handler for handler zero. We're interested in ID hex 70 zero. And the last false means it's 11 bit. Is it extended? Is the last parameter? So as soon as main falls off the end, the system is configured and it's just sitting around waiting for the at CANRX zero event handler to be called. And as soon as we receive a 70 zero, kaboom, this gets called and my test code inside of here basically just prints out the fields. And this is what I was talking about, structured data. So there's this thing that looks like an array, this RX message, but it has this capital QCM CAN message inside of it. If you look in the SDK include directory, you will see the definition for this QCM CAN message that sets up the structured data for this RX message. And you can see in the print app when we actually get into that structured data, it looks a lot like C, how we would do it. So it's rxmessage.id, rxmessage is extended, rxmessage dlc, which is the link of the message on the CAN bus. We loop through the data because that's an embed, there's a member inside of QCM CAN message inside of the rxmessage that basically is an array of all the data that came in the message and we print it out. And then just as part of this test, we change the id to 78 and we just transmit the message to back out. So that's what the QCM CAN TX. As soon as you call QCM CAN TX, it sends it, right? So you could see it's pretty easy if you wanted to just set something up that let's say we wanted to reverse this where we make a diagnostic request to 70-0 and we're interested in the response, say, on address 78. Well, the way that we would modify this is we would set up our rxhandler for 70-8 because we're interested on that message coming back and then we would just transmit the message that we want as soon as the engine responds, we would get it and we would process it, right? To reverse this example. This is kind of like from the perspective of the other side. So one of the last things I wanted to talk about, there's another extension that I, to see, I think, is pretty important to talk about in regards to PON because PON is basically designed for embedded systems. It has this concept of built-in state machine automation. And the way that it works is, you know, we saw these event handlers up here like CAN RX-0 and stuff like that. The way it works is you can define several of the same event handler, but tell it in what state you want that event to be handled. So you could have, here's an example where let's just do a PWM signal on a GPIO. So we start a timer, timer zero, 250 milliseconds, only this time we pass it true because we want it to just run all the time. And then we use this PON built-in keyword called state, which means set the state to what I'm gonna tell you. So we're gonna initialize the state to the state called PWM low. And then you'll see in the event handlers above for timer zero, there are two of them. And the first one has this construct after it that says PWM low. And the next timer zero one has this other construct for PWM high. So what that means is if the internal state machine is in the state PWM low and you get a timer zero event, it's gonna call that top one. If the internal state machine was in this state called PWM high, which you can just make these state machine names up. I mean, the state names on the fly, right? The compiler knows how to deal with them. It will call the PWM high one if you're in that state. So you can kind of see here what's gonna happen is timer zero is gonna get called first because when that timer expires, it's gonna set the output to false and then it's gonna set the state to PWM high. And because the timer is repeating over and over again, the timer's gonna go off again in 250 milliseconds. Well, only now we're in the PWM high state. So the PWM high timer zero handler is gonna get called. So on and then it sets low, so on and so forth. That's basically how you've seen how I have the scrolling stuff coming across here. I just have a lot of timer zero events set up at a certain interval and with states and it basically just walks through and sets the LCD accordingly for every time that expires. So it's kind of a good thing, like if you wanted to handle message sequencing, so you send a can message and you're going to get back, you send a can message and you set the state, you're gonna get back a response that you're gonna wanna process in a certain way. Let's say it's on a specific ID, you're gonna send something else back out and you're gonna get different data but with like the same ID. Well, you could just have different states for that can handler, so on and so forth. So it's just kind of a way to automate that. I wanna see something here, okay. So I was actually gonna open up, I was just gonna open that up here real quick and I was just gonna show you the example that this badge is using to show that data. So basically what you'll see in here is, this again is in the SDK, how to control this LCD. I copied it here for my reference but there are several of these at timer event handlers for every single state. And by far, this isn't like the most efficient way to do it at all, like you could set up an array that has the characters in it and walk through, et cetera, et cetera, but this was fast to do. So first state is C-A-R, those binary things, if you look at the SDK, that's controlling the individual segments so that car shows up. The next one comes in, it shifts it one over, it says A-R and X I use for space and then I set the next state. Next state is R, space, H. The next state is space, H-A, the next state is H-A-C, so on and so forth just to achieve the scrolling effect. So there's a lot of these timer zero event handlers, one for every state. And way down here in Maine, I initialize the state to the first one where it starts with the word C-A-R or the letter C-A-R and then I set up the timer to run every 250 milliseconds and just walk through. So it's kind of like the, so as you learn more about PON and dig into it, you'll see that there are things that can be turned on or off depending upon how PON is being used in the system. And these are choices that I've made. I have enabled floating point, so because I thought that that was pretty important because a lot of messages, a lot of data that comes over can might be expressed in a certain unit that you might have to multiply by some factor in order to get what you actually need. So like miles per hour might be expressed in kilometers an hour, but it's offset by a certain number of bits so that they can do fractional values over the bus. If you have floating point built into the script, it's very easy to do that. You don't have to do any integer mass shifting, all that other stuff. You can just multiply it by a factor and just be done with it. As I mentioned, there's no dynamic memory allocation. Almost all the core PON stuff is there, so as you read through PON, you'll see a lot of these native routines that ship with stock. They're almost all there, except like a couple of stringier routines. I didn't think it would be useful to have like the UU encode, UU decode routines in the target, so they're just taking up space, got rid of them. Unix time stamping, stuff like that. They also have some socket stuff where you can send UDP in like the core example. Obviously it doesn't apply to this at this point. When I mentioned the sleep, there is a sleep routine that can be called in the main routine to kind of like allow event handlers to run. And I'm basically using the latest version of PON that you can find out there. And it's actually a little bit more than that because I have other contributions that have not been accepted back into the core edition to work around some bugs that I've come across when using it. So it really is kind of like the bleeding edge of PON that's inside of here. I mean, PON isn't used in a lot of places, but there were some real showstopper bugs that would not make some of those examples even possible, right, without these fixes. So as I mentioned, look in the SDK downloaded carhackingvillage.com. You will see, it's structured very well. You will be able to go and find your way. I will be available at all times throughout the con back at the carhackingvillage. Come and talk to me. We can write scripts. I'll show you how to load them. We can go through all of that stuff. I basically listed a couple ideas because some of you might be like, okay, well, this is great. You know, we could script this thing. You know, what are we gonna do? Right? You know, we saw a script that waits for OBD2 to be connected. So, you know, let's use that to our advantage. So like, maybe let's use a script that waits for the OBD2 to be connected, then listens for some particular can message and shows it on the display. So like, let's say we wanted to show vehicle speed on the display. Would be very easy to do on a lot of vehicles, right? You could make a simple can diagnostic tool. That basically just dumps over the UART can messages of interest, right? So it's a way to just, you know, make like a can sniffer. Because the scripts are persistent and you know, they're stored when you remove power, of course. I mean, you could program this thing too as you plug it into vehicles, you know, do some diagnostic stuff, query something and send it over UART or figure out something to set and set it on a lot of things or, you know, things like that. You could wait for data on the can bus and then resend that data but format it a little bit differently. And depending upon your timing there, you might cause the vehicle to do things that you want it to do, not what it's going to do. Example of this might be, you know, you just saw the speed message come over the can bus, change the speed and send it out immediately. I mean, it's going to be sent within, you know, under a millisecond. So the things that are paying attention to speed are going to see that first message but they're also going to see your message and they're probably going to take your message over the one because they always take the latest data. So if you're always triggering off of a can message and you're always resending it immediately afterwards, you can alter what the vehicle might display or do. An interesting one would be, you know, let's link two badges together and make a crude gateway where you could actually interrupt, you can cut the can bus, put one listener here and a transmitter over here, maybe make it bi-directional so you can actually, for the notes that you can't just repeat data, you want to intercept something that's being sent and you want to modify it so that something else, you know, believes what's not really true. Two badges could be used to do that. You know, a potential example might be, you know, a lot of OEM head units won't, that could play DVDs, won't play them if the vehicle's moving. Well, they're paying attention to the speed message and maybe it's not enough to just retransmit it. Maybe you actually have to intercept the speed message, modify it and retransmit it but let everything else go through. You know, you could use two badges to do that, you know, link them together over UART, couple scripts on each side, bang, it's done. And you know, of course, you don't have to use the OBD2 interface on the badge. I mean, you have some IOs, you got UART, you have a display, interface it to something else and you know, use PON to your advantage there as well. So, you know, as I mentioned, feel free to grab me anytime. I put my email address in here, you know, if you guys want to spam me with stuff, it's easy to set up filters. And you know, I'm curious to know about your badge experiences, so come and tell me or, you know, feel free to post up to Twitter, you know, to CHV badge and share your experiences but I guess I'll just open up for questions. I mean, I just kind of wanted to give a high level overview as far as, you know, what the system is, what it can kind of do, you know, until you get in and actually play with it a little bit it'll probably become a little bit more concrete but any questions? How do you get it? Carhackingvillage.com, which I think I mentioned in here. You can download the SDK there, that's where it lives. And the badges, if everybody doesn't have them, we sold out this morning, we will have at least 80 more for sale tomorrow starting at 10. So you have another chance to get them. They are 50. Yes, say again. I would attend some of the other turbo talks that we're doing back in the village. There are some talks that address exactly you know, what you're talking about. We go through some CAN bus examples, we talk about, you know, the types of things that you can do over OBD and what that looks like and what CAN messaging looks like, you know, the whole concept, right? If you're familiar with like, you know, traditional networking, depending upon your level of familiarity with it, you'll probably find CAN bus to be about 20 years behind that. It's a very simplistic messaging paradigm and you know, you'll catch on to it very fast because there are some methodologies that all the manufacturers use to transmit data back and forth and there are some standards in place but when it all boils down, you know, I like to think of CAN, it's kind of like UDP to a certain extent where it's a fire and forget type bus and there's a fixed payload and the receivers get it and that's how it goes, right? I mean, it's pretty simplistic but yeah, grab us, come to more turbo talks. We'll bring you up to speed. Yes, yes, when you download the SDK, they're in there, everything's there. Oh no, okay, well, we're repeating stuff tomorrow as well. I think all the talks get repeated tomorrow and all the slides should be available someplace as well for that and if you're really interested, just come by and grab us. I mean, we'll just go through it with you. I mean, we wanna, we wanna awareness, we want people to be able to learn, we wanna show people, I mean, we really like this stuff. Everybody involved with the village and we're more than happy to share it with you, the knowledge, bringing up to speed. I mean, that's the whole goal here, right? So, yes, there is. When you come back to the village, there's a company there called Intrepid Control Systems. They make what I think is pretty much the flagship. I mean, it's a really good program to do this. The problem with it is, you know, it is a high-end engineering tool so I think they have options to get lower cost versions of that, perhaps even free versions of it that are limited but we can show you those tools back there and how they work. It's really a feature-rich program that allows you to do a lot of stuff. You know, you can find, you can find, you know, canned dongles out there that just dump stuff. You know, this badge, you could turn it in to something like that, as I mentioned. I mean, it has a UR port on it. But as far as like cheap, I've seen canned dongles out there for not expensive. Now, you aren't gonna get a lot with them but yeah, exactly. That's where Vehicle Spy excels, of course, but other ones, we'll have to talk to the guys back there to see what their experiences are too. I always use Vehicle Spy, personally, but you have to use one of their dongles though in order to utilize it. I mean, the badge doesn't work with their software, of course, but I think you can get in, I'm not sure what the value cans run now. They have like a value can limited. It might be, and don't quote me on this, it's probably on the order of a few hundred dollars, 200, 300, something like that. Yeah, it's more limitation of bought rates. So, you know, traditional high-speed can buses in vehicles are running at 500 kilobits per second. It's a lot of data going back and forth. The UART on this is fixed at 230, 400, right? So if you're translating this binary data into like ASCII data, and then you're sending out can frames, obviously there's gonna be a bottleneck there, right? It can't get all the data through. But if you're selective, as far as, you know, what range of IDs you listen to, if you put just a little bit of filtering in there, you could use this, like let's say you could, you could put something in there that sends all the messages that start, that are like, you know, 5XX, so 500, so and so. That might be sufficient to open up the bandwidth so that you can, you know, dump that stuff to like a terminal using printf. So that's the, what I was kind of getting at there. Any other questions? Okey-dokey, well thank you guys, and I look forward to seeing you back at the village. And as I mentioned, feel free to grab me, if you have any questions. Thanks.