Dual CANbus monitor and instrumentation cluster supporting ILI9341 display controller

Dependencies:   SPI_TFTx2_ILI9341 TOUCH_TFTx2_ILI9341 TFT_fonts mbed

Fork of CANary by Tick Tock

main.cpp

Committer:
TickTock
Date:
2013-03-16
Revision:
30:e633a63eb257
Parent:
26:462ccb580472
Child:
31:082372c83f68

File content as of revision 30:e633a63eb257:

// main.cpp

//To Do:
// * USB device detect
// * end user programmable message decode
// * brake trainer
// * write and read the Mode Data
// * Date entry config screen (keypad)
// * auto-poll option for cellpair data
// * cellpair histogram
// * config screen (with ts cal, data, time, autopoll, enable/disable logging

#include "mbed.h"
#include "CAN.h"
#include "beep.h"
#include "MSCFileSystem.h"
#include "PowerControl.h"
#include "EthernetPowerControl.h"
#include "utility.h"
#include "displayModes.h"
#include "GraphicsDisplay.h"
#include "SPI_TFTx2.h"
#include "TOUCH_TFTx2.h"

LocalFileSystem local("local");

// to write to USB Flash Drives, or equivalent (SD card in Reader/Writer)
MSCFileSystem fs("fs"); // to write to a USB Flash Drive

time_t seconds ;
Beep spkr(p21);

Ticker ticker;
Timer timer;

DigitalOut led1(LED1);
DigitalOut led2(LED2);
DigitalOut led3(LED3);
DigitalOut led4(LED4);

PwmOut dled(p23);

InterruptIn touchpad(p17);
CAN can1(p9, p10);      // CAN1 (EV) uses pins 9 and 10 (rx, tx) and pin 8 (rs)
DigitalOut can1SleepMode(p8);     // Use pin 8 to control the sleep mode of can2
CAN can2(p30, p29);     // CAN2 (CAR) uses pins 30 and 29 (rx, tx) and pin 28 (rs)
DigitalOut can2SleepMode(p28);     // Use pin 28 to control the sleep mode of can1

TOUCH_TFTx2 tt(p16, p17, p19, p20, p11, p12, p13, p6, p7, p5, "TFT"); // x+,x-,y+,y-,mosi, miso, sclk, cs0, cs1, reset

bool logEn = false,logOpen = false;
FILE *cfile;
FILE *file;
char fileName[35] = "" ;
char writeBuffer[maxBufLen][13]; // buffer for USB write
char indexLastMsg[0x800]={0}; // index table for last message
CANMessage lastMsg[100]; // table to store last message of eachtype
unsigned char battData[256]={0};
unsigned char msgChanged[100]; // inidcates which bytes changed
char c;
volatile int writePointer = 0;
volatile int secsNoMsg = 0;
volatile int secsNoTouch = 0;
volatile bool canIdle;
volatile bool userIdle;
bool touched=false; //flag to read touchscreen
char counter = 0;
unsigned char dMode[2] = {dteScreen,brakeScreen}; //display mode
unsigned char sMode = 0; // setup mode
unsigned char lastDMode[2] = {0,0}; //last screen mode
unsigned char dtMode = 6;
char displayLog[20][40];
unsigned char displayLoc = 0;
unsigned char indexOffset = 1;
bool showCP = false;
bool pollCP = false;

