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:
- 5:22a337cdc0e3
- Parent:
- 4:2034b04c86d2
--- a/source/Node.cpp Sat Jan 09 17:15:29 2016 +0000 +++ b/source/Node.cpp Sat Feb 13 20:22:59 2016 +0000 @@ -36,84 +36,17 @@ 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) +Node::Node (int id, ServiceProvider * pProvider, int bLoop) +{ + nodeId = id; - /*========================================================================= - * 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 - *========================================================================= - */ + state.nmtState = State::INITIALIZED; - /** 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; + bLoopbackOn = bLoop; -Node::Node (ServiceProvider * pProvider) -{ pMyProvider = pProvider; - pProvider->AddNode(this); + pProvider->AddNode(this); } /*============================================================================= @@ -121,29 +54,41 @@ *============================================================================= */ -int Node::DispatchMessage(CanOpenMessage *msg) +int Node::DispatchMessage(CanOpenMessage *canOpenMsg) { - int command = MESSAGE_GET_COMMAND(msg->id); - int nodeId = MESSAGE_GET_NODEID(msg->id); + int command = MESSAGE_GET_COMMAND(canOpenMsg->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]); + printf(" NMT Control: \r\n"); + HandleNodeControl(canOpenMsg); + break; + + case CANOPEN_FUNCTION_CODE_PDO1T: + case CANOPEN_FUNCTION_CODE_PDO1R: + case CANOPEN_FUNCTION_CODE_PDO2T: + case CANOPEN_FUNCTION_CODE_PDO2R: + case CANOPEN_FUNCTION_CODE_PDO3T: + case CANOPEN_FUNCTION_CODE_PDO3R: + case CANOPEN_FUNCTION_CODE_PDO4T: + case CANOPEN_FUNCTION_CODE_PDO4R: + if (state.bPDO) { + HandlePdo(canOpenMsg); } break; + + case CANOPEN_FUNCTION_CODE_SDOT: + case CANOPEN_FUNCTION_CODE_SDOR: + if (state.bSDO) { + HandleSdo(canOpenMsg); + } + break; + default: - printf("*** N.Dispatch: some random message\r\n"); + printf(" some random message\r\n"); break; } - // ECHO *********************** - pMyProvider->PostMessage(msg); - // END ECHO ******************* - return 1; } @@ -152,14 +97,191 @@ *============================================================================= */ -int Node::ConsumePdo (const int pdoNum, char *const data) +static void CopyBits(uint8_t *sourceData, + uint8_t *destData, + uint8_t mappedBits, + uint8_t &sourceBitNum, + uint8_t &destBitNum); + +int Node::HandlePdo (CanOpenMessage *canOpenMsg) { - return 0; + printf(" RPDO:\r\n"); + + int result = 0; + + if (CANOPEN_TYPE_REMOTE == canOpenMsg->type) { + + } else { + int pdoNum = 0; + int bSearching = 1; + + ObjectData * parameterObject; + + /* search through PDO parameters until we find a match */ + while (bSearching) { + + //printf(" PDO %d?", pdoNum); + parameterObject = ScanIndex (0x1400 + pdoNum); + if (parameterObject) { + + uint32_t *cobId = (uint32_t*) parameterObject->entries[1].pData; + if (canOpenMsg->id == *cobId) { + bSearching = 0; + + //printf(" ... match!!!\r\n"); + } else { + pdoNum++; + //printf(" ... nope\r\n"); + } + + } else { + bSearching = 0; + printf("\r\n ERROR: No PDO Parameter match found\r\n"); + } + + + } + + /* if a matching parameter object was found then get mapping */ + if (parameterObject) { + + ObjectData *mappingObject = ScanIndex (0x1600 + pdoNum); + + if (mappingObject) { + SubIndexSize *numMappedVariables = (SubIndexSize*) mappingObject->entries[0].pData; + + /* variable to track position in data copy */ + uint8_t sourceBitNum = 0; + + int bError = 0; + + /* for each mapped variable, write in data from message */ + for (SubIndexSize subIndexIterator = 1; subIndexIterator <= *numMappedVariables && !bError; subIndexIterator++) { + + uint32_t *map = (uint32_t*)mappingObject->entries[subIndexIterator].pData; + + uint8_t mappedBits = (uint8_t) (*map); + uint8_t mappedBytes = mappedBits / 8; + SubIndexSize mappedSubIndex = (SubIndexSize) (*map >> 8); + IndexSize mappedIndex = (IndexSize) (*map >> 16); + + printf(" mapped: %#06x, %#04x, %d\r\n", + mappedIndex, mappedSubIndex, mappedBits); + + /* if less than 0x1000 then it is a dummy value */ + if (mappedIndex < 0x1000) { + sourceBitNum += mappedBits; + } else { + + /* get the index object */ + ObjectData *mappedObject = ScanIndex (mappedIndex); + if (mappedObject) { + + /* get the subindex object */ + if (mappedSubIndex <= *(SubIndexSize*) mappedObject->entries[0].pData) { + + EntryData *destinationEntry = &mappedObject->entries[mappedSubIndex]; + + /* can we write to it? */ + if (!(destinationEntry->properties & EntryData::PROPERTY_WRITEABLE)) { + printf(" ERROR: Mapped SubIndex is not writeable!\r\n"); + bError = 1; + } + + uint8_t sourceByteNum = sourceBitNum / 8; + if (sourceByteNum + mappedBytes > canOpenMsg->dataCount) { + printf(" ERROR: Insufficient mapped data remaining!\r\n"); + bError = 1; + } + + if (destinationEntry->size < mappedBytes) { + printf(" ERROR: Too much data to pack into destination!\r\n"); + bError = 1; + } + + if (!bError) { + + //printf(" No Errors, copying data...\r\n"); + + uint8_t* destData = (uint8_t*) destinationEntry->pData; + uint8_t* sourceData = canOpenMsg->data; + + uint8_t destBitNum = 0; + CopyBits(sourceData, destData, mappedBits, sourceBitNum, destBitNum); + } + + } else { + printf(" ERROR: Mapped SubIndex does not exist!\r\n"); + bError = 1; + } + + } else { + printf(" ERROR: Mapped Index does not exist!\r\n"); + bError = 1; + } + + } /* if mappedIndex < 0x1000 */ + + + } /* for each mapping */ + + if (!bError) { + result = 1; + } + + } else { + printf(" ERROR: No PDO Mapping match found\r\n"); + } + + } /* if parameter exists */ + + } /* if remote message */ + + return result; } -int Node::HandlePdoReadRequest (const int pdoNum) + +int Node::HandleSdo (CanOpenMessage *canOpenMsg) { - return 0; + + printf(" SDO:\r\n"); + + int result = 0; + + int bSearching = 1; + + int sdoNum = 0; + int sdoType = 0; /* 0=unknown, 1=receive/server, 2=transmit/client */ + ObjectData * sdoObject; + + /* search through PDO parameters until we find a match */ + while (bSearching) { + + sdoObject = ScanIndex (0x1200 + sdoNum); + if (sdoObject) { + + uint32_t *receiveCobId = (uint32_t*) sdoObject->entries[1].pData; + uint32_t *transmitCobId = (uint32_t*) sdoObject->entries[2].pData; + + if (canOpenMsg->id == *receiveCobId) { + bSearching = 0; + sdoType = 1; + printf(" Receive SDO\r\n"); + } else if (canOpenMsg->id == *transmitCobId) { + bSearching = 0; + sdoType = 2; + printf(" Transmit SDO\r\n"); + } + + } else { + printf(" ERROR: No SDO parameters found"); + bSearching = 0; + } + + sdoNum++; + } + + return result; } int Node::ConsumeEmergency (void) @@ -167,84 +289,109 @@ return 0; } -int Node::HandleNodeControl (int commandSpecifier) +int Node::HandleNodeControl (CanOpenMessage *canOpenMsg) { int result = 0; - switch (commandSpecifier) { - case NMT_CS_START: - if (State::INITIALIZED != state.nmtState) { - state.nmtState = State::OPERATIONAL; + if (canOpenMsg->data[0] == nodeId) { + + int commandSpecifier = (int)canOpenMsg->data[1]; + + switch (commandSpecifier) { + case NMT_CS_START: + printf(" NMT_CS_START\r\n"); + if ((State::INITIALIZED == state.nmtState) || + (State::PREOPERATIONAL == state.nmtState) || + (State::STOPPED == 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 = 1; - state.bLSS = 0; - OnOperational(); + state.bPDO = 0; + state.bLSS = 1; + OnPreoperational(); result = 1; - } - break; + break; - case NMT_CS_STOP: - if (State::INITIALIZED != state.nmtState) { - state.nmtState = State::STOPPED; - state.bBoot = 0; + case NMT_CS_RESET_NODE: + case NMT_CS_RESET_COM: + printf(" NMT_CS_RESET\r\n"); + + 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(nodeId, &msgBoot); + + OnInitialize(); + + 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; - } - 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; + + OnPreoperational(); - 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; + result = 1; + break; - default: - break; + default: + break; + } + } return result; @@ -265,29 +412,256 @@ *============================================================================= */ +void Node::FixedUpdate (uint32_t time) +{ + timeSinceLastTick = time - timeCurrentTick; + timeCurrentTick = time; + + if (State::OPERATIONAL == state.nmtState) { + OnFixedUpdate(); + } + +} + void Node::Update (void) { - if (State::OPERATIONAL == state.nmtState) { + 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 + * Other Member Functions *============================================================================= */ +int Node::PostTPDO (int specifiedCobId) +{ + printf(" TPDO:\r\n"); + + int result = 0; + + /* initialize a blank message -------------------------------------------*/ + CanOpenMessage msg; + + msg.id = specifiedCobId; + msg.dataCount = 0; + msg.type = CANOPEN_TYPE_DATA; + msg.format = CANOPEN_FORMAT_STANDARD; + + msg.data[0] = 0; + msg.data[1] = 0; + msg.data[2] = 0; + msg.data[3] = 0; + msg.data[4] = 0; + msg.data[5] = 0; + msg.data[6] = 0; + msg.data[7] = 0; + + int pdoNum = 0; + int bSearching = 1; + + /* Find the mapped data and send ----------------------------------------*/ + + ObjectData * parameterObject; + + /* search through PDO parameters until we find a match */ + while (bSearching) { + + //printf(" PDO %d?", pdoNum); + parameterObject = ScanIndex (0x1800 + pdoNum); + if (parameterObject) { + + uint32_t *cobId = (uint32_t*) parameterObject->entries[1].pData; + if (specifiedCobId == *cobId) { + bSearching = 0; + + //printf(" ... match!!!\r\n"); + } else { + pdoNum++; + //printf(" ... nope\r\n"); + } + + } else { + bSearching = 0; + printf("\r\n ERROR: No PDO Parameter match found\r\n"); + } + } + + /* if a matching parameter object was found then get mapping */ + if (parameterObject) { + + ObjectData *mappingObject = ScanIndex (0x1A00 + pdoNum); + + if (mappingObject) { + SubIndexSize *numMappedVariables = (SubIndexSize*) mappingObject->entries[0].pData; + + //printf(" numMappedVariables: %d\r\n", *numMappedVariables); + + /* variable to track position in data copy */ + uint8_t destBitNum = 0; + + int bError = 0; + + /* for each mapped variable, write in data from message */ + for (SubIndexSize subIndexIterator = 1; subIndexIterator <= *numMappedVariables && !bError; subIndexIterator++) { + + uint32_t *map = (uint32_t*)mappingObject->entries[subIndexIterator].pData; + + uint8_t mappedBits = (uint8_t) (*map); + uint8_t mappedBytes = mappedBits / 8; + SubIndexSize mappedSubIndex = (SubIndexSize) (*map >> 8); + IndexSize mappedIndex = (IndexSize) (*map >> 16); + + msg.dataCount += mappedBytes; + + //printf(" mapped: %#06x, %#04x, %d\r\n", + // mappedIndex, mappedSubIndex, mappedBits); + + /* if less than 0x1000 then it is a dummy value */ + if (mappedIndex < 0x1000) { + destBitNum += mappedBits; + //printf(" No Errors, skipping VOID data...\r\n"); + } else { + + /* push into the TPDO data */ + ObjectData *mappedObject = ScanIndex (mappedIndex); + if (mappedObject) { + + /* get the subindex object */ + if (mappedSubIndex <= *(SubIndexSize*) mappedObject->entries[0].pData) { + + EntryData *sourceEntry = &mappedObject->entries[mappedSubIndex]; + + /* can we write to it? */ + if (!(sourceEntry->properties & EntryData::PROPERTY_READABLE)) { + printf(" ERROR: Mapped SubIndex is not readable!\r\n"); + bError = 1; + } + + uint8_t destByteNum = destBitNum / 8; + if (destByteNum + mappedBytes > 8) { + printf(" ERROR: Too much data to pack into destination!\r\n"); + bError = 1; + } + + if (sourceEntry->size < mappedBytes) { + printf(" ERROR: trying to grab too much information!\r\n"); + bError = 1; + } + + if (!bError) { + + //printf(" No Errors, copying data...\r\n"); + + uint8_t *destData = msg.data; + uint8_t *sourceData = (uint8_t*)sourceEntry->pData; + + uint8_t sourceBitNum = 0; + CopyBits(sourceData, destData, mappedBits, sourceBitNum, destBitNum); + } + + } else { + printf(" ERROR: Mapped SubIndex does not exist!\r\n"); + bError = 1; + } + + } else { + printf(" ERROR: Mapped Index does not exist!\r\n"); + bError = 1; + } + + } /* if mappedIndex < 0x1000 */ + + + } /* for each mapping */ + + if (!bError) { + result = 1; + + /* Send the message we built up */ + pMyProvider->PostMessage(nodeId, &msg); + } + + } else { + printf(" ERROR: No PDO Mapping match found\r\n"); + } /* if mappingObject exists */ + + } /* if parameter exists */ + + + return result; +} + +/*============================================================================= + * Private functions + *============================================================================= + */ + +void ChangeState(int newState) { + +} + /*============================================================================= * Local functions *============================================================================= */ +void CopyBits(uint8_t *sourceData, + uint8_t *destData, + uint8_t mappedBits, + uint8_t &sourceBitNum, + uint8_t &destBitNum) +{ + uint8_t sourceByteNum; + uint8_t destByteNum; + uint8_t bitCounter = 0; + + if ((mappedBits % 8) == 0 && (sourceBitNum % 8) == 0 && (destBitNum % 8) == 0) { + + //printf(" Loading BYTEwise...\r\n"); + /* load in by bytes */ + uint8_t destByteNum = 0; + while (bitCounter < mappedBits) { + + + destByteNum = destBitNum / 8; + sourceByteNum = sourceBitNum / 8; + + destData[destByteNum] = sourceData[sourceByteNum]; + + destBitNum += 8; + sourceBitNum += 8; + bitCounter += 8; + } + + } else { + + + //printf(" Loading BITwise..."); + /* not a multiple of 8, so do bit by bit */ + while (bitCounter < mappedBits) { + + destByteNum = destBitNum / 8; + sourceByteNum = sourceBitNum / 8; + + /* clear the destination bit */ + destData[destByteNum] &= ~(1 << destBitNum); + /* get source bit value */ + uint8_t destValue = (sourceData[sourceByteNum] & (1 << (sourceBitNum % 8))) >> (sourceBitNum % 8) << destBitNum; + /* set dest bit */ + destData[destByteNum] |= destValue; + + destBitNum++; + sourceBitNum++; + bitCounter++; + } + } +} /*============================================================================= - *============================================================================= + *============================================================================= * Methods to handle message requests and responses * Called by the node, usually during Update() or during handling of * incoming messages. @@ -303,45 +677,45 @@ * @note * @param */ -void RequestPdo (int pdoNum){} +void RequestPdo (int pdoNum) {} /** Build and send a PDO * @note * @param */ -void ProducePdo (int pdoNum, char * data){} +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 + * 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){} +void DownloadSdo (int sdoNum, int index, int subindex, int size, char * data) {} /** initiate SDO upload - * @note + * @note * @param */ -void UploadSdo (int sdoNum, int index, int subindex){} +void UploadSdo (int sdoNum, int index, int subindex) {} /** Acknowledge that SDO was recieved properly - * @note + * @note * @param */ -void ConfirmSdo (int sdoNum, int bSuccess){} +void ConfirmSdo (int sdoNum, int bSuccess) {} /** Abort current SDO transfer - * @note + * @note * @param */ -void AbortSdo (int sdoNum){} +void AbortSdo (int sdoNum) {} /* Emergency object (7.2.7) ---------------------------------------------*/ @@ -356,7 +730,10 @@ * @note * @param */ -int SendNodeControl (NmtCommandSpecifier cs, unsigned int nodeId){return 0;} +int SendNodeControl (NmtCommandSpecifier cs, unsigned int nodeId) +{ + return 0; +} /* ---- Error Control (7.2.8.2.2) ---------------------------------------*/ @@ -365,13 +742,19 @@ * @note * @param */ -int RequestErrorControl (NmtCommandSpecifier cs, unsigned int nodeId){return 0;} +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;} +int RespondErrorControl (NmtCommandSpecifier cs, unsigned int nodeId) +{ + return 0; +} } /* namspace ppCANOpen */