
vehicle CAN message log to SD file system using ring buffer memory
Dependencies: SDFileSystem mbed
main.cpp@0:de9553dd79ec, 2013-01-25 (annotated)
- Committer:
- ym1784
- Date:
- Fri Jan 25 21:04:19 2013 +0000
- Revision:
- 0:de9553dd79ec
- Child:
- 1:4a538cae9042
initial version
Who changed what in which revision?
User | Revision | Line number | New contents of line |
---|---|---|---|
ym1784 | 0:de9553dd79ec | 1 | // CAN message log to SD card using can2.attach with ring buffer |
ym1784 | 0:de9553dd79ec | 2 | // 2013/Jan/25 using official SDFileSyatem library |
ym1784 | 0:de9553dd79ec | 3 | |
ym1784 | 0:de9553dd79ec | 4 | #include "mbed.h" |
ym1784 | 0:de9553dd79ec | 5 | #include "SDFileSystem.h" |
ym1784 | 0:de9553dd79ec | 6 | |
ym1784 | 0:de9553dd79ec | 7 | CAN can2(p30, p29); |
ym1784 | 0:de9553dd79ec | 8 | CANMessage can_MsgRx; |
ym1784 | 0:de9553dd79ec | 9 | Timer timer; |
ym1784 | 0:de9553dd79ec | 10 | |
ym1784 | 0:de9553dd79ec | 11 | // LED to know the status |
ym1784 | 0:de9553dd79ec | 12 | DigitalOut User_Led1(LED1); |
ym1784 | 0:de9553dd79ec | 13 | DigitalOut User_Led2(LED2); |
ym1784 | 0:de9553dd79ec | 14 | DigitalOut User_Led3(LED3); |
ym1784 | 0:de9553dd79ec | 15 | DigitalOut User_Led4(LED4); |
ym1784 | 0:de9553dd79ec | 16 | #define LED_ON 1 |
ym1784 | 0:de9553dd79ec | 17 | #define LED_OFF 0 |
ym1784 | 0:de9553dd79ec | 18 | |
ym1784 | 0:de9553dd79ec | 19 | // status monitor |
ym1784 | 0:de9553dd79ec | 20 | Serial pc(USBTX, USBRX); |
ym1784 | 0:de9553dd79ec | 21 | |
ym1784 | 0:de9553dd79ec | 22 | SDFileSystem sd(p5, p6, p7, p8, "sd"); // mosi, miso, sclk, cs, name |
ym1784 | 0:de9553dd79ec | 23 | FILE *fp; |
ym1784 | 0:de9553dd79ec | 24 | int file_open = 0; |
ym1784 | 0:de9553dd79ec | 25 | |
ym1784 | 0:de9553dd79ec | 26 | // button switch for closing file |
ym1784 | 0:de9553dd79ec | 27 | DigitalIn button1(p16); |
ym1784 | 0:de9553dd79ec | 28 | DigitalIn button2(p17); |
ym1784 | 0:de9553dd79ec | 29 | DigitalIn button3(p18); |
ym1784 | 0:de9553dd79ec | 30 | DigitalIn button4(p19); |
ym1784 | 0:de9553dd79ec | 31 | int SW0 = 0x0f, SW1 = 0x0f, SW2 = 0x0f, BUTTON = 0; |
ym1784 | 0:de9553dd79ec | 32 | Ticker sw_check; |
ym1784 | 0:de9553dd79ec | 33 | |
ym1784 | 0:de9553dd79ec | 34 | // function prototypes |
ym1784 | 0:de9553dd79ec | 35 | void can_check(void); |
ym1784 | 0:de9553dd79ec | 36 | void check_sw(); |
ym1784 | 0:de9553dd79ec | 37 | |
ym1784 | 0:de9553dd79ec | 38 | // CAN message buffer |
ym1784 | 0:de9553dd79ec | 39 | #define BUFFER_SIZE 512 // buffer size must be power of 2 |
ym1784 | 0:de9553dd79ec | 40 | #define BUFFER_MASK ( BUFFER_SIZE - 1 ) |
ym1784 | 0:de9553dd79ec | 41 | unsigned int second[BUFFER_SIZE]; |
ym1784 | 0:de9553dd79ec | 42 | unsigned short can_id[BUFFER_SIZE]; |
ym1784 | 0:de9553dd79ec | 43 | unsigned char msg_length[BUFFER_SIZE]; |
ym1784 | 0:de9553dd79ec | 44 | unsigned char data[8][BUFFER_SIZE]; |
ym1784 | 0:de9553dd79ec | 45 | volatile unsigned int head = 0; |
ym1784 | 0:de9553dd79ec | 46 | volatile unsigned int tail = 0; |
ym1784 | 0:de9553dd79ec | 47 | |
ym1784 | 0:de9553dd79ec | 48 | int main() |
ym1784 | 0:de9553dd79ec | 49 | { |
ym1784 | 0:de9553dd79ec | 50 | button1.mode(PullUp); |
ym1784 | 0:de9553dd79ec | 51 | button2.mode(PullUp); |
ym1784 | 0:de9553dd79ec | 52 | button3.mode(PullUp); |
ym1784 | 0:de9553dd79ec | 53 | button4.mode(PullUp); |
ym1784 | 0:de9553dd79ec | 54 | sw_check.attach_us(&check_sw, 5000); // status check every 5 msec |
ym1784 | 0:de9553dd79ec | 55 | |
ym1784 | 0:de9553dd79ec | 56 | can2.frequency(500000); |
ym1784 | 0:de9553dd79ec | 57 | pc.baud(9600); |
ym1784 | 0:de9553dd79ec | 58 | pc.printf("CAN log to SD card using ring buffer, 9600 bps\r\n"); |
ym1784 | 0:de9553dd79ec | 59 | |
ym1784 | 0:de9553dd79ec | 60 | User_Led1 = LED_OFF; |
ym1784 | 0:de9553dd79ec | 61 | User_Led2 = LED_OFF; |
ym1784 | 0:de9553dd79ec | 62 | User_Led3 = LED_OFF; |
ym1784 | 0:de9553dd79ec | 63 | User_Led4 = LED_OFF; |
ym1784 | 0:de9553dd79ec | 64 | |
ym1784 | 0:de9553dd79ec | 65 | char file_name[20]; |
ym1784 | 0:de9553dd79ec | 66 | |
ym1784 | 0:de9553dd79ec | 67 | time_t t; |
ym1784 | 0:de9553dd79ec | 68 | t = time( NULL ) + 32400; // UTC + 9 hours for JST |
ym1784 | 0:de9553dd79ec | 69 | strftime( file_name, 20, "/sd/%y%m%d%H%M.log", localtime( &t ) ); |
ym1784 | 0:de9553dd79ec | 70 | pc.printf( "log file is %s\r\n", file_name ); |
ym1784 | 0:de9553dd79ec | 71 | |
ym1784 | 0:de9553dd79ec | 72 | fp = fopen(file_name, "w"); |
ym1784 | 0:de9553dd79ec | 73 | if ( fp == NULL ) { |
ym1784 | 0:de9553dd79ec | 74 | pc.printf("Unable to create the file '%s'\r\n", file_name); |
ym1784 | 0:de9553dd79ec | 75 | pc.printf("Please try again\r\n"); |
ym1784 | 0:de9553dd79ec | 76 | |
ym1784 | 0:de9553dd79ec | 77 | User_Led1 = LED_OFF; |
ym1784 | 0:de9553dd79ec | 78 | file_open = 0; |
ym1784 | 0:de9553dd79ec | 79 | } else { |
ym1784 | 0:de9553dd79ec | 80 | User_Led1 = LED_ON; |
ym1784 | 0:de9553dd79ec | 81 | file_open = 1; |
ym1784 | 0:de9553dd79ec | 82 | } |
ym1784 | 0:de9553dd79ec | 83 | |
ym1784 | 0:de9553dd79ec | 84 | timer.stop(); |
ym1784 | 0:de9553dd79ec | 85 | timer.reset(); |
ym1784 | 0:de9553dd79ec | 86 | timer.start(); |
ym1784 | 0:de9553dd79ec | 87 | can2.attach(&can_check); |
ym1784 | 0:de9553dd79ec | 88 | |
ym1784 | 0:de9553dd79ec | 89 | int tmptail; |
ym1784 | 0:de9553dd79ec | 90 | while(1) { |
ym1784 | 0:de9553dd79ec | 91 | if ( head != tail ) { |
ym1784 | 0:de9553dd79ec | 92 | tmptail = (tail + 1) & BUFFER_MASK; |
ym1784 | 0:de9553dd79ec | 93 | fprintf(fp, "%03X,%03X,", head&0xfff, tmptail&0xfff); |
ym1784 | 0:de9553dd79ec | 94 | fprintf(fp, "%08X,", second[tmptail]); |
ym1784 | 0:de9553dd79ec | 95 | fprintf(fp, "t%03X%d", can_id[tmptail], msg_length[tmptail]); |
ym1784 | 0:de9553dd79ec | 96 | |
ym1784 | 0:de9553dd79ec | 97 | for (int i=0; i<msg_length[tmptail]; i++) { |
ym1784 | 0:de9553dd79ec | 98 | fprintf(fp, "%02X", data[i][tmptail]); |
ym1784 | 0:de9553dd79ec | 99 | } // for |
ym1784 | 0:de9553dd79ec | 100 | fprintf(fp, "\r\n"); |
ym1784 | 0:de9553dd79ec | 101 | |
ym1784 | 0:de9553dd79ec | 102 | tail = tmptail; // update tail after data sent |
ym1784 | 0:de9553dd79ec | 103 | if ( tail == 0 ) { |
ym1784 | 0:de9553dd79ec | 104 | // toggle led3 |
ym1784 | 0:de9553dd79ec | 105 | User_Led3 = !User_Led3; |
ym1784 | 0:de9553dd79ec | 106 | t = time( NULL ) + 32400; // UTC + 9 hours for JST |
ym1784 | 0:de9553dd79ec | 107 | strftime( file_name, 20, "%T", localtime( &t ) ); |
ym1784 | 0:de9553dd79ec | 108 | pc.printf("new cycle of ring buffer at %s\r\n", file_name); |
ym1784 | 0:de9553dd79ec | 109 | } |
ym1784 | 0:de9553dd79ec | 110 | } // if head != tail |
ym1784 | 0:de9553dd79ec | 111 | |
ym1784 | 0:de9553dd79ec | 112 | if ( BUTTON&0x01 ) { // button1 pressed |
ym1784 | 0:de9553dd79ec | 113 | BUTTON &= 0xfe; // clear button status |
ym1784 | 0:de9553dd79ec | 114 | can2.attach(0); // detach CAN interrupt |
ym1784 | 0:de9553dd79ec | 115 | file_open = 0; |
ym1784 | 0:de9553dd79ec | 116 | //Close the file |
ym1784 | 0:de9553dd79ec | 117 | fclose(fp); |
ym1784 | 0:de9553dd79ec | 118 | pc.printf("file closed\r\n"); |
ym1784 | 0:de9553dd79ec | 119 | User_Led1 = LED_OFF; |
ym1784 | 0:de9553dd79ec | 120 | } // if button |
ym1784 | 0:de9553dd79ec | 121 | } // while |
ym1784 | 0:de9553dd79ec | 122 | } // main |
ym1784 | 0:de9553dd79ec | 123 | |
ym1784 | 0:de9553dd79ec | 124 | // read CAN2 message using intterupt and ring buffer |
ym1784 | 0:de9553dd79ec | 125 | void can_check(void) { |
ym1784 | 0:de9553dd79ec | 126 | int temp_head; |
ym1784 | 0:de9553dd79ec | 127 | if ( file_open == 1 ) { |
ym1784 | 0:de9553dd79ec | 128 | while ( can2.read(can_MsgRx) ) { |
ym1784 | 0:de9553dd79ec | 129 | temp_head = (head + 1) & BUFFER_MASK; |
ym1784 | 0:de9553dd79ec | 130 | if ( temp_head == tail ) { // buffer overflow error |
ym1784 | 0:de9553dd79ec | 131 | fclose(fp); |
ym1784 | 0:de9553dd79ec | 132 | fprintf(stderr, "buffer overflow\r\n"); |
ym1784 | 0:de9553dd79ec | 133 | fprintf(stderr, "head = %d\r\n", head); |
ym1784 | 0:de9553dd79ec | 134 | fprintf(stderr, "tail = %d\r\n", tail); |
ym1784 | 0:de9553dd79ec | 135 | User_Led4 = 1; |
ym1784 | 0:de9553dd79ec | 136 | exit(1); |
ym1784 | 0:de9553dd79ec | 137 | } // if |
ym1784 | 0:de9553dd79ec | 138 | |
ym1784 | 0:de9553dd79ec | 139 | second[temp_head] = timer.read_us(); |
ym1784 | 0:de9553dd79ec | 140 | can_id[temp_head] = can_MsgRx.id & 0xFFF; |
ym1784 | 0:de9553dd79ec | 141 | msg_length[temp_head] = can_MsgRx.len; |
ym1784 | 0:de9553dd79ec | 142 | for (int i=0; i<can_MsgRx.len; i++) { |
ym1784 | 0:de9553dd79ec | 143 | data[i][temp_head] = can_MsgRx.data[i]; |
ym1784 | 0:de9553dd79ec | 144 | } // for |
ym1784 | 0:de9553dd79ec | 145 | head = temp_head; // update head after data stored |
ym1784 | 0:de9553dd79ec | 146 | // toggle led2 |
ym1784 | 0:de9553dd79ec | 147 | User_Led2 = !User_Led2; |
ym1784 | 0:de9553dd79ec | 148 | } // while |
ym1784 | 0:de9553dd79ec | 149 | } // if open |
ym1784 | 0:de9553dd79ec | 150 | } // can_check |
ym1784 | 0:de9553dd79ec | 151 | |
ym1784 | 0:de9553dd79ec | 152 | // read switch status, called every 5 msec |
ym1784 | 0:de9553dd79ec | 153 | void check_sw() { |
ym1784 | 0:de9553dd79ec | 154 | SW2 = SW1; // shift previous status |
ym1784 | 0:de9553dd79ec | 155 | SW1 = SW0; // shift previous status |
ym1784 | 0:de9553dd79ec | 156 | // get new status |
ym1784 | 0:de9553dd79ec | 157 | SW0 = button1.read()+(button2.read()<<1)+(button3.read()<<2)+(button4.read()<<3); |
ym1784 | 0:de9553dd79ec | 158 | // following sequence detects switch press edge |
ym1784 | 0:de9553dd79ec | 159 | // HIGH(SW2) -> LOW(SW1) -> LOW(SW0) |
ym1784 | 0:de9553dd79ec | 160 | BUTTON |= ((~(SW0|SW1))&SW2); // update button status |
ym1784 | 0:de9553dd79ec | 161 | } // check_sw |