int main() {
    int readPointer=0;
    char sTemp[40];
    unsigned long secs;
    char i,j,display=0;
    point lastTouch;

    can1.monitor(true); // set to snoop mode
    can2.monitor(true); // set to snoop mode
    can1.frequency(500000);
    can2.frequency(500000);
    can1SleepMode = 1;         // Turn on Monitor_only Mode
    can2SleepMode = 1;         // Turn on Monitor_only Mode
    can1.attach(&recieve1);
    can2.attach(&recieve2);
    
    tt.set_orientation(1);
    tt.background(Black);
    tt.set_display(2);       // select both displays
    tt.cls();
    tt.claim(stdout);        // send stdout to the TFT display
    touchpad.rise(&touch_ISR);
    tt.wfi();               // enable interrupt on touch
    dled = 0.8; // turn on display LED 80%

    timer.start() ;
    RTC_Init(); // start the RTC Interrupts that sync the timer
    struct tm t; // pointer to a static tm structure
    NVIC_SetPriority(TIMER3_IRQn, 1); //set ticker priority
    NVIC_SetPriority(CAN_IRQn, 2); //higher than can (so RTC sync works)


    seconds = time(NULL);
    t = *localtime(&seconds) ;
    // is it a date before 2012 ?
    if ((t.tm_year + 1900) < 2012 ) {
        // before 2013 so update year to make date entry easier
        t.tm_year = 2013 - 1900;
        // set the RTC
        set_time(mktime(&t));
        seconds = time(NULL);
    }
    t = *localtime(&seconds) ;
    strftime(sTemp, 32, "%a %m/%d/%Y %X\n", &t);
    logMsg(sTemp);

    // Look for new binary on thumbdrive
    // Can't make this work right now since USB doesn't attach the right timestamp (so new binary isn't loaded)
    /*cfile = fopen("/fs/CANary.bin", "rb");
    if (cfile!=NULL){ //found a new binary on the thumbdrive so copy it over
        sprintf(sTemp,"New binary found.\n");
        logMsg(sTemp);
        file = fopen("/local/CANary.bin", "wb");
        if (file==NULL){ //failed to open destination
            sprintf(sTemp,"Unable to open destination file.\n");
            logMsg(sTemp);
        } else {
            tt.set_display(2);
            tt.foreground(White);
            tt.background(Black);
            tt.cls();
            tt.locate(1,40);
            printf("%s\n","Copying binary - Do no remove power.");
            tt.locate(1,80);
            printf("CANary will reset when complete.\n");
            wait(1); //Wait 1 sec for display DMA to finish before writing file
            while ( int size = fread( writeBuffer, sizeof(char), maxBufLen*13, cfile )){
                fwrite( writeBuffer, sizeof(char), size, file );
                led4=led3;
                led3=led2;
                led2=led1;
                led1=!led4;
            }
        fclose(cfile);
        fclose(file);
        remove("/fs/CANary.bin"); // delete original
        mbed_reset(); //restart
        }
    }*/

    secsNoMsg = 0;
    secsNoTouch = 0;

    // Read config file
    readConfig();
    touched=false;
    secsNoTouch=2;

    while (true) {
        if (!logOpen) { // Open new file if one is not already open
            if(logEn){ //logging enable
                seconds = time(NULL);
                t = *localtime(&seconds) ;
                strftime(fileName, 32, "/fs/%m%d%H%M.alc", &t); //mmddhhmm.alc
                //sprintf(sTemp,"Using file %s\n",fileName);
                //logMsg(sTemp);
                file = fopen(fileName, "ab");
                
                if(file==NULL){
                    sprintf(sTemp,"\nUnable to open %s\n\n\n\n",fileName);
                    logMsg(sTemp);
                    logEn=false;
                    spkr.beep(1000,0.25);
                } else {
                    logOpen = true;
                    readPointer=writePointer;
                    sprintf(sTemp,"Starting Can Log %s\n",fileName);
                    logMsg(sTemp);
                    logTS();
                    spkr.beep(2000,0.25);
                }
            }//logging enabled
        } else { // if (logOpen)
            if (((writePointer+maxBufLen-readPointer)%maxBufLen)>(maxBufLen/16)||canIdle||!logEn) {
                // Dump buffer if > 1/16 full or canbus has stopped
                if (file == NULL) {
                    logOpen = false;
                    sprintf(sTemp,"Failed to append log file.\n\n");
                    spkr.beep(1000,0.25);
                    logMsg(sTemp);
                    logEn=false;
                } else {
                    while (readPointer != writePointer) {
                        for (j = 0; j<13; j++){
                            fprintf(file,"%c",writeBuffer[readPointer][j]);
                        }
                        if(++readPointer >= maxBufLen)
                            readPointer=0;
                    }
                    led4 = !led4;
                }
            } // if > 1/16 full, canbus has stopped, or logging stopped
            if (!logEn) {
                fclose(file);
                logOpen=false;
            }
        } // if logOpen
        if (canIdle&&userIdle) { // canbus idle --> sleep to save power
            if (logOpen){
                fclose(file);
            } // if (logOpen)*/
            seconds = time(NULL);
            t = *localtime(&seconds) ;
            strftime(sTemp, 40, "Sleeping: %a %m/%d/%Y %X\n", &t);
            logMsg(sTemp);
            updateDisplay(0); //Added for turbo3 who has a display override and wants to see the sleep message before going to sleep
            updateDisplay(1);
            //LPC_RTC->CIIR=0x00; // block RTC interrupts
            led1=0;
            led2=0;
            led3=0;
            led4=0;
            dled=0; // turn off display
            secs = time(NULL); // seconds past 12:00:00 AM 1 Jan 1900
            while (secsNoMsg>canTimeout && !touched) {
                //DeepPowerDown();
                tt.wfi(); //enable touch interrupt
                //__wfi(); // freeze CPU and wait for interrupt (from canbus or touch)
                Sleep();
            }
            secsNoTouch=0;
            canIdle=secsNoMsg>canTimeout;
            userIdle=secsNoTouch>userTimeout;
            dled=0.8; // turn on display LED
            seconds = time(NULL);
            t = *localtime(&seconds) ;
            strftime(sTemp, 40, "Waking: %a %m/%d/%Y %X\n", &t);
            logMsg(sTemp);
            if (time(NULL)>(secs+1800)) {
                logOpen = false; // Start new file if asleep for more than 30 minutes
                if (secsNoTouch>100) secsNoTouch = 100; // also mostly reset user Idle counter
            } else if (false){ // insert timestamp on each wake if logging enabled (disabled for now)
                file = fopen(fileName, "ab");
                logTS();
            }
        } // if idle
        
        if(touched){ // call touchscreen procedure if touch interrupt detected
            lastTouch = tt.get_touch();       
            lastTouch = tt.to_pixel(lastTouch);          // convert to pixel pos
            if((lastTouch.x!=639)&&(lastTouch.x!=319)&&(lastTouch.y!=239)){
                secsNoTouch=0; //debounce
            }
            //sprintf(sTemp,"%d,%d ",lastTouch.x,lastTouch.y);
            //logMsg(sTemp);
            touched = false; // clear interrupt flag
        }
        if (!userIdle) {
            if (secsNoTouch<2) {// Recently touched
                secsNoTouch +=2; // increment to prevent double touch
                if (lastTouch.x>320){
                    i=1;
                } else {
                    i=0;
                }
                if (sMode==0) sMode = 1;
                //sprintf(sTemp,"button %d %d,%d %d\n",i,buttonX(lastTouch.x,3),buttonY(lastTouch.y,3),lastTouch.x);
                //logMsg(sTemp);
                switch (sMode) {
                    case 0: // no select
                        break;
                    case 1: // select screen
                        switch (buttonX(lastTouch.x,3)*10+buttonY(lastTouch.y,3)) {
                            case 00:
                            case 30:
                                if (dMode[i]==monitorScreen||dMode[i]==changedScreen) {
                                indexOffset=indexOffset>4?indexOffset-4:1;
                                } else if (dMode[i]==config1Screen) {
                                    wait_ms(500);
                                    tt.calibrate();
                                }
                                break;
                            case 10:
                            case 40:
                                if (dMode[i]==changedScreen) {
                                    for(j=0;j<100;j++) msgChanged[j]=0; // clear changed data
                                    lastDMode[i]=99;//force refresh
                                } else if (dMode[i]==cpScreen) {
                                    pollCP=true;
                                } else if (dMode[i]==config1Screen) {
                                    mbed_reset();
                                }
                                break;
                            case 20:
                            case 50:
                                if (dMode[i]==monitorScreen||dMode[i]==changedScreen) {
                                    indexOffset=indexOffset<77?indexOffset+4:80;
                                } else if (dMode[i]==config1Screen) {
                                    sprintf(sTemp,"Saving config file.\n");
                                    logMsg(sTemp);
                                    saveConfig();
                                    spkr.beep(2000,0.25);
                                }
                                break;
                            case 01:
                            case 31:
                                if (dMode[i]==config1Screen) {
                                    logEn = !logEn;
                                } else if (dMode[i]==config2Screen){
                                    dtMode=(dtMode<6)?dtMode+1:0;
                                    lastDMode[i]=99;
                                }
                                break;
                            case 11:
                            case 41:
                                if (dMode[i]==config2Screen){
                                    upDate(dtMode,true);
                                    lastDMode[i]=99;
                                }
                                break;
                            case 21:
                            case 51:
                                if (dMode[i]==config2Screen){
                                    upDate(dtMode,false);
                                    lastDMode[i]=99;
                                }
                                break;
                            case 02:
                            case 32:
                                dMode[i]=dMode[i]>0?dMode[i]-1:maxScreens;
                                break;
                            case 12:
                            case 42:
                                secsNoTouch = userTimeout; // immediately exit config mode
                                if (dMode[i]==config1Screen) mbed_reset();
                                break;
                            case 22:
                            case 52:
                                dMode[i]=dMode[i]<maxScreens?dMode[i]+1:0;
                                break;
                            default:
                                break;
                        }
                        break;
                    case 2: // numpad
                        break;
                    case 3:
                        break;
                    default:
                        break;
                } // case sMode
            } //recently touched
        } else { // userIdle
            if(sMode==1){
                sMode=0;
                lastDMode[0]=99;
                lastDMode[1]=99;
            }
        }

        if(pollCP){ // We do this inside main loop instead of ticker so CAN RX will not be blocked
            sendCPreq(); // send cellpair data request.
            wait_ms(16);
            sendTreq(); //send temperature request
            wait_ms(16);
            pollCP=false;
            showCP=true;
        }
        display=display<1?display+1:0; // toggle display
        updateDisplay(display);
    } //while (true)
}