Skip to content
Open
Show file tree
Hide file tree
Changes from 28 commits
Commits
Show all changes
41 commits
Select commit Hold shift + click to select a range
dfad85a
SDO Sample
DiegoLHendrix Nov 1, 2024
35424c8
This SDO no worky
DiegoLHendrix Nov 5, 2024
dd1dd90
Merge branch 'main' of https://github.com/RIT-EVT/EVT-core into featu…
DiegoLHendrix Nov 9, 2024
c00d790
idk anymore
DiegoLHendrix Nov 9, 2024
fbeb922
Merge branch 'main' of https://github.com/RIT-EVT/EVT-core into featu…
DiegoLHendrix Nov 12, 2024
4451a8b
The voices are getting louder
DiegoLHendrix Nov 18, 2024
ae64dc7
I Start Drinking On mondays at 8:15 am
DiegoLHendrix Nov 22, 2024
028f030
Start Drinking On comapny time
DiegoLHendrix Nov 23, 2024
9169c95
Good heavens I have arrived!
DiegoLHendrix Dec 3, 2024
4c750e4
Added comments
DiegoLHendrix Dec 3, 2024
580dbfa
CANopen is my sleep paralysis demon
DiegoLHendrix Dec 6, 2024
fff86b4
Merge branch 'main' of https://github.com/RIT-EVT/EVT-core into featu…
DiegoLHendrix Dec 6, 2024
ffc8495
please work cmake
DiegoLHendrix Dec 6, 2024
f85675a
Merge branch 'main' into feature/diegolhendrix/sdo-sample
DiegoLHendrix Dec 8, 2024
6319675
Merge branch 'main' of https://github.com/RIT-EVT/EVT-core into featu…
DiegoLHendrix Dec 14, 2024
9301881
Beetlejuice Beetlejuice Beetlejuice
DiegoLHendrix Dec 16, 2024
8a9b880
I am the Oppenheimer of CAN
DiegoLHendrix Dec 17, 2024
53d5b88
Merge branch 'feature/diegolhendrix/sdo-sample' of https://github.com…
DiegoLHendrix Dec 17, 2024
ff17043
Applied Formatting Changes During GitHub Build
Dec 17, 2024
359df66
Get me out of PR review hell
DiegoLHendrix Dec 21, 2024
0563097
Applied Formatting Changes During GitHub Build
Dec 21, 2024
7ee46da
I am Tyler Durden
DiegoLHendrix Jan 3, 2025
92d8cc7
Applied Formatting Changes During GitHub Build
Jan 3, 2025
df47e01
Merge branch 'main' of https://github.com/RIT-EVT/EVT-core into featu…
DiegoLHendrix Mar 18, 2025
a651e26
Made a macro and changed registerCallBack
DiegoLHendrix Mar 18, 2025
f4aca03
Applied Formatting Changes During GitHub Build
Mar 18, 2025
83b893b
Increased size of message size in snprintf
DiegoLHendrix May 2, 2025
0c37b58
Merge branch 'main' into feature/diegolhendrix/sdo-sample
DiegoLHendrix May 24, 2025
d4f9389
Started pr changes
DiegoLHendrix Jun 7, 2025
04e4cfd
Added #ifdef to sdo canInterupt
DiegoLHendrix Jun 7, 2025
ff7c199
Deleted unnecessary comments
DiegoLHendrix Jun 12, 2025
ad442dc
Applied Formatting Changes During GitHub Build
Jun 14, 2025
221c07c
Edited more comments
DiegoLHendrix Jun 18, 2025
ea7e8b2
Fixed SDO_CONFIGURATION_1200 method in SDOCanNode.hpp
DiegoLHendrix Jul 28, 2025
3587bce
Merge branch 'main' into feature/diegolhendrix/sdo-sample
DiegoLHendrix Feb 14, 2026
59806c1
Merge branch 'main' into feature/diegolhendrix/sdo-sample
DiegoLHendrix Feb 16, 2026
9cf8008
Merge branch 'feature/diegolhendrix/sdo-sample' of https://github.com…
DiegoLHendrix Feb 16, 2026
d0dc51b
Fixed SDO methods
DiegoLHendrix Mar 14, 2026
5c1b840
Merge branch 'main' into feature/diegolhendrix/sdo-sample
DiegoLHendrix Mar 17, 2026
9532b47
Fixed UART in tpdo and rpdo after a merging error
DiegoLHendrix Mar 17, 2026
0a003be
Applied Formatting Changes During GitHub Build
Mar 17, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
34 changes: 32 additions & 2 deletions include/core/io/CANOpenMacros.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -121,16 +121,46 @@
}, \
{ \
/* SDO Server Request COBID */ \
.Key = CO_KEY(0x1200, 0x01, CO_OBJ__N__R_), \
.Key = CO_KEY(0x1200, 0x01, CO_OBJ_DN__R_), \
.Type = CO_TUNSIGNED32, \
.Data = (CO_DATA) CO_COBID_SDO_REQUEST(), \
}, \
{ /* SDO Server Response COBID */ \
.Key = CO_KEY(0x1200, 0x02, CO_OBJ__N__R_), \
.Key = CO_KEY(0x1200, 0x02, CO_OBJ_DN__R_), \
.Type = CO_TUNSIGNED32, \
.Data = (CO_DATA) CO_COBID_SDO_RESPONSE(), \
}

