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.

Revision:
4:2034b04c86d2
Parent:
3:12b3c25bdeba
Child:
5:22a337cdc0e3
--- a/source/Node.cpp	Mon Jan 04 06:10:49 2016 +0000
+++ b/source/Node.cpp	Sat Jan 09 17:15:29 2016 +0000
@@ -30,12 +30,90 @@
 #include "ServiceProvider.h"
 #include "ObjectDictionary.h"
 
+#include "CanOpenMessage.h"
+
+#include <stdio.h>
+
 namespace ppCANOpen
 {
+    
 
-Node::Node (ServiceProvider * provider) 
+    /** 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)
 {
-    provider->AddNode(this);
+    pMyProvider = pProvider;
+    pProvider->AddNode(this);
 }
 
 /*=============================================================================
@@ -43,21 +121,29 @@
  *=============================================================================
  */
 
-int Node::DispatchMessage(CanOpenMessage *canOpenMsg)
+int Node::DispatchMessage(CanOpenMessage *msg)
 {
-    int command = MESSAGE_GET_COMMAND(canOpenMsg->id);
-    int nodeId = MESSAGE_GET_NODEID(canOpenMsg->id);
+    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:
-            if (canOpenMsg->data[0] == nodeId) {
-                HandleNodeControl ((int)canOpenMsg->data[1]);
+            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;
 }
 
@@ -84,11 +170,11 @@
 int Node::HandleNodeControl (int commandSpecifier)
 {
     int result = 0;
-    
+
     switch (commandSpecifier) {
         case NMT_CS_START:
-            if (state.nmtState != NMT_STATE_INITIALIZED) {
-                state.nmtState = NMT_STATE_OPERATIONAL;
+            if (State::INITIALIZED != state.nmtState) {
+                state.nmtState = State::OPERATIONAL;
                 state.bBoot         = 0;
                 state.bSDO          = 1;
                 state.bEmergency    = 1;
@@ -100,10 +186,10 @@
                 result = 1;
             }
             break;
-            
+
         case NMT_CS_STOP:
-            if (state.nmtState != NMT_STATE_INITIALIZED) {
-                state.nmtState = NMT_STATE_STOPPED;
+            if (State::INITIALIZED != state.nmtState) {
+                state.nmtState = State::STOPPED;
                 state.bBoot         = 0;
                 state.bSDO          = 0;
                 state.bEmergency    = 0;
@@ -115,9 +201,9 @@
             OnStopped();
             result = 1;
             break;
-            
+
         case NMT_CS_ENTER_PREOP:
-            state.nmtState = NMT_STATE_PREOPERATIONAL;
+            state.nmtState = State::PREOPERATIONAL;
             state.bBoot         = 0;
             state.bSDO          = 1;
             state.bEmergency    = 1;
@@ -128,10 +214,11 @@
             OnPreoperational();
             result = 1;
             break;
-            
+
         case NMT_CS_RESET_NODE:
         case NMT_CS_RESET_COM:
-            state.nmtState      = NMT_STATE_INITIALIZED;
+            
+            state.nmtState      = State::INITIALIZED;
             state.bBoot         = 1;
             state.bSDO          = 0;
             state.bEmergency    = 0;
@@ -139,14 +226,27 @@
             state.bLifeGuard    = 0;
             state.bPDO          = 0;
             state.bLSS          = 0;
-            OnInitialize();
+            
+            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;
 }
 
@@ -164,12 +264,14 @@
  * Methods to handle operation of node device
  *=============================================================================
  */
- 
+
 void Node::Update (void)
 {
-     if (NMT_STATE_OPERATIONAL == state.nmtState) {
+    if (State::OPERATIONAL == state.nmtState) {
         OnUpdate();
-     }
+    }
+    
+    // TODO: check elapsed time to see if it is time for fixed update
 }
 
 /*=============================================================================
@@ -181,8 +283,96 @@
  * 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 */