library for C++ CANOpen implementation. mbed independant, but is easy to attach into with mbed.

Dependents:   ppCANOpen_Example DISCO-F746NG_rtos_test

Example:

Import programppCANOpen_Example

I am no longer actively working on the ppCANOpen library, however, I want to publish this project so that anyone who wants to pick up any of the pieces can have a good example. This is a a project I was working on using the ppCANOpen library. It has a pretty in deep use of the object dictionary structure. And a number of functions to control high voltage pinball drivers, if you're into that sort of thing.

source/Node.cpp

Committer:
ptpaterson
Date:
2016-01-09
Revision:
4:2034b04c86d2
Parent:
3:12b3c25bdeba
Child:
5:22a337cdc0e3

File content as of revision 4:2034b04c86d2:

/**
 ******************************************************************************
 * @file
 * @author  Paul Paterson
 * @version
 * @date    2015-12-14
 * @brief   CANOpen implementation library
 ******************************************************************************
 * @attention
 *
 * <h2><center>&copy; COPYRIGHT(c) 2015 Paul Paterson
 *
 * All rights reserved.

 This program is free software: you can redistribute it and/or modify
 it under the terms of the GNU General Public License as published by
 the Free Software Foundation, either version 3 of the License, or
 (at your option) any later version.

 This program is distributed in the hope that it will be useful,
 but WITHOUT ANY WARRANTY; without even the implied warranty of
 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 GNU General Public License for more details.

 You should have received a copy of the GNU General Public License
 along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

#include "Node.h"
#include "ServiceProvider.h"
#include "ObjectDictionary.h"

#include "CanOpenMessage.h"

#include <stdio.h>

namespace ppCANOpen
{
    

    /** CANOpen Function Codes */
    typedef enum {
        CANOPEN_FUNCTION_CODE_NMT        = 0x00,
        CANOPEN_FUNCTION_CODE_SYNC       = 0x01,
        CANOPEN_FUNCTION_CODE_TIME       = 0x02,
        CANOPEN_FUNCTION_CODE_PDO1T      = 0x03,
        CANOPEN_FUNCTION_CODE_PD01R      = 0x04,
        CANOPEN_FUNCTION_CODE_PD02T      = 0x05,
        CANOPEN_FUNCTION_CODE_PD02R      = 0x06,
        CANOPEN_FUNCTION_CODE_PD03T      = 0x07,
        CANOPEN_FUNCTION_CODE_PD03R      = 0x08,
        CANOPEN_FUNCTION_CODE_PD04T      = 0x09,
        CANOPEN_FUNCTION_CODE_PD04R      = 0x0A,
        CANOPEN_FUNCTION_CODE_SD0T       = 0x0B,
        CANOPEN_FUNCTION_CODE_SD0R       = 0x0C,
        CANOPEN_FUNCTION_CODE_NODE_GUARD = 0x0E,
        CANOPEN_FUNCTION_CODE_LSS        = 0x0F
    } CanOpenFunctionCodes;

    /* Message Constants */
    #define MESSAGE_NODEID_BITS     0b00001111111
    #define MESSAGE_COMMAND_BITS    0b11110000000

    /* Message Macros -----------------------------------------------------------*/ 
    #define MESSAGE_GET_NODEID(cobId)   (cobId & MESSAGE_NODEID_BITS)
    #define MESSAGE_GET_COMMAND(cobId)  ((cobId & MESSAGE_COMMAND_BITS) >> 7)

    /*=========================================================================
     * SDO MESSAGE PARAMETERS
     *=========================================================================
     */
    
    /** SDO initiate protocol command specifiers */
    typedef enum {
         SDO_CCS_DOWNLOAD_SEGMENT_REQUEST   = 0x00, 
         SDO_CCS_INITIATE_DOWNLOAD_REQUEST  = 0x01,
         SDO_CCS_INITIATE_UPLOAD_REQUEST    = 0x02,
    } SdoClientCommandSpecifier;
    
    /** SDO segment protocol command specifiers */
    typedef enum {
         SDO_SCS_DOWNLOAD_SEGMENT_RESPONSE  = 0x01,
         SDO_SCS_INITIATE_UPLOAD_RESPONSE   = 0x02,
         SDO_SCS_INITIATE_DOWNLOAD_RESPONSE = 0x03,
    } SdoServerCommandSpecifier;
    
    /* SDO constants --------------------------------------------------------*/
    #define SDO_SIZE_INDICATOR_BIT  0b00000001
    #define SDO_TRANSFER_TYPE_BIT   0b00000010
    #define SDO_DATA_COUNT_BITS     0b00001100
    #define SDO_TOGGLE_BIT          0b00010000
    #define SDO_CS_BITS             0b11100000
    
    /* SDO macros -----------------------------------------------------------*/ 
    #define SDO_GET_CS(data0)           ((data0 & SDO_CS_BITS) >> 5)
    #define SDO_GET_DATA_COUNT(data0)   ((data0 & SDO_DATA_COUNT_BITS) >> 2)
    
    
    /*=========================================================================
     * NMT MESSAGE PARAMETERS
     *=========================================================================
     */

    /** NMT node control protocol command specifiers */
    typedef enum {
         NMT_CS_START       = 0x01,
         NMT_CS_STOP        = 0x02,
         NMT_CS_ENTER_PREOP = 0x80,
         NMT_CS_RESET_NODE  = 0x81,
         NMT_CS_RESET_COM   = 0x82
    } NmtCommandSpecifier;

