Small project to display some OBD values from the Toyota GT86/ Subaru BRZ/ Scion FRS on an OLED display.

Dependencies:   Adafruit_GFX MODSERIAL mbed-rtos mbed

main.cpp

Committer:
chrta
Date:
2014-05-11
Revision:
7:a19b63c0a0fa
Parent:
6:506b703a8acf

File content as of revision 7:a19b63c0a0fa:

#include "mbed.h"
#include "rtos.h"
#include "IsoTpHandler.h"
#include "MODSERIAL.h"
#include "display.h"

#include "EngineCoolantTemperature.h"
#include "OilTemperature.h"
#include "VehicleSpeed.h"
#include "Throttle.h"
#include "EngineRpm.h"

//#define CAN1_TEST
//#define CAN1_OBD_CAR_SIMULATOR

// Make TX buffer 1024bytes and RX buffer use 512bytes.
MODSERIAL pc(USBTX, USBRX, 2 * 1024, 512); // tx, rx
DigitalOut led1(LED1);
DigitalOut led2(LED2);
DigitalOut led3(LED3);
DigitalOut led4(LED4);

CAN can1(p9, p10);
DigitalOut can1_disable(p8);
CAN can2(p30, p29);
DigitalOut can2_disable(p28);

IsoTpHandler tpHandler(&can2);

Display display;

//#define ACTIVATE_DEBUG_OUTPUT
#ifdef ACTIVATE_DEBUG_OUTPUT
#define DEBUG_PRINT(format, ...) pc.printf(format, ##__VA_ARGS__) 
#else
#define DEBUG_PRINT(format, ...)
#endif

void led2_thread(void const *args) {
    while (true) {
        led2 = !led2;
        Thread::wait(1000);
    }
}

Mail<CANMessage, 16> can_rx_queue;

void can_process_packets(void const *args) {
    while (true) {
        //pc.printf("Th wait for can packet\r\n");
        osEvent evt = can_rx_queue.get(osWaitForever);
        //pc.printf("Got evt %d\r\n", evt.status);
        if (evt.status == osEventMail) {
            //pc.printf("Got can packet\r\n");
            CANMessage *msg = (CANMessage*) evt.value.p;
            //pc.printf("Process can packet\r\n");
            tpHandler.processCanMessage(msg);
            //pc.printf("Processed can packet\r\n");
            can_rx_queue.free(msg);
            //pc.printf("Freed can packet\r\n");
        }
    }
}

 
void can_rx_int_handler() {
    //pc.printf("can_rx_int_handler\r\n");
    CANMessage* msg = can_rx_queue.alloc();
    if (!can2.read(*msg))
    {
        //pc.printf("can_rx_int_handler no read\r\n");
        //this should not happen, because this function is called from the rx interrupt
        can_rx_queue.free(msg);
        //pc.printf("can_rx_int_handler ret 1\r\n");
        return;
    }
    if (msg->id != 0x7E8)
    {
        //no OBD message
        can_rx_queue.free(msg);
        return;
    }
    //pc.printf("can_rx_int_handler got packet\r\n");
    osStatus error_code = can_rx_queue.put(msg);
    //pc.printf("can_rx_int_handler in queue\r\n"); 
    if (error_code != osOK) {
        //pc.printf("can_rx_int_handler failed\r\n");
        //error("Putting can message into mailbox failed with code %d!", error);
    }
    
    //pc.printf("can_rx_int_handler ok\r\n");
}

Mail<CANMessage, 16> can2_tx_queue;
void can2_send_packets(void const *args) {
    DEBUG_PRINT("TX2 start\r\n");
    while (true) {
        osEvent evt = can2_tx_queue.get(osWaitForever);
        if (evt.status == osEventMail) {
            CANMessage *msg = (CANMessage*) evt.value.p;
            DEBUG_PRINT("TX2 check\r\n");
            if (can2.write(*msg))
            {
                DEBUG_PRINT("TX2 send\r\n");
                can2_tx_queue.free(msg);
                Thread::wait(150);
            }
            else
            {
                DEBUG_PRINT("TX2 wait \r\n");
                Thread::wait(150);
            }
        }
    }
}


