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.

Files at this revision

API Documentation at this revision

Comitter:
ptpaterson
Date:
Sat Jan 09 17:15:29 2016 +0000
Parent:
3:12b3c25bdeba
Child:
5:22a337cdc0e3
Commit message:
echo ability

Changed in this revision

drivers/mbed-Nucleo-F091RC/canopen_api.cpp Show annotated file Show diff for this revision Revisions of this file
include/CanOpenMessage.h Show annotated file Show diff for this revision Revisions of this file
include/Node.h Show annotated file Show diff for this revision Revisions of this file
include/ObjectDictionary.h Show annotated file Show diff for this revision Revisions of this file
include/ProcessDataObject.h Show annotated file Show diff for this revision Revisions of this file
include/ServiceDataObject.h Show annotated file Show diff for this revision Revisions of this file
include/ServiceProvider.h Show annotated file Show diff for this revision Revisions of this file
include/canopen_api.h Show annotated file Show diff for this revision Revisions of this file
include/canopen_protocol.h Show diff for this revision Revisions of this file
source/Node.cpp Show annotated file Show diff for this revision Revisions of this file
source/ServiceProvider.cpp Show annotated file Show diff for this revision Revisions of this file
--- a/drivers/mbed-Nucleo-F091RC/canopen_api.cpp	Mon Jan 04 06:10:49 2016 +0000
+++ b/drivers/mbed-Nucleo-F091RC/canopen_api.cpp	Sat Jan 09 17:15:29 2016 +0000
@@ -28,9 +28,13 @@
 
 #include "canopen_api.h"
 #include "canopen_config.h"
+#include "CanOpenHandle.h"
 
 #include "mbed.h"
 
+#include "CanOpenHandle.h"
+#include "CanOpenMessage.h"
+
 int CanOpenApiInit (CanOpenHandle *hCanOpen)
 {
     printf ("----------- CANOPEN API: API INIT\r\n");
@@ -54,6 +58,9 @@
 {
     int result = 0;
     
+    printf("api: can_read: Anything to read?\r\n");
+    
+    /*
     if (hCanOpen->can) {
         
         CANMessage canMsg;
@@ -78,7 +85,7 @@
         }
         
     }
-    
+    */
     return result;
 }
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/include/CanOpenMessage.h	Sat Jan 09 17:15:29 2016 +0000
@@ -0,0 +1,68 @@
+/**
+ ******************************************************************************
+ * @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/>.
+ */
+
+#ifndef PPCAN_CANOPEN_MESSAGE_H
+#define PPCAN_CANOPEN_MESSAGE_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*=========================================================================
+ * CANOpen Message Structure
+ *=========================================================================
+ */
+
+/** CANOpen Message Format */
+typedef enum {
+    CANOPEN_FORMAT_STANDARD = 0,
+    CANOPEN_FORMAT_EXTENDED,
+    CANOPEN_FORMAT_ANY
+} CanOpenFormat;
+
+/** CANOpen Message Data Type */
+typedef enum {
+    CANOPEN_TYPE_DATA = 0,
+    CANOPEN_TYPE_REMOTE
+} CanOpenType;
+
+
+/** CANOpen Message */
+typedef struct CanOpenMessage {
+    unsigned int    id;
+    char   data[8];
+    CanOpenFormat   format;
+    CanOpenType     type;
+    unsigned char   dataCount;
+} CanOpenMessage;
+
+#ifdef __cplusplus
+};
+#endif
+
+#endif /* PPCAN_CANOPEN_MESSAGE_H */
--- a/include/Node.h	Mon Jan 04 06:10:49 2016 +0000
+++ b/include/Node.h	Sat Jan 09 17:15:29 2016 +0000
@@ -29,7 +29,18 @@
 #ifndef PPCAN_NODE_H
 #define PPCAN_NODE_H
 