/**
* This macro helps create an SDO configuration range of the object dictionary.
* This lives at the key 0x1280 with 4 sub indices.
*/
#define SDO_CONFIGURATION_1280 \
{ \
/* Communication Object SDO Server */ \
.Key = CO_KEY(0x1280, 0x00, CO_OBJ_D___R_), \
.Type = CO_TUNSIGNED32, \
.Data = (CO_DATA) 0x03, \
}, \
{ \
/* SDO Server Request COBID */ \
.Key = CO_KEY(0x1280, 0x01, CO_OBJ_D___R_), \
.Type = CO_TUNSIGNED32, \
.Data = (CO_DATA) CO_COBID_SDO_REQUEST(), \
}, \
{ \
/* SDO Server Response COBID */ \
.Key = CO_KEY(0x1280, 0x02, CO_OBJ_D___R_), \
.Type = CO_TUNSIGNED32, \
.Data = (CO_DATA) CO_COBID_SDO_RESPONSE(), \
}, \
{ \
/* SDO Server Response COBID */ \
.Key = CO_KEY(0x1280, 0x03, CO_OBJ_D___R_), \
.Type = CO_TUNSIGNED8, \
.Data = (CO_DATA) 1, \
}

/**
* This macro creates an RPDO settings object. This macro itself is abstract,
* allowing it to be used with any RPDO number supported by CANOpen. To make
Expand Down
34 changes: 34 additions & 0 deletions include/core/io/CANopen.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -13,12 +13,14 @@
#include <core/dev/Timer.hpp>
#include <core/io/CAN.hpp>
#include <core/io/types/CANMessage.hpp>
#include <core/utils/log.hpp>
#include <core/utils/types/FixedQueue.hpp>

// Allows for resizable CANOpen queue if needed
#ifndef CANOPEN_QUEUE_SIZE
#define CANOPEN_QUEUE_SIZE 150
#endif
namespace log = core::log;

namespace core::io {

Expand Down Expand Up @@ -94,6 +96,38 @@ void initializeCANopenNode(CO_NODE* canNode, CANDevice* canDevice, CO_IF_DRV* ca
*/
void processCANopenNode(CO_NODE* canNode);

/**
* This function sets up and starts an SDO download (write) request to transfer data
* to the specified object dictionary entry on the target CANopen node.
*
* @param node[in] Reference to the CANopen node object
* @param data[in] Pointer to the data buffer that holds the data to send
* @param size[in] Size of the data to transfer in bytes
* @param entry[in] Object dictionary entry (index + subindex) to write to
* @return CO_ERR[out] Returns the result of the transfer operation
*/
CO_ERR SDOTransfer(CO_NODE& node, uint8_t* data, uint8_t size, uint32_t entry);

/**
* This function starts an SDO upload (read) request to fetch data from the specified
* object dictionary entry on the target CANopen node
*
* @param node[in] Reference to the CANopen node object
* @param data[in] Pointer to the buffer where received data will be stored
* @param size[in] Size of the buffer provided to receive data
* @param entry[in] Object dictionary entry (index + subindex) to read from
* @return CO_ERR[out] Returns the result of the receive operation
*/
CO_ERR SDOReceive(CO_NODE& node, uint8_t* data, uint8_t size, uint32_t entry);