struct behaviour_t {
    const char *rxData; //[8];
    char txData[8];
};


const char broken_message[] = {0x02, 0x01, 0x21, 0, 0, 0, 0, 0};
behaviour_t behaviour[] = 
{
    {OilTemperature::REQUEST_DATA, {0x10, 0x1F, 0x61, 0x01, 0x51, 0, 0x37, 0x01}}, //first oil temp packet
    {OilTemperature::SECOND_MESSAGE, {0x21, 0x1F, 0x61, 0x01, 0x51, 0, 0x37, 0x01}}, //second oil temp packet, TODO more pakets must be sent
    {broken_message, {0x04, 0x41, 0x21, 0, 0, 0, 0, 0}},
    {VehicleSpeed::REQUEST_DATA, {0x03, 0x41, 0x0D, 0x26, 0, 0, 0, 0}},
    {EngineRpm::REQUEST_DATA, {0x04, 0x41, 0x0C, 0x0F, 0xA2, 0, 0, 0}},
    {Throttle::REQUEST_DATA, {0x03, 0x41, 0x11, 0x26, 0, 0, 0, 0}},
    {EngineCoolantTemp::REQUEST_DATA, {0x03, 0x41, 0x05, 0x4D, 0, 0, 0, 0}},  //engine coolant temp
};

void can2_send_requests(void const *args) {
    while (true) {
        Thread::wait(2000);
        CANMessage sendMsg(0x7E0, (char*) behaviour[3].rxData, 8);
        CANMessage* msg = can2_tx_queue.alloc();
        *msg = sendMsg;
        can2_tx_queue.put(msg);
        Thread::wait(200);
        msg = can2_tx_queue.alloc();
        sendMsg.data[2] = behaviour[4].rxData[2];
        *msg = sendMsg;
        can2_tx_queue.put(msg);
        Thread::wait(200);
        sendMsg.data[2] = behaviour[5].rxData[2];
        *msg = sendMsg;
        can2_tx_queue.put(msg);
        Thread::wait(200);
        sendMsg.data[2] = behaviour[6].rxData[2];
        *msg = sendMsg;
        can2_tx_queue.put(msg);
        Thread::wait(200);
        CANMessage sendMsg2(0x7E0, (char*) behaviour[0].rxData, 8);
        msg = can2_tx_queue.alloc();
        *msg = sendMsg2;
        can2_tx_queue.put(msg);
    }
}

#ifdef CAN1_TEST
Mail<CANMessage, 16> can1_rx_queue;
CANMessage msg1;
void can1_rx_int_handler() {
    led3 = !led3;
    CANMessage* msg = can1_rx_queue.alloc();
    if (!can1.read(*msg))
    {
        can1_rx_queue.free(msg);
        return;
    }
    if ((msg->id != 0x7E8) && (msg->id != 0x7E0))
    {
        can1_rx_queue.free(msg);
        return;
    }
    can1_rx_queue.put(msg);
    led4 = !led4;
}


#ifdef CAN1_OBD_CAR_SIMULATOR

Mail<CANMessage, 16> can1_tx_queue;

void can1_obd_car_simulator_process_packet(CANMessage &msg)
{
    if (msg.id != 0x7E0)
    {
        return;
    }
    
    for (unsigned int i = 0; i < sizeof(behaviour) / sizeof (behaviour[0]); i++)
    {
        if (memcmp(msg.data, behaviour[i].rxData, 8) == 0)
        {
            CANMessage sendMsg(0x7E8, (char*) behaviour[i].txData, 8);
            CANMessage* msg = can1_tx_queue.alloc();
            *msg = sendMsg;
            can1_tx_queue.put(msg);
            
            if (i == 1)
            {
                //send additinal packets later
                sendMsg.data[0] = 0x22;
                msg = can1_tx_queue.alloc();
                *msg = sendMsg;
                can1_tx_queue.put(msg);
                sendMsg.data[0] = 0x23;
                msg = can1_tx_queue.alloc();
                *msg = sendMsg;
                can1_tx_queue.put(msg);
                sendMsg.data[0] = 0x24;
                msg = can1_tx_queue.alloc();
                *msg = sendMsg;
                can1_tx_queue.put(msg);
            }
        }
    }
}

