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)

CANPort.cpp

Committer:
WiredHome
Date:
2012-07-15
Revision:
0:7b81b19d9b10
Child:
1:f0b4e47d948d

File content as of revision 0:7b81b19d9b10:

/// @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");
    }
}