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, committed 2012-07-15
- 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