Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
Fork of CANnucleo_Hello by
Revision 6:e977526d114f, committed 2015-12-06
- Comitter:
- sordfish
- Date:
- Sun Dec 06 21:16:26 2015 +0000
- Parent:
- 5:c6503b7ae971
- Commit message:
- test
Changed in this revision
main.cpp | Show annotated file Show diff for this revision Revisions of this file |
--- a/main.cpp Fri Oct 23 19:54:49 2015 +0000 +++ b/main.cpp Sun Dec 06 21:16:26 2015 +0000 @@ -1,47 +1,70 @@ /* - * An example showing how to use the CANnucleo library: - * - * Two NUCLEO boards are connected to the same CAN bus via CAN transceivers (MCP2551 or TJA1040, or etc.). - * Transceivers are not part of the NUCLEO boards, therefore must be added by you. - * Remember also that CAN bus must be terminated with 120 Ohm resitors on both ends. - * See <https://developer.mbed.org/users/WiredHome/notebook/can---getting-started/> - * The same source code is used for both NUCLEO boards, but: - * For board #1 compile the example without any change. - * For board #2 comment out the line #define BOARD1 1 before compiling - * - * Once compiled, download the binaries to the boards. - * To start ping/ponging messages reset both boards at the same time. - * - * Note: - * To simplify adding/getting data to/from a CAN message - * inserter "<<" and extractor ">>" operators have been defined. - * Please be aware that CAN message maximum data length is limited to eight bytes. - * To make sure this limitation is not violated I recommend to first compile - * your application with DEBUG enabled in "CAN.h" file. - * Then run it and check for error messages. - */ +* INNOVATE MTS SERIAL STREAM TO MEGASQUIRT MSCAN ANALOG +* +* Written by Arran Short <sordfish2050@gmail.com> +* +* This was tested on the olimex olimexino-stm32. +* code comes with no warrenty, always confirm AFR readings at the device. +* +* code was based off http://developer.mbed.org/users/hudakz/code/CAN_Nucleo_Hello/ +* mts datasheet http://www.innovatemotorsports.com/support/downloads/Seriallog-2.pdf +* MSCAN http://www.msextra.com/doc/pdf/Megasquirt_CAN_Broadcast.pdf +* +* +* +* ************ PLEASE NOTE ************ +* MSCAN has table and data offsets to choose what data it requires, +* this code hasn't implimented any of that so regardless of them +* it just sends lambda for the first analog value and the mts function value in the second +* +* +* MTS Serial is RS232 not ttl so you will need an RS-232 Transceiver +* +*/ #include "mbed.h" #include "CAN.h" -#define BOARD1 1 // please comment out this line when compiling for board #2 +Serial device(PA_9, PA_10); +Serial pc(SERIAL_TX, SERIAL_RX); -#if defined(BOARD1) - #define RX_ID 0x100 - #define TX_ID 0x101 -#else - #define RX_ID 0x101 - #define TX_ID 0x100 -#endif +DigitalOut led1(PA_5); // GREEN +DigitalOut led2(PA_1); // YELLOW -DigitalOut led(LED1); -int ledReceived; -Timer timer; -CAN can(PA_11, PA_12); // CAN Rx pin name, CAN Tx pin name, Automatic recovery from bus-off state enabled by default +CAN can(PB_8, PB_9); // CAN Rx pin name, CAN Tx pin name, Automatic recovery from bus-off state enabled by default CANMessage rxMsg; CANMessage txMsg; -int counter = 0; -volatile bool msgAvailable = false; + +uint16_t lambda; +uint8_t mtsfunction; + +volatile bool CANmsgAvailable = false; +volatile bool LM1 = false; +volatile bool gotLambda = false; +volatile bool gotMscanreq = false; + +uint8_t mycanid = 0x09; // this is the id set in tunerstudio + +uint8_t offset = 0; +uint8_t msgtype = 0; +uint8_t fromid = 0; +uint8_t toid = 0; +uint8_t table = 0; + +uint8_t myvarblk; // these three bytes are the location of where the MS cpu wants the data to be sent, +uint16_t myvaroff; // MS doesnt have any error checking so make sure these values are correct. +uint8_t varbyt; // + +char rxSerial[8]; +char header[2]; +char txData[8]; + + +// macros ripped from arduino +#define bitRead(value, bit) (((value) >> (bit)) & 0x01) +#define bitSet(value, bit) ((value) |= (1UL << (bit))) +#define bitClear(value, bit) ((value) &= ~(1UL << (bit))) +#define bitWrite(value, bit, bitvalue) (bitvalue ? bitSet(value, bit) : bitClear(value, bit)) /** * @brief 'CAN receive-complete' interrup handler. @@ -50,61 +73,277 @@ * @param * @retval */ -void onMsgReceived() { - msgAvailable = true; +void onCanMsgReceived() { + CANmsgAvailable = true; +} + +/** + * @brief 'process sub packet' + * @note Called when main loop detects a matching Innovate MTS header + * it then detects if its legacy or new protocol, then strips afr data from stream, TODO: Need to add mts inputs and 2nd o2 sensor to mscan messages + * @param + * @retval + */ +void processsubpacket() { + + led2 = !led2; + + if ( bitRead(rxSerial[2], 6) == 1 && bitRead(rxSerial[2], 1) == 1 && bitRead(rxSerial[3], 7) == 0) { + LM1 = false; + //pc.printf("not LM1\n"); + } + if ( bitRead(rxSerial[2], 7) == 1 && bitRead(rxSerial[2], 1) == 0 && bitRead(rxSerial[3], 7) == 0) { + LM1 = true; + //pc.printf("is LM1\n"); + } + + mtsfunction = 0; + + bitWrite(mtsfunction, 2, bitRead(rxSerial[2], 4)); + bitWrite(mtsfunction, 1, bitRead(rxSerial[2], 3)); + bitWrite(mtsfunction, 0, bitRead(rxSerial[2], 2)); + + pc.printf("function is "+mtsfunction+"\r\n"); + + if (mtsfunction == 0) { //function 0 mean good data. + + lambda = rxSerial[4] << 6; + lambda = lambda + rxSerial[5]; + + gotLambda = true; + } else { + //turn off serial led + led2 = 0; + } + +}//processsubpacket() + +/** + * @brief 'ms can id' + * @note Called when can message has been received + * it then converts data into human readable names + * @param + * @retval + */ +void mscanid() { + + offset = rxMsg.id >> 18; + msgtype = (rxMsg.id << 14) >> 29; + fromid = (rxMsg.id << 17) >> 28; + toid = (rxMsg.id << 21) >> 28; + table = (((rxMsg.id << 29) >> 31) << 5) + ((rxMsg.id << 25) >> 28); + } /** + * @brief 'mscan tx header' + * @note Called when mscan message has been processed + * and a responce needs to be generated from serial data + * @param + * @retval + */ +void mscantxheader(uint8_t messagetype, uint8_t sendtoid) { // makes an mscan header, byte is for message type + + switch (messagetype) { + case 0: + // command + break; + case 1: + // request + break; + case 2: + // response + txMsg.clear(); + txMsg.type = CANData; + txMsg.format = CANExtended; + + bitWrite(txMsg.len, 3, bitRead(varbyt, 3)); + bitWrite(txMsg.len, 2, bitRead(varbyt, 2)); + bitWrite(txMsg.len, 1, bitRead(varbyt, 1)); + bitWrite(txMsg.len, 0, bitRead(varbyt, 0)); + + //offset + bitWrite(txMsg.id, 28, bitRead(myvaroff, 10)); + bitWrite(txMsg.id, 27, bitRead(myvaroff, 9)); + bitWrite(txMsg.id, 26, bitRead(myvaroff, 8)); + bitWrite(txMsg.id, 25, bitRead(myvaroff, 7)); + bitWrite(txMsg.id, 24, bitRead(myvaroff, 6)); + bitWrite(txMsg.id, 23, bitRead(myvaroff, 5)); + bitWrite(txMsg.id, 22, bitRead(myvaroff, 4)); + bitWrite(txMsg.id, 21, bitRead(myvaroff, 3)); + bitWrite(txMsg.id, 20, bitRead(myvaroff, 2)); + bitWrite(txMsg.id, 19, bitRead(myvaroff, 1)); + bitWrite(txMsg.id, 18, bitRead(myvaroff, 0)); + //message type = responce + bitWrite(txMsg.id, 17, 0); + bitWrite(txMsg.id, 16, 1); + bitWrite(txMsg.id, 15, 0); + //from id + bitWrite(txMsg.id, 14, bitRead(mycanid, 3)); + bitWrite(txMsg.id, 13, bitRead(mycanid, 2)); + bitWrite(txMsg.id, 12, bitRead(mycanid, 1)); + bitWrite(txMsg.id, 11, bitRead(mycanid, 0)); + //to id + bitWrite(txMsg.id, 10, bitRead(sendtoid, 3)); + bitWrite(txMsg.id, 9, bitRead(sendtoid, 2)); + bitWrite(txMsg.id, 8, bitRead(sendtoid, 1)); + bitWrite(txMsg.id, 7, bitRead(sendtoid, 0)); + //var block + bitWrite(txMsg.id, 6, bitRead(myvarblk, 3)); + bitWrite(txMsg.id, 5, bitRead(myvarblk, 2)); + bitWrite(txMsg.id, 4, bitRead(myvarblk, 1)); + bitWrite(txMsg.id, 3, bitRead(myvarblk, 0)); + //spares + bitWrite(txMsg.id, 2, bitRead(myvarblk, 4)); + bitWrite(txMsg.id, 1, 0); + bitWrite(txMsg.id, 0, 0); + + txMsg.data[0] = lambda >> 8; + txMsg.data[1] = lambda; + txMsg.data[2] = 0x00; + txMsg.data[3] = mtsfunction; + txMsg.data[4] = 0x00; + txMsg.data[5] = 0x00; // 2 Spare channels, could add values from shield or other sensors. + txMsg.data[6] = 0x00; // + txMsg.data[7] = 0x00; + + break; + case 3: + // xsub + break; + case 4: + // burn + break; + } + pc.printf("Tx Message id is: %d \r\n", txMsg.id); + gotMscanreq = true; + +} + + +void mscanrxdata() { + + if (msgtype == 1 ) { //message is a request + + myvarblk = rxMsg.data[0]; + pc.printf("message is a request\r\n"); + + bitWrite(myvaroff, 10, bitRead(rxMsg.data[1], 7)); + bitWrite(myvaroff, 9, bitRead(rxMsg.data[1], 6)); + bitWrite(myvaroff, 8, bitRead(rxMsg.data[1], 5)); + bitWrite(myvaroff, 7, bitRead(rxMsg.data[1], 4)); + bitWrite(myvaroff, 6, bitRead(rxMsg.data[1], 3)); + bitWrite(myvaroff, 5, bitRead(rxMsg.data[1], 2)); + bitWrite(myvaroff, 4, bitRead(rxMsg.data[1], 1)); + bitWrite(myvaroff, 3, bitRead(rxMsg.data[1], 0)); + bitWrite(myvaroff, 2, bitRead(rxMsg.data[2], 7)); + bitWrite(myvaroff, 1, bitRead(rxMsg.data[2], 6)); + bitWrite(myvaroff, 0, bitRead(rxMsg.data[2], 5)); + + varbyt = rxMsg.data[2] << 3 >> 3; + + //megasquirt ecu has requested some data, details of what data it wants is provided in the header. TODO - add a function say what data it wants. + // we need to generate some data to send back, this is done with mscantxheader + mscantxheader(0x02, fromid); + } +}//mscanrxdata() + + +void flushSerialBuffer(void) { + //pc.printf("flushing..\r\n"); + char char1 = 0; + while (device.readable()) { + char1 = device.getc(); + } + return; + } + +void testcantx(void) { + txMsg.clear(); // clear Tx message storage + txMsg.type = CANData; + txMsg.format = CANExtended; + txMsg.len = 0x03; + txMsg.id = 0x1FFD487C; + txMsg.data[0] = 0x01; + txMsg.data[1] = 0x02; + txMsg.data[2] = 0x03; + can.write(txMsg); + pc.printf("test CAN message sent\r\n"); + + } + + +/** * @brief Main * @note * @param * @retval - */ + */ int main() { - can.frequency(1000000); // set bit rate to 1Mbps - can.attach(&onMsgReceived, CAN::RxIrq); // attach 'CAN receive-complete' interrupt handler - timer.reset(); -#if defined(BOARD1) - led = 1; - timer.start(); -#else - led = 0; -#endif - - while(1) { - if(timer.read() >= 1.0) { // check for timeout - timer.stop(); // stop timer - timer.reset(); // reset timer (to avaoid repeated send) - counter++; // increment counter - txMsg.clear(); // clear Tx message storage - txMsg.id = TX_ID; // set ID - txMsg << counter; // append first data item (make sure that CAN message total data lenght <= 8 bytes!) - txMsg << led.read(); // append second data item (make sure that CAN message total data lenght <= 8 bytes!) - can.write(txMsg); // transmit message - printf("CAN message sent\r\n"); - led = 0; // turn off LED + device.baud(19200); // set bit rate to 19200, this is the baudrate of innovate mts + device.format(8,SerialBase::None,1); + can.frequency(500000); // set bit rate to 500k + can.attach(&onCanMsgReceived, CAN::RxIrq); // attach 'CAN receive-complete' interrupt handler + can.filter(mycanid << 7, 0x780, CANExtended); + //testcantx(); + + while (1) { //loop forever + led1 = 1; + + if ( gotLambda && gotMscanreq ) { //send reply to megasquirt when we get data from mts serial and we have mscan frame ready. + pc.printf("ready to send\r\n"); + led2 = !led2; + pc.printf("can tx id is: %d \r\n", txMsg.id); + pc.printf("can tx type is: %d \r\n", txMsg.type); + pc.printf("can tx format is: %d \r\n", txMsg.format); + pc.printf("can tx len is: %d \r\n", txMsg.len); + pc.printf("can tx data 0 is: %d \r\n", txMsg.data[0]); + pc.printf("can tx data 1 is: %d \r\n", txMsg.data[1]); + pc.printf("can tx data 2 is: %d \r\n", txMsg.data[2]); + pc.printf("can tx data 3 is: %d \r\n", txMsg.data[3]); + pc.printf("can tx data 4 is: %d \r\n", txMsg.data[4]); + pc.printf("can tx data 5 is: %d \r\n", txMsg.data[5]); + pc.printf("can tx data 6 is: %d \r\n", txMsg.data[6]); + pc.printf("can tx data 7 is: %d \r\n", txMsg.data[7]); + can.write(txMsg); + pc.printf("CAN message sent\r\n"); + //gotLambda = false; + gotMscanreq = false; + } - if(msgAvailable) { - msgAvailable = false; // reset flag for next use - can.read(rxMsg); // read message into Rx message storage - printf("CAN message received:\r\n"); - printf(" ID = %#x\r\n", rxMsg.id); - printf(" Type = %d\r\n", rxMsg.type); - printf(" Format = %d\r\n", rxMsg.format); - printf(" Length = %d\r\n", rxMsg.len); - printf(" Data ="); - for(int i = 0; i < rxMsg.len; i++) - printf(" %x", rxMsg.data[i]); - printf("\r\n"); - if(rxMsg.id == RX_ID) { // if ID matches - rxMsg >> counter; // extract first data item - rxMsg >> ledReceived; // extract second data item - led = ledReceived; // set LED - printf("counter = %d\r\n", counter); - timer.start(); + + if(CANmsgAvailable) { //check if interupt has set the flag for avaliable messages + //led2 = !led2; + CANmsgAvailable = false; // reset flag for next use + can.read(rxMsg); // read message into Rx message storage + mscanid(); + mscanrxdata(); + //led2 = 0; } + + while (device.readable()) { // checks if there has been and messages from serial port + for (int x=0; x < 8; x++){ + rxSerial[x] = device.getc(); + if ( x==0 ) { + if ( (rxSerial[0] & 0xA2) == 0xA2 ){ + //led1 = 1; + } else { + x=0; + pc.printf("serial data reset\r\n"); + } + } + } + + header[0] = (rxSerial[0] & 0xA2); + header[1] = (rxSerial[1] & 0x80); + + if ( header[0] == 0xA2 && header[1] == 0x80) { + processsubpacket(); + } + flushSerialBuffer(); } + led1 = 0; } -} +}//main