Development was done in C using Cygwin on Windows. This code is really just "test" quality, and may contain errors.
- Code: Select all
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <errno.h>
#include <termios.h>
#include <sys/select.h>
#include <time.h>
#define RESPONSE_MSG_LEN 128
int debug = false;
typedef struct ecu_t
{
int connected;
int fd;
} ecu;
int connect(ecu_t *e)
{
struct termios options;
e->connected = 0; /* reset in case we fail to connect */
e->fd = open("/dev/ttyS0", O_RDWR | O_NOCTTY);
if (e->fd == -1)
return 0;
else
fcntl(e->fd, F_SETFL, 0);
tcgetattr(e->fd, &options);
/* go to 4800 baud */
cfsetispeed(&options, B4800);
cfsetospeed(&options, B4800);
options.c_lflag = 0; /* No local flags */
options.c_oflag &= ~OPOST; /* No output processing */
options.c_iflag &= ~(IXON | IXOFF | INPCK | PARMRK | BRKINT | INLCR | ICRNL |
IUCLC | IXANY);
options.c_iflag |= IGNBRK; /* Ignore break conditions */
options.c_cflag |= (CLOCAL | CREAD); /* enable */
options.c_cflag &= ~CRTSCTS; /* Turn off RTS/CTS */
options.c_cflag &= ~PARENB; /* No parity */
options.c_cflag &= ~CSTOPB; /* 1 stop bit */
options.c_cflag &= ~CSIZE;
options.c_cflag |= CS8; /* 8 bits */
/* set all of the options */
tcsetattr(e->fd, TCSANOW, &options);
tcflush(e->fd, TCIOFLUSH); /* Added to flush buffer */
int status;
ioctl(e->fd, TIOCMGET, &status);
status |= TIOCM_DTR; /* Set DTR high */
status &= ~TIOCM_RTS; /* Set RTS low */
ioctl(e->fd, TIOCMSET, &status);
e->connected=1;
return 1;
}
void disconnect(ecu_t *e)
{
tcflush(e->fd, TCIOFLUSH);
if (!e->connected)
return;
close (e->fd);
}
void printMsg(u_int8_t* msg, int len)
{
printf("Message: ");
for (int i = 0; i < len; i++)
printf("%X ", msg[i]);
printf("\n");
}
u_int8_t calcChecksum(u_int8_t* msg, int len)
{
u_int8_t checksum = 0;
for (int i = 0; i < (len - 1); i++)
checksum += msg[i];
return checksum;
}
int sendMsg(ecu_t *e, u_int8_t* msg, int len)
{
int status;
int writeLen = 0;
tcflush(e->fd, TCIOFLUSH); // Added to flush buffer
writeLen = write(e->fd, msg, len);
return writeLen;
}
int recvMsg(ecu_t *e, u_int8_t* msg, int len)
{
struct termios oldtio, options;
tcgetattr(e->fd, &oldtio);
tcgetattr(e->fd, &options);
options.c_lflag = 0;
options.c_cc[VTIME] = 0;
options.c_cc[VMIN] = len;
//tcflush(e->fd, TCIFLUSH);
tcsetattr(e->fd, TCSANOW, &options);
int readLen = 0;
readLen = read(e->fd, msg, len);
tcsetattr(e->fd, TCSANOW, &oldtio);
return readLen;
}
int main(int argc, char** argv)
{
ecu_t e;
struct timeval hrTime;
u_int8_t responseMsg[RESPONSE_MSG_LEN];
int bytesRead;
if (debug)
printf("Opening serial port\n");
if (!connect(&e))
{
perror("Could not open port");
exit(-1);
}
else
{
if (debug)
printf("Port opened\n");
}
u_int8_t queryMsg[22];
queryMsg[0] = 0x80;
queryMsg[1] = 0x10;
queryMsg[2] = 0xF0;
queryMsg[3] = 0x11;
queryMsg[4] = 0xA8;
queryMsg[5] = 0x00;
queryMsg[6] = 0x00;
queryMsg[7] = 0x00;
queryMsg[8] = 0x0D; /* MAP */
queryMsg[9] = 0x00;
queryMsg[10] = 0x00;
queryMsg[11] = 0x0E; /* RPM High */
queryMsg[12] = 0x00;
queryMsg[13] = 0x00;
queryMsg[14] = 0x0F; /* RPM Low */
queryMsg[15] = 0x00;
queryMsg[16] = 0x00;
queryMsg[17] = 0x11; /* Ignition Timing */
queryMsg[18] = 0x00;
queryMsg[19] = 0x00;
queryMsg[20] = 0x22;
queryMsg[21] = calcChecksum(queryMsg, 22);
sleep(1);
while(1)
{
if (debug)
printMsg(queryMsg, 22);
if (sendMsg(&e, queryMsg, 22) == -1)
{
perror("Could not write");
exit(-1);
}
memset(responseMsg, 0, RESPONSE_MSG_LEN);
bytesRead = recvMsg(&e, responseMsg, 33);
if (debug)
printMsg(responseMsg, 33);
/* 80 F0 10 05 E8 MAP RPMH RPML IGN KNK CKSUM */
if (debug)
printf("MAP: %X, RPMH: %X, RPML: %X, IGN: %X\n", responseMsg[27],
responseMsg[28],
responseMsg[29],
responseMsg[30]);
float map = (responseMsg[27] * 37)/255;
unsigned int rpmH = responseMsg[28];
unsigned int rpmL = responseMsg[29];
rpmH <<= 8;
unsigned int rpm = (rpmH + rpmL)/4;
int ign = (responseMsg[30] - 128)/2;
int knk = (responseMsg[31] - 128)/2;
gettimeofday(&hrTime, NULL);
printf("%ld.%ld RPM: %i MAP: %.0f IGN: %i KNK: %i\n", hrTime.tv_sec,
hrTime.tv_usec/1000,
rpm,
map,
ign,
knk);
}
disconnect(&e);
return 0;
}