Node::Node (ServiceProvider * pProvider)
{
    pMyProvider = pProvider;
    pProvider->AddNode(this);
}

/*=============================================================================
 * Methods to handle message indication and confirmation
 *=============================================================================
 */

int Node::DispatchMessage(CanOpenMessage *msg)
{
    int command = MESSAGE_GET_COMMAND(msg->id);
    int nodeId  = MESSAGE_GET_NODEID(msg->id);

    //printf("*** N.Dispatch: got com and id\r\n");
    
    switch (command) {
        case CANOPEN_FUNCTION_CODE_NMT:
            printf("*** N.Dispatch: it's an NMT Control!!!\r\n");
            if (msg->data[0] == nodeId) {
                HandleNodeControl ((int)msg->data[1]);
            }
            break;
        default:
            printf("*** N.Dispatch: some random message\r\n");
            break;
    }

    // ECHO ***********************
    pMyProvider->PostMessage(msg);
    // END ECHO *******************

    return 1;
}

/*=============================================================================
 * Methods to handle message indication and confirmation
 *=============================================================================
 */

int Node::ConsumePdo (const int pdoNum, char *const data)
{
    return 0;
}

int Node::HandlePdoReadRequest (const int pdoNum)
{
    return 0;
}

int Node::ConsumeEmergency (void)
{
    return 0;
}

int Node::HandleNodeControl (int commandSpecifier)
{
    int result = 0;

    switch (commandSpecifier) {
        case NMT_CS_START:
            if (State::INITIALIZED != state.nmtState) {
                state.nmtState = State::OPERATIONAL;
                state.bBoot         = 0;
                state.bSDO          = 1;
                state.bEmergency    = 1;
                state.bSYNC         = 1;
                state.bLifeGuard    = 1;
                state.bPDO          = 1;
                state.bLSS          = 0;
                OnOperational();
                result = 1;
            }
            break;

        case NMT_CS_STOP:
            if (State::INITIALIZED != state.nmtState) {
                state.nmtState = State::STOPPED;
                state.bBoot         = 0;
                state.bSDO          = 0;
                state.bEmergency    = 0;
                state.bSYNC         = 0;
                state.bLifeGuard    = 1;
                state.bPDO          = 0;
                state.bLSS          = 1;
            }
            OnStopped();
            result = 1;
            break;

        case NMT_CS_ENTER_PREOP:
            state.nmtState = State::PREOPERATIONAL;
            state.bBoot         = 0;
            state.bSDO          = 1;
            state.bEmergency    = 1;
            state.bSYNC         = 1;
            state.bLifeGuard    = 1;
            state.bPDO          = 0;
            state.bLSS          = 1;
            OnPreoperational();
            result = 1;
            break;

        case NMT_CS_RESET_NODE:
        case NMT_CS_RESET_COM:
            
            state.nmtState      = State::INITIALIZED;
            state.bBoot         = 1;
            state.bSDO          = 0;
            state.bEmergency    = 0;
            state.bSYNC         = 0;
            state.bLifeGuard    = 0;
            state.bPDO          = 0;
            state.bLSS          = 0;
            
            state.bLifeGuardToggle = 0;
            
            /* boot message is actually just the first node guard/ heart beat message */
            // TODO: wrap up into heartbeat/lifeguard message             
            CanOpenMessage msgBoot;
            msgBoot.id      = CANOPEN_FUNCTION_CODE_NODE_GUARD | 5;
            msgBoot.format  = CANOPEN_FORMAT_STANDARD;
            msgBoot.type    = CANOPEN_TYPE_DATA;
            msgBoot.dataCount = 1;
            msgBoot.data[0] = 0;
            
            pMyProvider->PostMessage(&msgBoot);
            
            result = 1;
            break;

        default:
            break;
    }

    return result;
}