#endif //CAN1_OBD_CAR_SIMULATOR

void can1_process_packets(void const *args) {
    while (true) {
        osEvent evt = can1_rx_queue.get(osWaitForever);
        if (evt.status == osEventMail) {
            CANMessage *msg = (CANMessage*) evt.value.p;
            
            pc.printf("\r\nRX1: '%d' '%d' '%d' '%x' '", msg->format, msg->type, msg->len, msg->id);
            for (unsigned int i = 0; i < msg->len; i++)
            {
                pc.printf("%x ", msg->data[i]);
            }
            pc.printf("'\r\n");
#ifdef CAN1_OBD_CAR_SIMULATOR
            can1_obd_car_simulator_process_packet(*msg);
#endif //CAN1_OBD_CAR_SIMULATOR            
            can1_rx_queue.free(msg);
        }
    }
}    

#ifdef CAN1_OBD_CAR_SIMULATOR
void can1_send_packets(void const *args) {
    DEBUG_PRINT("TX1 start\r\n");
    while (true) {
        osEvent evt = can1_tx_queue.get(osWaitForever);
        if (evt.status == osEventMail) {
            CANMessage *msg = (CANMessage*) evt.value.p;
            DEBUG_PRINT("TX1 check\r\n");
            if (can1.write(*msg))
            {
                DEBUG_PRINT("TX1 send\r\n");
                can1_tx_queue.free(msg);
                Thread::wait(50);
            }
            else
            {
                DEBUG_PRINT("TX1 wait \r\n");
                Thread::wait(50);
            }
        }
    }
}    
#endif //CAN1_OBD_CAR_SIMULATOR
    
#endif //CAN1_TEST

char can_msg[8] = {0};
CANMessage msg(0x7E0, can_msg, 8);
void serial_int_handler() {
    if (!pc.readable()) {
        return;
    }
    uint8_t character = pc.getc();
    //pc.printf("Received '%c'\r\n", character);
    
    msg.data[0] = 0x02;
    msg.data[1] = 0x01;
    char pid = 0;
    switch (character)
    {
        case '1':
            pid = 0x0C; //engine rpm
            break;
        case '2':
            pid = 0x11; //throttle
            break;
        case '3': //oil 1
            msg.data[1] = 0x21; //endian
            pid = 1;
            break;
        case '4': //oil 2
            msg.data[1] = 1; //endian
            pid = 0x21;
            break;
        default:
            pid = 0x05; //engine coolant temp
    }
    msg.data[2] = pid;
    msg.len = 8;
    
    //pc.printf("Sending message\r\n");
    int result = can2.write(msg);  //or 0x7DF ?
    //pc.printf("Can write %d\r\n", result);
    //pc.printf("ret 1\r\n");
 }
 
int main() {
    display.clear();
    display.sendTo("Starting...\r\n");
    display.display();
    
    pc.baud(921600);
    //pc.attach(&serial_int_handler);
    can2_disable = 0;
    can2.frequency(500000);
    //mbed can filter is not working? check it later
    //can2.filter
    can2.attach(can_rx_int_handler);
    Thread thread(led2_thread);
    Thread can_thread(can_process_packets);
#ifdef CAN1_TEST
    can1_disable = 0;
    can1.frequency(500000);
    can1.attach(&can1_rx_int_handler);
    Thread can1_thread(can1_process_packets);
#ifdef CAN1_OBD_CAR_SIMULATOR
    Thread can1_tx_thread(can1_send_packets);
#endif //CAN1_OBD_CAR_SIMULATOR    
#endif //CAN1_TEST
    Thread can2_send_request_thread(can2_send_requests);
    Thread can2_tx_thread(can2_send_packets);
    display.sendTo("Init done.\r\n");
    display.display();
    
    pc.printf("Start\r\n");
    while (true) {
        led1 = !led1;
        Thread::wait(500);
        if (pc.readable()) {
            serial_int_handler();
        }
    }
}