CANPort provides a higher level interface to a CAN communication channel, and provides timestamping, servicing additional hardware interfaces (optional activity LED, CAN transceiver slope control)

Revision:
0:7b81b19d9b10
Child:
1:f0b4e47d948d
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/CANPort.cpp	Sun Jul 15 15:15:19 2012 +0000
@@ -0,0 +1,243 @@
+/// @file CANPort.cpp is where all the port level functionality resides
+///
+/// @note Copyright &copr; 2011 by Smartware Computing, all rights reserved.
+///     Individuals may use this application for evaluation or non-commercial
+///     purposes. Within this restriction, changes may be made to this application
+///     as long as this copyright notice is retained. The user shall make
+///     clear that their work is a derived work, and not the original.
+///     Users of this application and sources accept this application "as is" and
+///     shall hold harmless Smartware Computing, for any undesired results while
+///     using this application - whether real or imagined.
+///
+/// @author David Smart, Smartware Computing
+///
+/// 20110718
+///   Fixed a bug in the Receive handler - it was not propagating the message
+///   out.
+/// 20110605
+///   Revised the SlopeControl so that it actually works for any change in value
+///   where it was previously able to go low or high, but once as an input it
+///   then would not go back to an output.
+///
+#include "mbed.h"
+#include "CANPort.h"
+#include "Utilities.h"
+
+#define FLASH_PERIOD (float)0.04
+#define FLASH_TX_LEVEL 0.10
+#define FLASH_RX_LEVEL 1.00
+
+
+CANPort::CANPort(CANCHANNEL_T chNum, PinName rd, PinName td, PinName _activityPin, PinName _slopePin, CANSlopeControl_T slope) {
+    channel = chNum;
+    can = new CAN(rd, td);
+    if (_activityPin != NC) {
+        activityPin = new PwmOut(_activityPin);
+        activityPin->pulsewidth_us(100);
+        }
+    else
+        activityPin = NULL;
+    if (_slopePin != NC) {
+        slopePin = new DigitalInOut(_slopePin);
+        SetSlopeControl(slope);
+    } else
+        slopePin = NULL;
+    slopePinName = _slopePin;
+    txCounter = 0;
+    rxCounter = 0;
+}
+
+
+CANPort::~CANPort() {
+    if (slopePin)
+        delete slopePin;
+    if (activityPin)
+        delete activityPin;
+    if (can)
+        delete can;
+    slopePin = NULL;
+    activityPin = NULL;
+    can = NULL;
+}
+
+
+bool CANPort::TransmitMsg(CANmsg msg) {
+    bool success = false;
+
+    if (msg.dir == xmt) {   // we have to have indicated our intent to transmit
+        msg.ch = channel;
+        if (can->write(CANMessage(msg.id, (char *)&msg.data, msg.len, CANData, msg.format))) {
+            txCounter++;
+            Flash(msg.dir);
+            success = true;
+        }
+    }
+    return success;
+}
+
+
+bool CANPort::ReceiveMsg(CANmsg &msg) {
+    bool success = false;
+    CANMessage _msg;
+
+    if (can->read(_msg)) {
+        /// @TODO This looks like a very inefficient method, but it works.
+        CANmsg Xmsg(channel, rcv, _msg);
+        msg = Xmsg;
+        rxCounter++;
+        Flash(msg.dir);
+        success = true;
+    }
+    return success;
+}
+
+
+void CANPort::Attach( void (*fptr)(void)) {
+    can->attach(fptr);
+}
+
+
+void CANPort::Extinguish(void) {
+    if (activityPin) {
+        *activityPin = 0.0;
+    }
+}
+
+
+void CANPort::Flash(CANDIR_T tx) {
+    if (activityPin) {
+        *activityPin = (tx == xmt) ? FLASH_TX_LEVEL : FLASH_RX_LEVEL;     // dim for transmit, bright for receive
+        activityTimeout.attach(this, &CANPort::Extinguish, FLASH_PERIOD);
+    }
+}
+
+
+bool CANPort::SetAutoReset(bool enable) {
+    autoReset = enable;
+    return true;
+}
+
+
+bool CANPort::SetBusMode(CANBusMode_T mode) {
+    switch (mode) {
+        case MONITOR:
+            can->monitor(true);
+            busMode = mode;
+            break;
+        case ACTIVE:
+            can->monitor(false);
+            busMode = mode;
+            break;
+        default:
+            return false;
+    }
+    return true;
+}
+
+
+CANBusMode_T CANPort::GetBusMode() {
+    return busMode;
+}
+
+
+bool CANPort::SetSlopeControl(CANSlopeControl_T slope) {
+    if (slopePin) {
+        slopeMode = slope;
+        switch (slope) {
+            case HIGHSPEED:
+                slopePin->output();
+                slopePin->write(0);
+                break;
+            case NORMALSPEED:
+                slopePin->input();
+                slopePin->mode(PullNone);
+                break;
+            case STANDBY:
+                slopePin->output();
+                slopePin->write(1);
+                break;
+            default:
+                return false;
+        }
+        return true;
+    } else
+        return false;
+}
+
+
+CANSlopeControl_T CANPort::GetSlopeControl() {
+    return slopeMode;
+}
+
+
+bool CANPort::SetBitRate(int rate) {
+    if (can->frequency(rate)) {
+        bitRate = rate;
+        return true;
+    } else {
+        return false;
+    }
+}
+
+
+int CANPort::GetBitRate() {
+    return bitRate;
+}
+
+
+int CANPort::GetTxCounter() {
+    return txCounter;
+}
+
+
+int CANPort::GetRxCounter() {
+    return rxCounter;
+}
+
+
+int CANPort::GetTxErrorCounter() {
+    return can->tderror();
+}
+
+
+int CANPort::GetRxErrorCounter() {
+    return can->rderror();
+}
+
+
+bool CANPort::ResetChip() {
+    can->reset();
+    return true;
+}
+
+
+void CANPort::PrintInfo(Serial * stream) {
+    if (stream) {
+        stream->printf("\r\n");
+        stream->printf("  Register:       CAN1       CAN2      Register:       CAN1       CAN2\r\n");
+        stream->printf("       MOD:   %08X   %08X    ", LPC_CAN1->MOD, LPC_CAN2->MOD);
+        stream->printf("       GSR:   %08X   %08X\r\n", LPC_CAN1->GSR, LPC_CAN2->GSR);
+        stream->printf("       ICR:   %08X   %08X    ", LPC_CAN1->ICR, LPC_CAN2->ICR);
+        stream->printf("       IER:   %08X   %08X\r\n", LPC_CAN1->IER, LPC_CAN2->IER);
+        stream->printf("       BTR:   %08X   %08X    ", LPC_CAN1->BTR, LPC_CAN2->BTR);
+        stream->printf("       EWL:   %08X   %08X\r\n", LPC_CAN1->EWL, LPC_CAN2->EWL);
+        stream->printf("        SR:   %08X   %08X    ", LPC_CAN1->SR,  LPC_CAN2->SR );
+        stream->printf("       RFS:   %08X   %08X\r\n", LPC_CAN1->RFS, LPC_CAN2->RFS);
+        stream->printf("       RID:   %08X   %08X    ", LPC_CAN1->RID, LPC_CAN2->RID);
+        stream->printf("       RDA:   %08X   %08X\r\n", LPC_CAN1->RDA, LPC_CAN2->RDA);
+        stream->printf("       RDB:   %08X   %08X    ", LPC_CAN1->RDB, LPC_CAN2->RDB);
+        stream->printf("      TFI1:   %08X   %08X\r\n", LPC_CAN1->TFI1, LPC_CAN2->TFI1);
+        stream->printf("      TID1:   %08X   %08X    ", LPC_CAN1->TID1, LPC_CAN2->TID1);
+        stream->printf("      TDA1:   %08X   %08X\r\n", LPC_CAN1->TDA1, LPC_CAN2->TDA1);
+        stream->printf("      TDB1:   %08X   %08X    ", LPC_CAN1->TDB1, LPC_CAN2->TDB1);
+        stream->printf("      TFI2:   %08X   %08X\r\n", LPC_CAN1->TFI2, LPC_CAN2->TFI2);
+        stream->printf("      TID2:   %08X   %08X    ", LPC_CAN1->TID2, LPC_CAN2->TID2);
+        stream->printf("      TDA2:   %08X   %08X\r\n", LPC_CAN1->TDA2, LPC_CAN2->TDA2);
+        stream->printf("      TDB2:   %08X   %08X    ", LPC_CAN1->TDB2, LPC_CAN2->TDB2);
+        stream->printf("      TFI3:   %08X   %08X\r\n", LPC_CAN1->TFI3, LPC_CAN2->TFI3);
+        stream->printf("      TID3:   %08X   %08X    ", LPC_CAN1->TID3, LPC_CAN2->TID3);
+        stream->printf("      TDA3:   %08X   %08X\r\n", LPC_CAN1->TDA3, LPC_CAN2->TDA3);
+        stream->printf("      TDB3:   %08X   %08X    ", LPC_CAN1->TDB3, LPC_CAN2->TDB3);
+        stream->printf("\r\n");
+    }
+}