/**
* This function assigns the user-provided callback function and AppContext to be
* used when an SDO operation completes
*
* @param AppCallback[in] Pointer to the callback function to register
* @param AppContext[in] Context to be passed to the callback
*/
void registerCallBack(void (*AppCallback)(CO_CSDO* csdo, uint16_t index, uint8_t sub, uint32_t code), void* AppContext);
} // namespace core::io

#endif
1 change: 1 addition & 0 deletions samples/canopen/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
add_subdirectory(canopen_rpdo)
add_subdirectory(canopen_sample)
add_subdirectory(canopen_sdo)
add_subdirectory(canopen_tpdo)
21 changes: 16 additions & 5 deletions samples/canopen/canopen_rpdo/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,10 @@
#include <core/io/UART.hpp>
#include <core/io/types/CANMessage.hpp>
#include <core/manager.hpp>
#include <core/utils/log.hpp>
#include <core/utils/time.hpp>
#include <core/utils/types/FixedQueue.hpp>
#include <string>

#include <core/io/CANopen.hpp>

Expand All @@ -19,6 +21,7 @@
namespace io = core::io;
namespace dev = core::dev;
namespace time = core::time;
namespace log = core::log;

///////////////////////////////////////////////////////////////////////////////
// EVT-core CAN callback and CAN setup. This will include logic to set
Expand All @@ -36,20 +39,26 @@ namespace time = core::time;
* @param message[in] The passed in CAN message that was read.
*/

io::UART& uart = io::getUART<io::Pin::UART_TX, io::Pin::UART_RX>(9600);

