I'm continuing to play with the CAN network available on the OBD2 port located under the dash to hopefully reverse engineer its capabilities. Click here for my previous posts on this.
I have started to play with the 30 service as outlined in ISO-14230, which is the InputOutputControlByLocalIdentifier service. Another the370z.com forum user sent me logs of his Consult-III clone software controlling the door locks. It used the 745/765 (send/receive) CAN addresses to control the locks and the 30 service as expected. Therefore, the 745 address must be for the BCM (Body Control Module), which is the module that controls just about everything you interact with in the car on a normal basis. So I wrote a program to snoop out which addresses the 30 service could use. To do this you first have to enter the correct diagnostic mode in order for the car to allow you to make changes. The following command does this:
745 02 10 C0
745 is the CAN address we are sending the command to, 02 is the number of bytes in the packet, 10 is the StartDiagnosticSession command, and C0 is the session we need for the 30 service.
Then we need to poll the 0x00 address to see what other addresses are supported:
745 02 30 00
745 is the CAN address we are sending the command to, 02 is the number of bytes in the packet, 30 is the InputOutputControlByLocalIdentifier service, and 00 is the first address we are testing. This command will return a response like this:
765 05 70 0D E7 92 51
765 is the response CAN address pair for the 745 address we used (745 + 20), 05 is the number of bytes in the packet, 70 is the response to the 30 service (30 + 40), and the last 4 bytes are a bit field that tells you which of the next 32 addresses are supported (one bit for each address from 0x01 to 0x20). The order is from most significant bit to the list significant bit. The last bit tells you if there is another bit field to retrieve. In this case there is, so you can send a request to get another bit field from address 0x20 and keep going until you run out.
In my 370Z, I could query all the way up to 0x60, so that's gives the possibility of 124 items to control. However, only 52 returned a '1' to indicate that they are supported. Once you know which addresses are supported you can change the state of many things in your car with a command like the following:
745 04 30 05 00 01
The first 3 parts we are familiar with now, 05 is the address for the door locks, 00 is a control parameter that determines what you are trying to do, 01 is the state you want to put the control in to. There seems to be 2 options for the control parameter that make changes happen: 00 or 20. 00 seems to make a brief change, kind of like pushing the door locks button briefly. 20 makes a permanent change like turning on the luggage light. Regardless, most commands take 20 as the control parameter, but some take 00. They won't work if you use the wrong one so you can't screw it up.
The last byte is different for each address, but is usually 00 or 01 for Off and On. Some have more values, such as the door locks, which can be All Unlock, All Lock, Driver Unlock, Passenger Unlock, etc. My dropbox spreadsheet shows all of the items I identified on the BCM PIDs tab. One last important note is that I was unable to just hop from address to address changing items as much as I wanted. I had to exit the C0 diagnostic mode and then return to it before I could change the next item. That is accomplished with the following 2 commands:
745 02 10 81
745 02 10 C0
That will jump back to the default session and then back into the diagnostic session. I think this just stops too many things from happening at once to make diagnosing problems easier. It would be easy to change a lot and then think something is wrong because you messed with so many items. I'll keep sharing my progress as I go.
This is a departure from my usual electronics projects, but I want to share anyway. I read an article a while back about how clocks evolved into what we use today. The escapement mechanism is what makes them possible. In the middle of reading about escapements I came across webpages dedicated to building old school wooden clocks. I'm an electrical engineer, but something about this fascinated me. The name Clayton Boyer came up many times for his clock designs. I found his site and thought it would be a fun project to buy one of his plans and build a wooden clock with nothing to drive it except a weight and pendulum. Not a single wire, battery, or motor.
I chose the Genesis clock plans because it was touted as the world's easiest clock. I bought the CAD version because I have access to a plotter at work and knew I would screw up a few times along the way. I printed out the plans, bought some nice Baltic birch plywood, and started cutting out the parts. It's easy enough to glue the plans on to the wood, but cutting out the individual gear teeth is a very tedious process. However, it's very rewarding to start with a board and end up with a mechanical device that works. Below is the escape wheel and the winding pulley.
After cutting out the pieces I sanded and filed them into their final shapes. Then I assembled everything to test their fit. Only a little sanding and filing was needed to get it spinning nicely. The next step was assembling the weight and counter-weight. The main weight is just a glorified copper tube filled with lead shot. The counter-weight is just a hollow copper tube to keep the weight line taught. Once the weights were attached I spent quite a bit of time getting the escapement mechanism working correctly. I even scrapped one and made another because I sanded it down too much. I got it right eventually and the clock was running on its own.
Next, I cut out and applied the numbers to gears. I didn't bother staining anything because the natural white wood looks nice. I did paint the numbers with some tea to darken them a bit to match the wood. Here's a shot of the final product.
I don't plan on making another one, but it was a fun project. Plus, it's a good excuse to buy some new power tools and cut some stuff up.
I picked up my 370Z CAN hacking project again after others expressed interest on a 370Z forum I frequent. I ported my old VB6 project over to VB.NET and created a few more tools to help. I've also added standard OBD PID polling to use that info to compare with Nissan's custom CAN data. I updated my CAN spreadsheet with new items and corrected a few others. I always keep the latest copy with the latest CAN information I've decoded on my Dropbox here.
Then I started looking into how to get to the undocumented Nissan PIDs. Various websites give bits and pieces of information, but a lot of times they're for different makes or models and nothing seemed to work with my car. Then I came across Swedish Implementation Standard SSF-14230. It relates to vehicle CAN systems and implements ISO-14230 that we use here in the US. You can find free copies using google. It outlines several of the protocols and commands used to access various parts of the CAN network. I was really interested in information on service 22, which is readDataByCommonIdentifier. Others had used this service successfully on Ford and GM cars to access their custom undocumented information.
This service works similarly to service 01, which is used to access the standard PIDs. However, this command takes 2 bytes for the address. This means there are 65,656 possible pieces of data ready to be accessed. The command structure is as follows:
7E0 03 22 XXXX
7E0 is the CAN address for the ECU, 03 is the number of bytes that follow, 22 is the readDataByCommonIdentifier command, and XXXX is the PID that you are requesting from the CAN node. However, sending this message returns the following error message:
7E8 03 7F 22 80
7E8 is the standard reply address from the ECU (7E0 + 8), 03 is the number of bytes that follow, 7F signifies a negative response, 22 is the command I sent that failed, and 80 is the error code for "Service Not Supported In Active Diagnostic Session". This means that the ECU recognizes the command, but the ECU needs to be placed in a different mode in order to act on it. I started researching diagnostic sessions and found there are 256 possible sessions. So I wrote a routine that automatically tried to place the ECU in every single diagnostic session. The command to place the ECU in a diagnostic session is as follows:
7E0 02 10 XX
10 is the startDiagnosticSession command and XX is the session you are requesting. Only 6 diagnostic sessions succeeded: 81, 85, C0, DA, FA, & FB.
I put the ECU in each diagnostic session one by one and tried to send the readDataByCommonIdentifier command from before. I received the same 80 error code for all sessions except for one: diagnostic session C0. Unfortunately, that response gave me a 12 error code. That means "Subfunction Not Supported or Invalid Format". Basically, it recognizes the command, but the parameters I sent with it (the 2 byte PID) are either unknown, not supported, or in an invalid format. That is the most vague error I've ever seen! It doesn't give you any kind of hint on how to fix the problem. I tried all sorts of different formats, added bytes, etc. but kept getting the same error. So I decided it must be in the right format, but there's just no information for that particular PID. I wrote another routine to try every single PID to see what I got.
After letting it run for an hour or so I looked through the logs and found lots of responses. I finally found Nissan's custom PIDs! 224 of them to be exact. I added the full list of supported PIDs to my spreadsheet and I will start trying to decipher them when I can. Please let me know if you are interested in helping. There's a ton of information to go through.
One other hiccup I ran into is that the ECU will drop out of the special diagnostic session and revert to the default session if there is no activity for about 3 seconds. The following command can be sent about every 2.5s to keep the current session active:
7E0 02 3E 01
Command 3E is the "Tester Present" command that lets the ECU know that a tester device is plugged in to the OBD port and to keep the active diagnostic session going. I added 01 to the message because it kept giving me a 12 error (just like I talked about above), which meant I needed some sort of parameter with it. I tried 01 and it responded with a positive response, which is good enough for me. The positive response looks like this:
7E8 01 7E
7E is the response to command 3E (3E + 40).
My LED Bar project uses an Arduino Duo to process button inputs, take analog readings, update the LCD display, and control the LED strips. That's a lot for a little microcontroller to handle and by the time I had all my features finalized I ran out of pins. All I needed was one more pin for a button input from the control panel. There are many ways to solve this problem depending on your project. However, one of the other buttons was already connected to an analog-to-digital converter (ADC) pin on the Arduino, but only using its digital input functionality. So I came up with a simple circuit to take both button inputs on this pin:
The microcontroller pictured above can be any microcontroller, not just an Arduino. When no buttons are pressed the bottom 10k resistor acts as a pull-down and the microcontroller sees 0V. When the left button is pressed 5V is fed directly into the microcontroller. When the right button is pressed it creates a voltage divider and splits the 5V in half, giving 2.5V. Unfortunately, if both buttons are pressed the top resistor is shorted out and it will look like only the left button is pressed. So it's a good idea to either pick two buttons that are not likely to be pressed at the same time or put the most important button on the left side.
In your Arduino project, just throw an analogRead() command in your main loop and use the result to determine which button is pressed. For the example above, the analog reading will be 0 when no buttons are pressed, 512 for the right button, and 1023 for the left button. These values are very spaced part, which makes for a very reliable circuit. I used the following ranges in my code to determine which button is pressed:
No buttons pressed: <256
Right button pressed: ≥256 and ≤768
Left button pressed: >768
Analog readings take much longer than a digital input reading, but my project is not time-sensitive and still responds instantly. In fact, I had to put in a timer scheme similar to debouncing a digital button input to prevent multiple hits on a single button press. This circuit isn't groundbreaking, but hopefully it helps someone out there if they run out of Arduino pins.
Adding More Buttons
The following circuit expands the first example to 4 buttons. You can expand even further, but eventually you'll hit a limit where temperature variations and resistor tolerances will cause unreliable readings.
The ADC readings for the above circuit are as follows:
None: 0 (0V)
Button #1: 255 (1.25V)
Button #2: 511 (2.5V)
Button #3: 769 (3.76V)
Button #4: 1023 (5V)
Simultaneous Button Presses
The following circuit expands the first example to add the ability to detect when both buttons are being pressed. The tradeoff is that the ADC values are closer together, but this shouldn't cause problems.
The ADC readings for the above circuit are as follows:
None: 0 (0V)
Left Button: 393 (1.92V)
Right Button: 511 (2.5V)
Both Buttons: 633 (3.1V)
As you can see, there are many ways to hook up multiple buttons to a single ADC pin. There are many other methods as well. For instance, you could use the internal pull-up resistor instead of the 10k pull-down resistor I used in my examples. The resistors could also be in series for each button so that different buttons engage different numbers of resistors, creating the effect of adding resistance. Experiment and search around online to find the best solution for your project.
Now that the LED Bar is installed and fully functional you can see it in action. These videos show off a few of the LED Bar effects. The first video shows the random shot routine. You just press the red random shot button and a crazy light show starts until a shelf and color are selected. This color matches colored wristbands on each of the bottles. Once it stops you take that shot.
This video shows the sliders in action. There is a red, green, and blue slider. Each one mixes in that color so that any color can be created on the bar LEDs. The demo just shows the panel, but the lights shine off the wall in the background.
This last video shows the flow effect. The colors change randomly and mix in to the next one. Sync is turned off for this video so the two shelves are different colors.