pgmfi.org

Hacking up Honda's ECU
It is currently Fri Mar 29, 2024 3:24 am

All times are UTC - 5 hours [ DST ]




Post new topic Reply to topic  [ 11 posts ] 
Author Message
 Post subject: Datalogging with C
PostPosted: Sun Jan 08, 2006 2:01 am 
Offline

Joined: Tue Jul 27, 2004 2:29 am
Posts: 474
Location: Baton Rouge, LA
I'm trying to write a program in C that will request data through the CN2 port. I currently have a ROM with John Cui's QuickDatalogger, and I am able to datalog with Cuddle and Freelog, so my hardware is setup properly.

I don't know a whole lot about doing serial communications with windows, so I found some prewritten code to get me started. Here is what I have:

Code:
#include <windows.h>
#include <stdio.h>
#define   LOOP 255

int main(int argc, char *argv[])
{
   DCB dcb;
   HANDLE hCom;
   BOOL fSuccess;
   char *pcCommPort = "COM1";

   hCom = CreateFile( pcCommPort,
                    GENERIC_READ | GENERIC_WRITE,
                    0,    // must be opened with exclusive-access
                    NULL, // no security attributes
                    OPEN_EXISTING, // must use OPEN_EXISTING
                    0,    // not overlapped I/O
                    NULL  // hTemplate must be NULL for comm devices
                    );

   if (hCom == INVALID_HANDLE_VALUE)
   {
       // Handle the error.
       printf ("CreateFile failed with error %d.\n", GetLastError());
       return (1);
   }

   // Build on the current configuration, and skip setting the size
   // of the input and output buffers with SetupComm.

   fSuccess = GetCommState(hCom, &dcb);

   if (!fSuccess)
   {
      // Handle the error.
      printf ("GetCommState failed with error %d.\n", GetLastError());
      return (2);
   }

   // Fill in DCB: 38,400 bps, 8 data bits, no parity, and 1 stop bit.

   dcb.BaudRate = CBR_38400;     // set the baud rate
   dcb.ByteSize = 8;             // data size, xmit, and rcv
   dcb.Parity = NOPARITY;        // no parity bit
   dcb.StopBits = ONESTOPBIT;    // one stop bit

   fSuccess = SetCommState(hCom, &dcb);

   if (!fSuccess)
   {
      // Handle the error.
      printf ("SetCommState failed with error %d.\n", GetLastError());
      return (3);
   }

   printf ("Serial port %s successfully reconfigured.\n", pcCommPort);

//This is where I began coding
   
   OVERLAPPED osWrite = {1};
   OVERLAPPED osRead = {1};

   int      x,
         code = 22;             //Ignition Timing
   DWORD   byteswrittensofar,
      bytesreadsofar,
      timing = 0;

   for(x = 0; x < LOOP; x++)
   {
   if(!WriteFile(hCom, &code, 2, &byteswrittensofar, &osWrite))
      printf("Can't Send Data!\n");

   if(!ReadFile(hCom, &timing, 2, &bytesreadsofar, &osRead))
      printf("Can't Read Data!\n");
   printf("Ignition Timing: %.2f\n", timing);
   }

return 0;
}


The program gets caught in the readfile function. I know this is kind of slapped together, if any of you guys know of a more efficient way for me to do this, comments are appreciated. Thanks.

--Darren


Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: Sun Jan 08, 2006 2:38 am 
Ive written some datalogging code in C and Objective-C but my serial communication was much simpler as I'm on a BSD base (Mac OS X) so I can't pffer you help in your serial configuration, but I see what might be a problem.

Maybe its cause its late and ive been drinking, but, it looks like your sending the integer 'code' to the ECU. You have code set to 22, in integer format. I believe you want 22 in hexidecmal format which is 34 in base 10. Also, I think you only send 1 byte to the ecu to and then wait for 1 byte to be returned. I haven't written C for Windows in a while, but I'm going to guess that an integer is 16 or 32 bits. Try sending something with sizeof(1) like a single char.

Everything I said could be wrong as I haven't played in C on Win32 in almost 4 years, and I never did RS232 during my Win32 days, but it might help you narrow down your issue.

Also, when you say it gets caught in the Readfile function, what do you mean? Does the program crash, does it hang? Give us some details.

I found the attached file on the forum sometime ago, its not complete, but it might help. (If you have a more updated version, or competing information please post it so I can combine all the data).


You do not have the required permissions to view the files attached to this post.


Top
  
Reply with quote  
 Post subject:
PostPosted: Sun Jan 08, 2006 3:31 am 
Offline

Joined: Tue Jul 27, 2004 2:29 am
Posts: 474
Location: Baton Rouge, LA
Good information!

When I say it gets stuck in there, the program gets into that function and just hangs indefinitely. I know it is there because I put a little printf statement above it and below it, and it only prints the one above, so that's where it is stuck. I suppose it is possible that I am sending the wrong code aswell and the ECU may not recognize it. I'll set it to 0x22 tommorow and see what happens. I'll do that sizeof thing and see how many bytes that int takes up aswell. But now that I'm thinking about it, there is no reason why 0x22 couldn't fit into one byte, so I'm probably giving the ReadFile and WriteFile the wrong parameters aswell.

I'll try it and update you, thanks!

