Dual CANbus monitor and instrumentation cluster

Dependencies:   SPI_TFTx2 TFT_fonts TOUCH_TFTx2 beep mbed

Fork of CANary by Tick Tock

main.cpp

Committer:
TickTock
Date:
2013-03-11
Revision:
22:a43df3905863
Parent:
21:22bdce9efcb5
Child:
23:cd03f9c3395e

File content as of revision 22:a43df3905863:

// 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"

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 = true,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=0; //flag to read touchscreen
char counter = 0;
unsigned char dMode[2] = {1,7}; //display mode
unsigned char sMode = 0; // setup mode
unsigned char lastDMode[2] = {0,0}; //last screen mode
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,ff,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) ;
    secsNoMsg = 0;
    secsNoTouch = 0;

    // is it a date before 2012 ?
    if ((t.tm_year + 1900) < 2012 ) {
        // before 2012, so the RTC probably lost power
        // So, set a near-recent date in 2012
        // enter people-values here
        t.tm_year = 2013 ; // 28 May 2012
        t.tm_mon = 3 ; // 1 to 12
        t.tm_mday = 5;
        t.tm_hour = 12; // 12:59:56 PM (after noon)
        t.tm_min = 59;
        t.tm_sec = 56;

        // adjust for tm structure required values
        t.tm_year = t.tm_year - 1900;
        t.tm_mon = t.tm_mon - 1;

        // set the RTC
        set_time(mktime(&t));
        seconds = time(NULL);

        //    printf("Set RTC to:\n" );
        //    strftime(sTemp, 32, "%a %m/%d/%Y %X", localtime(&seconds));
        //    printf("%s\n", sTemp); // DAY MM/DD/YYYY HH:MM:SS
    }
    t = *localtime(&seconds) ;
    strftime(sTemp, 32, "%a %m/%d/%Y %X\n", &t);
    logMsg(sTemp);

    // Look for new binary 
    // 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
        }
    }*/

    // Look for config file
    cfile = fopen("/local/config.txt", "r");
    if (cfile==NULL){ // if doesn't exist --> create
        sprintf(sTemp,"No config file found.\n");
        logMsg(sTemp);
        sprintf(sTemp,"Calibrating touch screen.\n");
        logMsg(sTemp);
        //tt.setcal(5570, 34030, 80, 108, 33700, 5780, 82, 108, 32500);// bypass calibration using my values
        tt.calibrate();   // run touchscreen calibration routine
        cfile = fopen("/local/config.txt", "w");
        fprintf(cfile,"format 1\r\n");
        fprintf(cfile,"x0_off %d\r\n",tt.x0_off);
        fprintf(cfile,"y0_off %d\r\n",tt.y0_off);
        fprintf(cfile,"x0_pp %d\r\n",tt.x0_pp);
        fprintf(cfile,"y0_pp %d\r\n",tt.y0_pp);
        fprintf(cfile,"x1_off %d\r\n",tt.x1_off);
        fprintf(cfile,"y1_off %d\r\n",tt.y1_off);
        fprintf(cfile,"x1_pp %d\r\n",tt.x1_pp);
        fprintf(cfile,"y1_pp %d\r\n",tt.y1_pp);
        fprintf(cfile,"x_mid %d\r\n",tt.x_mid);
    } else { // read params
        sprintf(sTemp,"Reading config file.\n");
        logMsg(sTemp);
        fscanf(cfile, "format %c\r\n", &ff ) ;
        fscanf(cfile, "x0_off %d\r\n", &tt.x0_off ) ;
        fscanf(cfile, "y0_off %d\r\n", &tt.y0_off ) ;
        fscanf(cfile, "x0_pp %d\r\n", &tt.x0_pp ) ;
        fscanf(cfile, "y0_pp %d\r\n", &tt.y0_pp ) ;
        fscanf(cfile, "x1_off %d\r\n", &tt.x1_off ) ;
        fscanf(cfile, "y1_off %d\r\n", &tt.y1_off ) ;
        fscanf(cfile, "x1_pp %d\r\n", &tt.x1_pp ) ;
        fscanf(cfile, "y1_pp %d\r\n", &tt.y1_pp ) ;
        fscanf(cfile, "x_mid %d\r\n", &tt.x_mid ) ;
    }
    fclose(cfile);    

    //ticker.attach(&tickerISR, 60);  //poll cellpair data every minute
    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.2);
                } else {
                    logOpen = true;
                    readPointer=writePointer;
                    sprintf(sTemp,"Starting Can Log %s\n",fileName);
                    logMsg(sTemp);
                    logTS();
                    spkr.beep(2000,0.2);
                }
            }//logging enabled
        } else { // if (logOpen)
            if (((writePointer+maxBufLen-readPointer)%maxBufLen)>(maxBufLen/16)||canIdle) {
                // 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.2);
                    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 PB1 pressed
        } // if logOpen
        if (canIdle&&userIdle) { // canbus idle --> sleep to save power
            if (logOpen){
                fclose(file);
            } // if (logOpen)*/
            //sprintf(sTemp,"Putting uC to sleep.\n");
            seconds = time(NULL);
            t = *localtime(&seconds) ;
            strftime(sTemp, 40, "Sleeping: %a %m/%d/%Y %X\n", &t);
            logMsg(sTemp);
            //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();
                //DeepPowerDown();
            }
            canIdle=secsNoMsg>canTimeout;
            userIdle=secsNoTouch>userTimeout;
            dled=0.8; // turn on display LED
            //sprintf(sTemp,"Waking uC.\n");
            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;
                    //lastTouch.x-=320;
                } else {
                    i=0;
                }
                //sprintf(sTemp,"button %d %d,%d %d\n",i,buttonX(lastTouch.x,3),buttonY(lastTouch.y,3),lastTouch.x);
                //logMsg(sTemp);
                if (buttonY(lastTouch.y,3)==2) { //bottom row
                    if (sMode==1) {
                        switch (buttonX(lastTouch.x,3)) {
                            case 0:
                            case 3:
                                dMode[i]=dMode[i]>0?dMode[i]-1:maxScreens;
                                break;
                            case 1:
                            case 4:
                                secsNoTouch = userTimeout; // immediately exit config mode
                                break;
                            case 2:
                            case 5:
                                dMode[i]=dMode[i]<maxScreens?dMode[i]+1:0;
                                break;
                            default:
                                break;
                        }
                    } else sMode=1;
                } else if (buttonY(lastTouch.y,3)==0) { // top row
                    switch (buttonX(lastTouch.x,3)) {
                        case 0:
                        case 3:
                            if (dMode[i]==monitorScreen||dMode[i]==changedScreen) {
                                indexOffset=indexOffset>4?indexOffset-4:1;
                            }
                            break;
                        case 1:
                        case 4:
                            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;
                            }
                            break;
                        case 2:
                        case 5:
                            if (dMode[i]==monitorScreen||dMode[i]==changedScreen) {
                                indexOffset=indexOffset<77?indexOffset+4:80;
                            }
                            break;
                        default:
                            break;
                    }
                } //top row
            } //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)
}