vehicle CAN message log to SD file system using ring buffer memory

Dependencies:   SDFileSystem mbed

main.cpp

Committer:
ym1784
Date:
2013-01-30
Revision:
1:4a538cae9042
Parent:
0:de9553dd79ec

File content as of revision 1:4a538cae9042:

// CAN message log to SD card using can2.attach with ring buffer
// 2013/Jan/25 using official SDFileSyatem library

#include "mbed.h"
#include "SDFileSystem.h"

CAN can2(p30, p29);
CANMessage can_MsgRx;
Timer timer;

// LED to know the status
DigitalOut User_Led1(LED1);
DigitalOut User_Led2(LED2);
DigitalOut User_Led3(LED3);
DigitalOut User_Led4(LED4);
#define LED_ON 1
#define LED_OFF 0

// status monitor
Serial pc(USBTX, USBRX); 

SDFileSystem sd(p5, p6, p7, p8, "sd"); // mosi, miso, sclk, cs, name
FILE *fp;
int file_open = 0;

// button switch for closing file
DigitalIn button1(p16);
DigitalIn button2(p17);
DigitalIn button3(p18);
DigitalIn button4(p19);
int SW0 = 0x0f, SW1 = 0x0f, SW2 = 0x0f, BUTTON = 0;
Ticker sw_check;

// function prototypes
void can_check(void);
void check_sw();

// CAN message ring buffer
#define BUFFER_SIZE 512  // buffer size must be power of 2
#define BUFFER_MASK ( BUFFER_SIZE - 1 )
unsigned int second[BUFFER_SIZE];
unsigned short can_id[BUFFER_SIZE];
unsigned char msg_length[BUFFER_SIZE];
unsigned char data[8][BUFFER_SIZE];
volatile unsigned int head = 0;
volatile unsigned int tail = 0;

int main()
{
    button1.mode(PullUp);
    button2.mode(PullUp);
    button3.mode(PullUp);
    button4.mode(PullUp);
    sw_check.attach_us(&check_sw, 5000);    // button switch status check every 5 msec

    can2.frequency(500000);
    pc.baud(9600);
    pc.printf("CAN log to SD card using ring buffer, 9600 bps\r\n");

    User_Led1 = LED_OFF;
    User_Led2 = LED_OFF;
    User_Led3 = LED_OFF;
    User_Led4 = LED_OFF;

    char file_name[20];

    time_t t;
    t = time( NULL ) + 32400;  // UTC + 9 hours for JST
    strftime( file_name, 20, "/sd/%y%m%d%H%M.log", localtime( &t ) );
    pc.printf( "log file is %s\r\n", file_name );

    fp = fopen(file_name, "w");
    if ( fp == NULL ) {
        pc.printf("Unable to create the file '%s'\r\n", file_name);
        pc.printf("Please try again\r\n");

        User_Led1 = LED_OFF;    // file open fail
        file_open = 0;
    } else {
        User_Led1 = LED_ON;     // file open
        file_open = 1;
    }

    timer.stop();
    timer.reset();
    timer.start();
    can2.attach(&can_check);

    int tmptail;
    while(1) {
        if ( head != tail ) {
            tmptail = (tail + 1) & BUFFER_MASK;
            fprintf(fp, "%03X,%03X,", head&0xfff, tmptail&0xfff);
            fprintf(fp, "%08X,", second[tmptail]);
            fprintf(fp, "t%03X%d", can_id[tmptail], msg_length[tmptail]);

            for (int i=0; i<msg_length[tmptail]; i++) {
                fprintf(fp, "%02X", data[i][tmptail]);
            } // for
            fprintf(fp, "\r\n");

            tail = tmptail; // update tail after data sent
            if ( tail == 0 ) {
                User_Led3 = !User_Led3;     // toggle led3 showing new cycle of ring buffer
                t = time( NULL ) + 32400;   // UTC + 9 hours for JST
                strftime( file_name, 20, "%T", localtime( &t ) );
                pc.printf("new cycle of ring buffer at %s\r\n", file_name);
            }
        } // if head != tail

        if ( BUTTON&0x01 ) {    // button1 pressed
            BUTTON &= 0xfe;     // clear button status
            can2.attach(0);     // detach CAN interrupt
            file_open = 0;
            //Close the file
            fclose(fp);
            pc.printf("file closed\r\n");
            User_Led1 = LED_OFF;
        } // if button
    } // while
} // main

// read CAN2 message using intterupt and ring buffer
void can_check(void) {
    int temp_head;
    if ( file_open == 1 ) {
        while ( can2.read(can_MsgRx) ) {
            temp_head = (head + 1) & BUFFER_MASK;
            if ( temp_head == tail ) {      // buffer overflow error
                fclose(fp);
                fprintf(stderr, "buffer overflow\r\n");
                fprintf(stderr, "head = %d\r\n", head);
                fprintf(stderr, "tail = %d\r\n", tail);
                User_Led4 = 1;              // buffer overflow error
                exit(1);
            } // if

            second[temp_head] = timer.read_us();
            can_id[temp_head] = can_MsgRx.id & 0xFFF;
            msg_length[temp_head] = can_MsgRx.len;
            for (int i=0; i<can_MsgRx.len; i++) {
                data[i][temp_head] = can_MsgRx.data[i];
            } // for
            head = temp_head;   // update head after data stored
            User_Led2 = !User_Led2;     // toggle led2 showing CAN message reading
        } // while
    } // if open
} // can_check

// read switch status, called every 5 msec
void check_sw() {
    SW2 = SW1;      // shift previous status
    SW1 = SW0;      // shift previous status
// get new status
    SW0 = button1.read()+(button2.read()<<1)+(button3.read()<<2)+(button4.read()<<3);
// following sequence detects switch press edge
// HIGH(SW2) -> LOW(SW1) -> LOW(SW0)
    BUTTON |= ((~(SW0|SW1))&SW2);   // update button status
} // check_sw