--Darren


Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: Sun Jan 08, 2006 12:47 pm 
The communication with the ECU is not foolproof. I have a timeout on my code to read data from the ecu. Basically, I send a byte, and then poll the ecu for X amount of times to get data. If no data is returned then I send the byte again and poll X amount more times. If this happens say 100 times and nothing then I return an error saying that the connection is broken.


Top
  
Reply with quote  
 Post subject:
PostPosted: Mon Jan 09, 2006 12:28 pm 
Offline

Joined: Tue Jul 27, 2004 3:01 am
Posts: 2945
Location: Tampa bay, Florida
I ran into a problem with that method, so be sure to read/clear the rx buffer before you output the next command. also you may wish to check if the tx buffer is empty before starting your rx timeout in case it isn't done sending. most trouble will be when you deal with multi byte commands, however, so don't be too concerned. I found the best method to deal with the serial commands is to convert your decimal/hex to ascii characters asociated with the value. ie val(0x22) if c has a similar command... then send it as a one character string at a time. make sure you enable null characters as a valid response, some defaults are set up to ignore it.


Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: Mon Jan 09, 2006 12:53 pm 
What I do in my code (C based) is send it as a single char (ie: char msg[1]; and just send write( pipe, msg[0] ); ) To set the appropriate byte in the array you can do something like msg[0] = 0x22, or msg[0] = (char)32;

Don't know how much help this will be since its *nix based and objective-c (if youve done any C++ or Java objective-c shouldn't be a problem, slightly different syntax) but here is my datalogging code. If any of it confuses you send me a PM or IM.

http://cvs.sourceforge.net/viewcvs.py/pgmfi/osxeditor/datalogger.m?view=markup


Top
  
Reply with quote  
 Post subject:
PostPosted: Mon Jan 09, 2006 9:05 pm 
Offline

Joined: Tue Jul 27, 2004 2:29 am
Posts: 474
Location: Baton Rouge, LA
Correct me if I am wrong, but it seems to me that the function you use to send the data, in my case the WriteFile, is expecting me pass the address of a string to it instead of the address of an int. I looked at your code and I notice that you put the codes into the 1 position of a string, and then pass that string to the GetData function, which then has a write command like so:

Code:
write( fd, string, 1 );


what are the parameters for the write function? is the 1 telling the write function which position in the string to find the data you want it to send? Or are you telling it how many bytes you want it to send and the function automatically starts at the 1 position?

Thanks in advance.

--Darren


Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: Tue Jan 10, 2006 10:28 am 
I have lots of things to discuss based on your last post. First, almost all C commands for linux are documented in whats known as the Man pages (as in manual). Google any C command and the word 'man' to get an explanation.

http://www.die.net/doc/linux/man/man2/write.2.html

write expects the file descriptor (the port we are using, com1, com2... etc), the data to be sent as a pointer, and the amount of bytes we wish to send from the data. It does not care what format the data is in, (void *). It will simply send the amount of bytes given in the last parameter starting from the begginning.

Also, some symatics, I am not placing the hex number in the 1 position of the string. The commands at the top are creating char arrays (not strings) that are one char long, and placing command in the 0 position. In C (and its derived language) arrays of size X have locations 0 through X-1. The 1 location is actually the second.


Top
  
Reply with quote  
 Post subject:
PostPosted: Tue Jan 10, 2006 8:29 pm 
Offline

Joined: Sun Aug 29, 2004 1:38 pm
Posts: 7
Using the serial port in Windows is a pain.

First thing. Set some timeout values before attempting anything.

SetCommTimeouts is the function to look at.

Second thing. Check the result - if there's an error, check the code. FOr example, you can get ERROR_IO_PENDING - not really any error, just meaning 'no data yet'.

Third thing, it's a good idea to make sure the PC and ECU are in 'sync' as far as the comms goes. Send a handshake byte '0xab', and reading anything that comes back until you get the '0xcd' handshake reply. When you do, you've actually a pretty good chance of getting back what you expect from the ECU when you send it something. As ltdannear's said already, watch out for multi-byte commands - it's annoying common for a byte to be lost part way through. When that happens, the ECU can try interpret the rest of the bytes in a multibyte command, as commands... which generally means you'll get something back, but not what you expect.

I have good Windows serial code, but it's not something I can release. I ended up using an extra thread along with the Windows event's system to handle the synchronisation. That approach works very well - but it's far from trivial. If you're just experimenting, it's better using another language on Windows that has a decent serial library so you're spared the pain of fighting the stupid Windows comms api, and can just get on with what you want to write.

-Brian.


Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: Tue Jan 10, 2006 11:47 pm 
Offline

Joined: Tue Jul 27, 2004 2:29 am
Posts: 474
Location: Baton Rouge, LA
Yeah, I'm starting to realise how much easier it is to get a PIC chip with a built in UART to send data than it would be to configure windows for it. It would be cool to say I did it tho.

--Darren


Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: Wed Jan 11, 2006 1:10 am 
just get a mac, serial code is super easy.


Top
  
Reply with quote  
Display posts from previous:  Sort by  
Post new topic Reply to topic  [ 11 posts ] 

All times are UTC - 5 hours [ DST ]


Who is online

Users browsing this forum: No registered users and 2 guests


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot post attachments in this forum

Search for:
Jump to:  
cron
Powered by phpBB® Forum Software © phpBB Group