int Node::HandleNodeGuardRequest (const int masterId)
{
    return 0;
}

int Node::ConsumeHeartbeat (const int producerId)
{
    return 0;
}

/*=============================================================================
 * Methods to handle operation of node device
 *=============================================================================
 */

void Node::Update (void)
{
    if (State::OPERATIONAL == state.nmtState) {
        OnUpdate();
    }
    
    // TODO: check elapsed time to see if it is time for fixed update
}

/*=============================================================================
 * Methods to implement node control in derived classes
 *=============================================================================
 */

/*=============================================================================
 * Local functions
 *=============================================================================
 */



/*=============================================================================
 *============================================================================= 
 * Methods to handle message requests and responses
 * Called by the node, usually during Update() or during handling of
 * incoming messages.
 *
 * Removed from Service ProviderClass.  Not sure if we will need these in the future
 *=============================================================================
 *=============================================================================
 */

/* PDO (7.2.2), MPDO (7.2.3) --------------------------------------------*/

/** Build and send a PDO request
 *  @note
 *  @param
 */
void RequestPdo (int pdoNum){}

/** Build and send a PDO
 *  @note
 *  @param
 */
void ProducePdo (int pdoNum, char * data){}


/* SDO (7.2.4) ----------------------------------------------------------*/

/** initiate SDO download
 *  @note Handles automatically whether it will be a expedited transfer or
 *  or if message will be split into   
 *  @param
 *
 *  Node will create a big data array and Service provide will have to
 *  iterate through and send all of the data.  ServiceProvider will pass
 *  the confirmation to the node, and the node will free up it's buffer.
 */
void DownloadSdo (int sdoNum, int index, int subindex, int size, char * data){}

/** initiate SDO upload
 *  @note 
 *  @param
 */
void UploadSdo (int sdoNum, int index, int subindex){}

/** Acknowledge that SDO was recieved properly
 *  @note 
 *  @param
 */
void ConfirmSdo (int sdoNum, int bSuccess){}

/** Abort current SDO transfer
 *  @note 
 *  @param
 */
void AbortSdo (int sdoNum){}


/* Emergency object (7.2.7) ---------------------------------------------*/

// TODO: emergency producer


/* Network Management (7.2.8) -------------------------------------------*/
/* ---- Node Control (7.2.8.2.1) ----------------------------------------*/

/** Build a CANOpen nmt control message to a node
 *  @note
 *  @param
 */
int  SendNodeControl (NmtCommandSpecifier cs, unsigned int nodeId){return 0;}


/* ---- Error Control (7.2.8.2.2) ---------------------------------------*/

/** Build a CANOpen error control request to a node
 *  @note
 *  @param
 */
int  RequestErrorControl (NmtCommandSpecifier cs, unsigned int nodeId){return 0;}

/** Build a CANOpen error control response
 *  @note
 *  @param
 */
int  RespondErrorControl (NmtCommandSpecifier cs, unsigned int nodeId){return 0;}


} /* namspace ppCANOpen */