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.
Diff: source/Node.cpp
- 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 */