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)

Files at this revision

API Documentation at this revision

Comitter:
WiredHome
Date:
Sun Jul 15 15:15:19 2012 +0000
Child:
1:f0b4e47d948d
Commit message:
[mbed] converted /A_CANAdapter/CANUtilities/CANPort

Changed in this revision

CANPort.cpp Show annotated file Show diff for this revision Revisions of this file
CANPort.h Show annotated file Show diff for this revision Revisions of this file
--- /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");
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/CANPort.h	Sun Jul 15 15:15:19 2012 +0000
@@ -0,0 +1,285 @@
+/// @file CANPort.h is where all the port level functionality is defined
+///
+/// This module creates the physical interface, services the hardware, and provides
+/// additional functionality on top of that (e.g. timestamp messages).
+///
+/// @todo Instead of providing a callback directly to the user code, all 
+///       callbacks should be handled in this class, and then the user 
+///       callback could be activated. In this way, the rxCounter, timestamps,
+///       and other features are preserved.
+///
+/// @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
+///
+/// History
+/// v1.01 20110608
+/// \li initial version numbered to match other CAN components
+///
+#ifndef CANPORT_H
+#define CANPORT_H
+#include "mbed.h"
+#include "CANMessage.h"
+#include "Utilities.h"      // mbed <-> Visual Studio
+
+
+typedef enum {
+    HIGHSPEED,
+    NORMALSPEED,
+    STANDBY
+} CANSlopeControl_T;
+
+typedef enum {
+    MONITOR,
+    ACTIVE
+} CANBusMode_T;
+
+/// This is the CANPort, which is the physical interface to CAN
+///
+/// This derived class has a number of additional capabilities:
+/// \li activity indicator to show receive and transmit activity per port
+/// \li slope control pin to permit controlling performance and power modes
+/// \li counters, to keep track of received and transmitted messages
+/// \li and more...
+///
+class CANPort {
+public:
+
+    /// The advanced form of the constructure to create a CANPort, name 
+    /// an activity indicator, and name a slope control pin
+    ///
+    /// This version lets you specify the receive and transmit pins
+    /// for a CANPort, indicate a pin which is used to indicate
+    /// CAN activity, both receive and transmit, and identify a slope
+    /// control pin.
+    ///
+    /// @param chNum is the user assigned channel number given to this port
+    /// @param rd is the receive pin
+    /// @param td is the transmit pin
+    /// @param activityPin is the PWM pin used to indicate CAN traffic
+    /// @param slopePin is the DigitalInOut pin used to control slope
+    /// @param slope is the initial slope setting
+    ///
+    CANPort(CANCHANNEL_T chNum, PinName rd, PinName td, PinName activityPin = NC, PinName slopePin = NC, CANSlopeControl_T slope = NORMALSPEED);
+    
+    /// Destroys the CANPort
+    virtual ~CANPort();
+
+    /// Transmit a message to the bus
+    ///
+    /// This method transmits a message to the bus.
+    ///
+    /// @param msg is a CANmsg
+    /// @returns true if the message was successfully written to CAN
+    ///
+    bool TransmitMsg(CANmsg msg);
+    
+    /// Read a message from the bus into a buffer
+    ///
+    /// This method will extract a message from the bus and put it 
+    /// in the message space provided
+    ///
+    /// @param msg is a reference to a CANmsg into which the msg is placed
+    /// @returns true if a message was received and processed
+    ///
+    bool ReceiveMsg(CANmsg &msg);
+    
+    /// This flashes the activity indicator associated with this CANPort
+    ///
+    /// If the activity indicator is configured.
+    ///
+    /// @param tx indiciates if the flash is to be a sign of xmt or rcv
+    ///        it will flash dimly for a transmit and bright for a receive
+    ///
+    void Flash(CANDIR_T tx);
+    
+    /// This extinguishes the activity indicator associated with this CANPort
+    ///
+    /// If the activity indicator is configured.
+    ///
+    void Extinguish(void);
+    
+    /// Attach a callback whenever a CAN receive interrupt is generated
+    ///
+    /// This attaches a simple callback to the CAN ISR
+    ///
+    /// @param fptr pointer to the function to be called 
+    ///
+    void Attach( void  (*fptr)(void) );
+    
+    /// Attach a callback whenever a CAN receive interrupt is generated
+    ///
+    /// This attaches a callback to the CAN ISR
+    ///
+    /// @param tptr pointer to the object to call the member function on 
+    /// @param mptr pointer to the member function to be called 
+    ///
+    template <typename T> void Attach(T * tptr, void (T::*mptr)(void)) {
+        can->attach(tptr, mptr);
+    }
+    
+    /// This provides control of the AutoReset feature
+    ///
+    /// AutoReset is a feature that permits automatically resetting the 
+    /// CAN chip when it is trapped in an error state (e.g. bus off).
+    /// The default is disabled.
+    ///
+    /// @param enable is used to enable or disable the auto reset feature
+    /// @returns true if the command was accepted
+    ///
+    bool SetAutoReset(bool enable);
+    
+    /// This returns the current state of the AutoReset feature
+    ///
+    /// Returns a value indicating the current state
+    ///
+    /// @returns true if AutoReset is enabled
+    /// @returns false if AutoReset is disabled
+    ///
+    bool GetAutoReset() { return autoReset; }
+    
+    /// This provides control to set the bus mode as active or listener only
+    ///
+    /// The CAN adapter can be placed into a monitor(LISTENER) mode (sometimes
+    /// called promiscuous mode) or into an active mode, in which case it
+    /// will send hardware acknowledge.
+    ///
+    /// @param mode is either MONITOR or ACTIVE
+    /// @returns true if the command was accepted
+    ///
+    bool SetBusMode(CANBusMode_T mode);
+    
+    /// This returns the current state of the bus mode
+    ///
+    /// @returns MONITOR if the chip is in the monitor (listen / promiscuous) mode
+    /// @returns ACTIVE if the chip is in the active mode
+    ///
+    CANBusMode_T GetBusMode();
+
+    /// This provides control to set the transceiver slope control mode
+    ///
+    /// Many CAN transceivers can be operated in one of several modes - 
+    /// \li HIGHSPEED - which supports the highest frequency of communication, but
+    ///     does tend to generate more EMI unless the cable is properly shielded
+    /// \li NORMALSPEED - which wave-shapes the rising and falling edge, and
+    ///     significantly reduces the EMI concerns, but may trade off the
+    ///     highest performance.
+    /// \li STANDBY - which puts the chip into the lowest power state, and prevents
+    ///     transmission of a message. It can typically still receive messages,
+    ///     but this mode may also be useful for other purposes (wake on CAN,
+    ///     autobaud w/o disrupting bus traffic, etc.)
+    ///
+    /// @param slope sets the slope control to one of the states HIGHSPEED, 
+    ///     NORMALSPEED, or STANDBY
+    /// @returns true if the command succeeded
+    /// @returns false if the command failed, which may be due to not having
+    ///     defined a slope control pin.
+    ///
+    bool SetSlopeControl(CANSlopeControl_T slope);
+    
+    /// This returns the current state of the slope control
+    /// 
+    /// The state is controlled by the SetSlopeControl command.
+    ///
+    /// @returns the current state; one of HIGHSPEED, NORMALSPEED, or STANDBY
+    ///
+    CANSlopeControl_T GetSlopeControl();
+
+    /// This sets the bitrate for the CAN channel
+    ///
+    /// This sets the bitrate for the CAN channel. The rate is in bits per
+    /// second. The actual bitrate and the sample point is automagically 
+    /// determined from the internal algorithms provided by the mbed library.
+    ///
+    /// This API appears redundant to the frequency api, however this one
+    /// will retain the rate setting and then permits the query of the bitrate.
+    /// 
+    /// @param rate is the desired bitrate in bits per second.
+    /// @returns true if teh command succeeded
+    ///
+    bool SetBitRate(int rate);
+    
+    /// This returns the current desired bitrate for the CAN channel
+    ///
+    /// This returns the previously set bitrate. Note that the actual bitrate
+    /// may be different, due to the internal calculations of the mbed library.
+    ///
+    /// @returns the bitrate in bits per second
+    ///
+    int GetBitRate();
+
+    /// This returns the number of messages that were sent by this CAN channel
+    ///
+    /// The counter is never reset.
+    ///
+    /// @returns the number of messages sent by this CAN channel
+    ///
+    int GetTxCounter();
+
+    /// This returns the number of messages that were received by this CAN channel
+    ///
+    /// The counter is never reset.
+    ///
+    /// @returns the number of messages received by this CAN channel
+    ///
+    int GetRxCounter();
+    
+    /// This returns the number of transmit errors
+    ///
+    /// As counted by the hardware
+    ///
+    /// @returns the number of transmit errors
+    int GetTxErrorCounter();
+    
+    /// This returns the number of receive errors
+    ///
+    /// As counted by the hardware
+    ///
+    /// @returns the number of receive errors
+    int GetRxErrorCounter();
+    
+    /// This resets the CAN interface
+    ///
+    /// Unconditionally.
+    ///
+    /// @returns true if success
+    ///
+    bool ResetChip();
+    
+    /// This writes various CAN info to the selected serial channel
+    ///
+    /// When supplied with a Serial port channel, this will output
+    /// some possibly interesting information about the CAN configuration.
+    /// It does not output details for only the active objects channel,
+    /// rather it outputs information about the CAN subsystem.
+    ///
+    /// @param stream is the handle of a serial channel
+    /// @returns nothing
+    ///
+    void PrintInfo(Serial * stream);
+
+private:
+    CANCHANNEL_T channel;       // user assigned port number of this port
+    CAN * can;                  // bind to a specific CAN
+    CANBusMode_T busMode;       // monitor or active mode
+    int bitRate;                // bit rate for this bus
+    PwmOut * activityPin;       // LED to indicate activity
+    Timeout activityTimeout;    // used to extinguish the LED
+
+    DigitalInOut * slopePin;    // pin used to control the transceiver slope modes
+    PinName slopePinName;
+    CANSlopeControl_T slopeMode;// current mode
+
+    bool autoReset;             // true when auto reset on error is enabled
+    uint32_t txCounter;
+    uint32_t rxCounter;
+};
+
+#endif // CANPORT_H