-#include "canopen_protocol.h"
+
+/*=========================================================================
+ * Forward declarations
+ *=========================================================================
+ */
+struct CanOpenMessage;
+
+/* NMT Constants --------------------------------------------------------*/
+#define NMT_STATE_TOGGLE_BIT      0x80
+
+/* NMT Macros -----------------------------------------------------------*/
+#define NMT_SET_STATE(curState, newState) (curState) = (((curState) & NMT_STATE_TOGGLE_BIT) | ((newState) & (~NMT_STATE_TOGGLE_BIT))))
 
 namespace ppCANOpen
 {
@@ -38,15 +49,26 @@
 class ServiceProvider;
 class ObjectDictionary;
 
+
+
 /** Node Class to implement feature of a CANOpen NMT node
  */
 class Node
 {
 public:
 
-    /** Maintain the multitude of states for a node */
-    typedef struct {
-        NmtState nmtState;
+    /** Node network management state */
+    struct State {
+        static const int INITIALIZED     = 0x00;
+        static const int DISCONNECTED    = 0x01;
+        static const int CONNECTING      = 0x02;
+        static const int PREPARING       = 0x02;
+        static const int STOPPED         = 0x04;
+        static const int OPERATIONAL     = 0x05;
+        static const int PREOPERATIONAL  = 0x7F;
+        static const int UNKNOWN         = 0x0F;
+        
+        int nmtState;
         int bBoot;
         int bSDO;
         int bEmergency;
@@ -54,7 +76,11 @@
         int bLifeGuard;
         int bPDO;
         int bLSS;
-    } State;
+        
+        int bLifeGuardToggle;
+    };
+
+    /** Maintain the multitude of states for a node */
 
     Node (ServiceProvider * provider);    
 
@@ -161,8 +187,6 @@
      * ========================================================================
      */
 
-    ServiceProvider * pMyProvider;
-
     /** object dictionary */
     ObjectDictionary * pMyDictionary;
 
@@ -173,6 +197,12 @@
      * ========================================================================
      */
      
+     
+    /** Reference to Service Provider that this node is attached to.
+      * @note May need to be a pointer, because node id is held in object dictionary
+      */
+    ServiceProvider * pMyProvider;
+     
     /** Network id for the node
       * @note May need to be a pointer, because node id is held in object dictionary
       */
--- a/include/ObjectDictionary.h	Mon Jan 04 06:10:49 2016 +0000
+++ b/include/ObjectDictionary.h	Sat Jan 09 17:15:29 2016 +0000
@@ -29,7 +29,6 @@
 #ifndef PPCAN_OBJECT_DICTIONARY_H
 #define PPCAN_OBJECT_DICTIONARY_H
 
-#include "canopen_protocol.h"
 #include <stdint.h>
 
 namespace ppCANOpen
--- a/include/ProcessDataObject.h	Mon Jan 04 06:10:49 2016 +0000
+++ b/include/ProcessDataObject.h	Sat Jan 09 17:15:29 2016 +0000
@@ -29,8 +29,6 @@
 #ifndef PPCAN_PDO_H
 #define PPCAN_PDO_H
 
-#include "canopen_protocol.h"
-
 namespace ppCANOpen
 {
 
--- a/include/ServiceDataObject.h	Mon Jan 04 06:10:49 2016 +0000
+++ b/include/ServiceDataObject.h	Sat Jan 09 17:15:29 2016 +0000
@@ -29,8 +29,6 @@
 #ifndef PPCAN_SDO_H
 #define PPCAN_SDO_H
 
-#include "canopen_protocol.h"
-
 namespace ppCANOpen
 {
 
--- a/include/ServiceProvider.h	Mon Jan 04 06:10:49 2016 +0000
+++ b/include/ServiceProvider.h	Sat Jan 09 17:15:29 2016 +0000
@@ -29,7 +29,15 @@
 #ifndef PPCAN_SERVICE_PROVIDER_H
 #define PPCAN_SERVICE_PROVIDER_H
 
-#include "canopen_protocol.h"
+#include "CanOpenMessage.h"
+#include <queue>
+
+/*=========================================================================
+ * Forward declarations
+ *=========================================================================
+ */  
+ 
+struct CanOpenHandle;
 
 namespace ppCANOpen
 {
@@ -43,117 +51,52 @@
 {
 public:
 
+    
+
     ServiceProvider (void);
     ~ServiceProvider (void);
     
-    /** Main loop
-     *  @note
-     *  @param
-     *  @retval
-     */
+    /** Main loop */
     void Run (void);
     
-    /**
-     *  @note
-     *  @param
-     *  @retval
-     */
+    /** Register a node to get messages and get update calls
+      * @note
+      * @param
+      * @retval
+      */
     int AddNode (Node * node);
     
+    /** Register a node to get messages and get update calls
+      * @note
+      * @param
+      * @retval
+      */
+      
+    /** Add a message to the message queue outbox
+      * @note
+      * @param
+      */
+    void PostMessage (CanOpenMessage * msg);
+    
     // TODO: remove node (swap pointers to fill in nicely
 private:
     
-    static const int SERVICE_MAX_NODES = 8;
-
-    /* ========================================================================
-     * Methods to handle message requests and responses
-     * Called by the node, usually during Update() or during handling of
-     * incoming messages.
-     * ========================================================================
-     */
-    
-    /* 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);
-
-
-    /* ---- 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);
-
-    /** Build a CANOpen error control response
-     *  @note
-     *  @param
-     */
-    int  RespondErrorControl (NmtCommandSpecifier cs, unsigned int nodeId);
-
+    /** define size of arrays in one place */
+    static const int SERVICE_MAX_NODES = 8;    
 
     /* ========================================================================
      * Private Members
      * ========================================================================
      */
 
+    /** array of messages in a queue
+      * @note twice number of max nodes is a bit arbitrary.  Will need at
+      * least max nodes, but not sure how much more to be safe.
+      */
+    std::queue<CanOpenMessage> outbox;
+    //CanOpenMessage outbox[SERVICE_MAX_NODES * 2];
+    //int messageCount;
+
     /** array of nodes to cycle through.
      *  @note
      */
--- a/include/canopen_api.h	Mon Jan 04 06:10:49 2016 +0000
+++ b/include/canopen_api.h	Sat Jan 09 17:15:29 2016 +0000
@@ -29,16 +29,26 @@
 #ifndef PPCAN_CANOPEN_API_H
 #define PPCAN_CANOPEN_API_H
 
-#include "canopen_protocol.h"
-
 #ifdef __cplusplus
 extern "C" {
 #endif
 
+    /*=========================================================================
+     * Forward declarations
+     *=========================================================================
+     */  
+    struct CanOpenHandle;
+    struct CanOpenMessage;
+
+    /*=========================================================================
+     * API functions
+     *=========================================================================
+     */    
+    
     int CanOpenApiInit  (CanOpenHandle * hCanOpen);
     
-    int CanOpenApiRead  (CanOpenHandle * hCanOpen, CanOpenMessage *canOpenMsg);
-    int CanOpenApiWrite (CanOpenHandle * hCanOpen, CanOpenMessage *canOpenMsg);
+    int CanOpenApiRead  (CanOpenHandle * hCanOpen, CanOpenMessage * canOpenMsg);
+    int CanOpenApiWrite (CanOpenHandle * hCanOpen, CanOpenMessage * canOpenMsg);
 
 #ifdef __cplusplus
 };
--- a/include/canopen_protocol.h	Mon Jan 04 06:10:49 2016 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,161 +0,0 @@
-/**
- ******************************************************************************
- * @file
- * @author  Paul Paterson
- * @version
- * @date    2015-12-17
- * @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/>.
- */
-
-#ifndef PPCAN_CANOPEN_PROTOCOL_H
-#define PPCAN_CANOPEN_PROTOCOL_H
-
-#include "CanOpenHandle.h"
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-    /*=========================================================================
-     * MESSAGES
-     *=========================================================================
-     */
-
-    /** CANOpen Message Format */
-    typedef enum {
-        CANOPEN_FORMAT_STANDARD = 0,
-        CANOPEN_FORMAT_EXTENDED,
-        CANOPEN_FORMAT_ANY
-    } CanOpenFormat;
-
-    /** CANOpen Message Data Type */
-    typedef enum {
-        CANOPEN_TYPE_DATA = 0,
-        CANOPEN_TYPE_REMOTE
-    } CanOpenType;
-
-    /** 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;
-
-    /** CANOpen Message */
-    typedef struct {
-        unsigned int    id;
-        char   data[8];
-        CanOpenFormat   format;
-        CanOpenType     type;
-        unsigned char   dataCount;
-    } CanOpenMessage;
-
-    
-
-    /* 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
-     *=========================================================================
-     */
-
-    /** Node network management state */
-    typedef enum NmtState {
-        NMT_STATE_INITIALIZED     = 0x00,
-        NMT_STATE_DISCONNECTED    = 0x01,
-        NMT_STATE_CONNECTING      = 0x02,
-        NMT_STATE_PREPARING       = 0x02,
-        NMT_STATE_STOPPED         = 0x04,
-        NMT_STATE_OPERATIONAL     = 0x05,
-        NMT_STATE_PREOPERATIONAL  = 0x7F,
-        NMT_STATE_UNKNOWN         = 0x0F
-    } NmtState;
-    
-    /** 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;
-    
-    /* NMT Constants --------------------------------------------------------*/
-    #define NMT_STATE_TOGGLE_BIT      0x80
-    
-    /* NMT Macros -----------------------------------------------------------*/
-    #define NMT_SET_STATE(curState, newState) (curState) = (((curState) & NMT_STATE_TOGGLE_BIT) | ((newState) & (~NMT_STATE_TOGGLE_BIT))))
-    
-#ifdef __cplusplus
-};
-#endif
-
-#endif /* PPCAN_CANOPEN_PROTOCOL */
--- 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 */
 
--- a/source/ServiceProvider.cpp	Mon Jan 04 06:10:49 2016 +0000
+++ b/source/ServiceProvider.cpp	Sat Jan 09 17:15:29 2016 +0000
@@ -29,6 +29,7 @@
 #include "ServiceProvider.h"
 #include "Node.h"
 
+#include "CanOpenHandle.h"
 #include "canopen_api.h"
 
 #include <string.h>
@@ -37,15 +38,20 @@
 namespace ppCANOpen
 {
     
+/*=============================================================================
+ * Construction
+ *=============================================================================
+ */ 
+
 ServiceProvider::ServiceProvider (void) : nodeCount(0) 
 {
-    printf ("-------- SERVICE PROVIDER: CONSTRUCTOR\r\n");
+    
+    //messageCount = 0;
     
     //memset (nodes, 0, sizeof(Node) * SERVICE_MAX_NODES ); // TODO: fix incorrect <--
     for (int i = 0; i < SERVICE_MAX_NODES; i++) {
         nodes[i] = 0;   
     }
-    printf ("-------- SERVICE PROVIDER: MEMSET GOOD\r\n");
     
     hCanOpen = new CanOpenHandle;
     CanOpenApiInit(hCanOpen);
@@ -63,8 +69,6 @@
 
 void ServiceProvider::Run (void)
 {
-    printf ("-------- SERVICE PROVIDER: RUN\r\n");
-    
     while (1) {
         
         /* Check for new messages */
@@ -72,18 +76,13 @@
         if (hCanOpen->can) {
             if (CanOpenApiRead (hCanOpen, &msg)) {
                 
+                //printf("*** SP.Run: About to dispatch\r\n");
                 /* if new message exists, give it to the nodes*/
                 /* update all of the nodes */
                 for (int i=0; i < nodeCount; i++) {
                     nodes[i]->DispatchMessage(&msg);                 
                 }
-                
-                //Node::DispatchMessage(&msg);
-                
-                //**ECHO**
-                if (CanOpenApiWrite(hCanOpen, &msg)) {
-                }
-                //**END ECHO
+                //printf("*** SP.Run: dispatched\r\n");
             }
         }    
    
@@ -91,11 +90,23 @@
         for (int i=0; i < nodeCount; i++) {
             nodes[i]->Update();            
         }
+        
+        /* send out the responses */
+        while (! outbox.empty()) {
+            
+            printf("msg id: %d\r\n", outbox.front().id);
+            if (CanOpenApiWrite(hCanOpen, &outbox.front())) {
+                outbox.pop();
+            } else {
+                   printf("Could not send last message.  Trying again\r\n");
+            }
+        }
+
     }    
 }
 
 /*=============================================================================
- * Add Node to list
+ * Register a node to get messages and get update calls
  *=============================================================================
  */ 
 
@@ -113,44 +124,15 @@
 }
 
 /* ========================================================================
- * Methods to handle message requests and responses
+ * Adds a message to the message queue outbox
  * ========================================================================
  */
 
-void ServiceProvider::RequestPdo (const int pdoNum)
-{}
-
-void ServiceProvider::ProducePdo (const int pdoNum, char * data)
-{}
-
-int  ServiceProvider::SendNodeControl (NmtCommandSpecifier cs, unsigned int targetId)
+void ServiceProvider::PostMessage (CanOpenMessage * msg)
 {
-//    CanOpenMessage canOpenMsg; 
-//    
-//    canOpenMsg.data[0]     = (char)cs;
-//    canOpenMsg.data[1]     = (char)nodeId;
-//    canOpenMsg.dataCount   = 2;
-//    canOpenMsg.type        = CANOPEN_TYPE_DATA;
-//    canOpenMsg.format      = CANOPEN_FORMAT_STANDARD;
-//    
-//    return CanOpenApiWrite (&canOpenMsg);
-
-    return 0;
+    outbox.push(*msg);
 }
 
-int  ServiceProvider::RequestErrorControl (NmtCommandSpecifier cs, unsigned int targetId)
-{
-    //NMT_STATE_SET(Node::state.nmtState, NMT_STATE_UNKNOWN);
-    return 0;    
-}
-
-int  ServiceProvider::RespondErrorControl (NmtCommandSpecifier cs, unsigned int targetId)
-{
-    //NMT_STATE_SET(Node::state.nmtState, NMT_STATE_UNKNOWN);
-    return 0;    
-}
-
-
 } /* namspace ppCANOpen */