// create a can interrupt handler
void canInterrupt(io::CANMessage& message, void* priv) {
auto* queue = (core::types::FixedQueue<CANOPEN_QUEUE_SIZE, io::CANMessage>*) priv;
char messageString[50];

// print out raw received data
uart.printf("Got RAW message from %X of length %d with data: ", message.getId(), message.getDataLength());
snprintf(&messageString[5],
6,
"Got RAW message from %X of length %d with data: ",
message.getId(),
message.getDataLength());

uint8_t* data = message.getPayload();

for (int i = 0; i < message.getDataLength(); i++) {
uart.printf("%X ", *data);
snprintf(&messageString[i * 5], 1, "%X ", *data);
data++;
}
uart.printf("\r\n");

log::LOGGER.log(log::Logger::LogLevel::INFO, "\r\n\t%s\r\n", messageString);

if (queue != nullptr)
queue->append(message);
Expand All @@ -59,6 +68,8 @@ int main() {
// Initialize system
core::platform::init();

io::UART& uart = io::getUART<io::Pin::UART_TX, io::Pin::UART_RX>(9600);

// Initialize the timer
dev::Timer& timer = dev::getTimer<dev::MCUTimer::Timer2>(100);

Expand Down
4 changes: 4 additions & 0 deletions samples/canopen/canopen_sdo/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
include(../../../cmake/evt-core_build.cmake)

set( SAMPLE_SOURCES main.cpp SDOCanNode.cpp)
make_exe(canopen_sdo "${SAMPLE_SOURCES}")
69 changes: 69 additions & 0 deletions samples/canopen/canopen_sdo/SDOCanNode.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
#include "SDOCanNode.hpp"
#include <core/io/CANopen.hpp>
#include <cstdio>

SDOCanNode::SDOCanNode(CO_NODE& canNode) : node(canNode) {
sampleDataA = 0;
sampleDataB = 0;
transferBuffArray[0] = 0;
transferBuffArray[1] = 0;
}

void SDOCanNode::transferData() {
/* Increment the first element of transferBuffArray by 1. */
transferBuffArray[0]++;
/* Set the second element of transferBuffArray to twice the new value of the first element. */
transferBuffArray[1] = transferBuffArray[0] * 2;

/*
* Initiates an SDO transfer for the specified node using the provided
* transfer buffer array. Targets the object dictionary entry at index 0x2100,
* sub-index 0x02. Registers and executes the SDOTransferCallback function upon completion.
*/
CO_ERR err = core::io::SDOTransfer(node, transferBuffArray, 2, CO_DEV(0x2100, 0x02));

/* Check if the SDO transfer was successfully started. */
if (err == CO_ERR_NONE) {
/* Transfer is started successfully */
log::LOGGER.log(log::Logger::LogLevel::INFO, "SDOTransfer Sent Request");

/* Note: don't use the 'readValue' until transfer is finished! */
} else {
/* Unable to start the SDO transfer */
log::LOGGER.log(log::Logger::LogLevel::ERROR, "SDOTransfer Request Error");
}
}

void SDOCanNode::receiveData() {
static uint8_t receiveBuffArray[1];

/*
* Initiates an SDO receive operation for the specified node, reading data into
* the provided receive buffer array. Targets the object dictionary entry at
* index 0x2100, sub-index 0x01. Registers and executes the SDOReceiveCallback function upon completion.
*/
CO_ERR err = core::io::SDOReceive(node, receiveBuffArray, 1, CO_DEV(0x2100, 0x01));

/* Check if the SDO receive operation was successfully started. */
if (err == CO_ERR_NONE) {
/* Transfer is started successfully */
log::LOGGER.log(log::Logger::LogLevel::INFO, "SDOReceive Sent Request");

/* Note: don't use the 'readValue' until transfer is finished! */
} else {
/* Unable to start the SDO transfer */
log::LOGGER.log(log::Logger::LogLevel::ERROR, "SDOReceive Request Error");
}
}

CO_OBJ_T* SDOCanNode::getObjectDictionary() {
return &objectDictionary[0];
}

uint8_t SDOCanNode::getNumElements() {
return OBJECT_DICTIONARY_SIZE;
}

uint8_t SDOCanNode::getNodeID() {
return NODE_ID;
}
107 changes: 107 additions & 0 deletions samples/canopen/canopen_sdo/SDOCanNode.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
#include <core/utils/log.hpp>
#include <cstdint>

#include <co_core.h>
#include <core/io/CANDevice.hpp>
#include <core/io/CANOpenMacros.hpp>

/**
* Representation of the CAN node. Handles constructing the object
* dictionary and other baseline settings. The idea is that each "board"
* will have a specific object dictionary associated with it. The object
* dictionary itself will also need to have information on "data of interest".
* For example, a temperature management system may to expose water pump
* flow rate in the object dictionary.
*/

namespace log = core::log;

class SDOCanNode : public CANDevice {
public:
SDOCanNode(CO_NODE& canNode);

/**
* Update Object Dictionary entry
*
* @param node[in] The canopen node to write to
*/
void transferData();

/**
* Read Object Dictionary entry
*
* @param node[in] The canopen node to read from
*/
void receiveData();

/**
* Get a pointer to the start of the object dictionary
*
* @return Pointer to the start of the object dictionary
*/
CO_OBJ_T* getObjectDictionary() override;

/**
* Get the number of elements in the object dictionary.
*
* @return The number of elements in the object dictionary
*/
uint8_t getNumElements() override;

/**
* Get the device's node ID
*
* @return The node ID of the can device.
*/
uint8_t getNodeID() override;

/**
* Get the device's node ID
*
* @return The node ID of the can device.
*/
static constexpr uint8_t NODE_ID = 2;

private:
/**
* This sample data will be exposed over CAN through the object
* dictionary. The address of the variable will be included in the
* object dictionary and can be updated via SDO via a CANopen client.
* This device will then broadcast the value via a triggered PDO.
*/
uint8_t sampleDataA;
uint16_t sampleDataB;
Comment on lines +73 to +74
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You are not really using these values in your sample, are you able to use them for your transfer and receive somehow instead of a raw array?


uint8_t transferBuffArray[2]{};

CO_NODE& node;

/**
* Have to know the size of the object dictionary for initialization
* process.
*/
static constexpr uint8_t OBJECT_DICTIONARY_SIZE = 24;

/**
* The object dictionary itself. Will be populated by this object during
* construction.
*
* The plus one is for the special "end of dictionary" marker.
*/
CO_OBJ_T objectDictionary[OBJECT_DICTIONARY_SIZE + 1] = {
MANDATORY_IDENTIFICATION_ENTRIES_1000_1014,
HEARTBEAT_PRODUCER_1017(2000),
IDENTITY_OBJECT_1018,
SDO_CONFIGURATION_1200,
SDO_CONFIGURATION_1280,

// User defined data, this will be where we put elements that can be
// accessed via SDO and depending on configuration PDO
DATA_LINK_START_KEY_21XX(0, 0x02),
DATA_LINK_21XX(0x00, 0x01, CO_TUNSIGNED8, &sampleDataA),
DATA_LINK_21XX(0x00, 0x02, CO_TUNSIGNED16, &sampleDataB),
Comment on lines +100 to +104
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are you using these entries?


// End of dictionary marker
CO_OBJ_DICT_ENDMARK,
};
};
Loading