parent
f5be17275a
commit
c452a91d02
@ -0,0 +1,55 @@
|
||||
cmake_minimum_required(VERSION 3.10)
|
||||
project(kyncat C)
|
||||
|
||||
# Set C standard
|
||||
set(CMAKE_C_STANDARD 99)
|
||||
set(CMAKE_C_STANDARD_REQUIRED ON)
|
||||
|
||||
# Set output directory for the compiled binary
|
||||
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${CMAKE_SOURCE_DIR}")
|
||||
set(CMAKE_BINARY_DIRECTORY "${CMAKE_SOURCE_DIR}")
|
||||
|
||||
# SOEM Repository Info
|
||||
set(SOEM_REPO "https://github.com/OpenEtherCATsociety/SOEM.git")
|
||||
set(SOEM_PATH "${CMAKE_SOURCE_DIR}/SOEM")
|
||||
|
||||
# Check if SOEM exists, if not, clone it
|
||||
if(NOT EXISTS ${SOEM_PATH}/CMakeLists.txt)
|
||||
message(STATUS "SOEM not found! Cloning from ${SOEM_REPO}...")
|
||||
execute_process(
|
||||
COMMAND git clone --depth 1 ${SOEM_REPO} ${SOEM_PATH}
|
||||
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
|
||||
RESULT_VARIABLE GIT_CLONE_RESULT
|
||||
)
|
||||
if(NOT GIT_CLONE_RESULT EQUAL 0)
|
||||
message(FATAL_ERROR "Failed to clone SOEM repository!")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
# Include SOEM as a subdirectory (it has its own CMakeLists.txt)
|
||||
add_subdirectory(${SOEM_PATH})
|
||||
|
||||
# Include directories for SOEM
|
||||
include_directories(
|
||||
${SOEM_PATH}/soem
|
||||
${SOEM_PATH}/osal
|
||||
${SOEM_PATH}/osal/linux
|
||||
${SOEM_PATH}/oshw/linux
|
||||
)
|
||||
|
||||
# Define the source files for kyncat
|
||||
set(SOURCES
|
||||
main.c
|
||||
slaveconfig.c
|
||||
)
|
||||
|
||||
set(HEADERS
|
||||
slaveconfig.h
|
||||
)
|
||||
|
||||
# Create the executable and link against the SOEM static library
|
||||
add_executable(kyncat ${SOURCES} ${HEADERS})
|
||||
|
||||
# Link SOEM library and required system libraries
|
||||
target_link_libraries(kyncat soem pthread rt)
|
||||
|
@ -0,0 +1,295 @@
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include "slaveconfig.h"
|
||||
#include "ethercat.h"
|
||||
|
||||
#define EC_TIMEOUTMON 100
|
||||
|
||||
char IOmap[4096];
|
||||
volatile int wkc;
|
||||
OSAL_THREAD_HANDLE thread1;
|
||||
int expectedWKC;
|
||||
boolean needlf;
|
||||
volatile int wkc;
|
||||
uint8 currentgroup = 0;
|
||||
|
||||
|
||||
/*!
|
||||
* @brief Set the given Slave to given State
|
||||
* @return 1 if No Error | 0 if Error
|
||||
* */
|
||||
uint8_t setSlaveState(uint8_t slave_index, uint16_t ethercat_state )
|
||||
{
|
||||
//printf("SET STATE: %s - Slave[%d] \n",ec_slave[slave_index].name, slave_index);
|
||||
ec_slave[slave_index].state = ethercat_state;// ec_slave[0] refers to a special virtual slave that represents all slaves
|
||||
ec_writestate(slave_index); // Same as above
|
||||
ec_statecheck(slave_index, ethercat_state, EC_TIMEOUTSTATE);
|
||||
|
||||
if (ec_slave[slave_index].state == ethercat_state) {
|
||||
{
|
||||
// printf(" |- ");
|
||||
// printState(ec_slave[slave_index].state);
|
||||
}
|
||||
return 1;
|
||||
} else {
|
||||
// printf(" |-> Failed\n");
|
||||
return 0;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
void searchForSlave()
|
||||
{
|
||||
for (int i = 1; i <= ec_slavecount; i++) {
|
||||
if (strcmp(ec_slave[i].name, "EL2008") == 0) {
|
||||
el2008_slave = i;
|
||||
printf("Found EL2008 at slave %d.\n", i);
|
||||
}
|
||||
}
|
||||
|
||||
if (el2008_slave == -1) {
|
||||
printf("EL2008 not found on the network.\n");
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
|
||||
void print_device_info() {
|
||||
printf("--------------------------------------------------\n");
|
||||
printf("EtherCAT Device Info Panel\n");
|
||||
printf("--------------------------------------------------\n");
|
||||
|
||||
for (int i = 1; i <= ec_slavecount; i++) {
|
||||
printf("Slave %d: %s\n", i, ec_slave[i].name);
|
||||
printf(" Vendor ID: 0x%08X\n", ec_slave[i].eep_man);
|
||||
printf(" Product Code: 0x%08X\n", ec_slave[i].eep_id);
|
||||
printf(" Revision: 0x%08X\n", ec_slave[i].eep_rev);
|
||||
printf(" ");
|
||||
printState(ec_slave[i].state);
|
||||
printf(" AL Status Code: 0x%04X\n", ec_slave[i].ALstatuscode);
|
||||
|
||||
// Print Process Data (PDOs)
|
||||
printf(" Process Data:\n");
|
||||
printf(" Inputs (%d bytes): ", ec_slave[i].Ibytes);
|
||||
for (uint32_t j = 0; j < ec_slave[i].Ibytes; j++) {
|
||||
printf("%02X ", ec_slave[i].inputs[j]);
|
||||
}
|
||||
printf("\n");
|
||||
|
||||
printf(" Outputs (%d bytes): ", ec_slave[i].Obytes);
|
||||
for (uint32_t j = 0; j < ec_slave[i].Obytes; j++) {
|
||||
printf("%02X ", ec_slave[i].outputs[j]);
|
||||
}
|
||||
printf("\n");
|
||||
|
||||
// Read available SDOs
|
||||
printf(" SDO List:\n");
|
||||
for (int sdo_index = 0x1000; sdo_index <= 0x1FFF; sdo_index++) {
|
||||
uint32_t sdo_value;
|
||||
int size = sizeof(sdo_value);
|
||||
if (ec_SDOread(i, sdo_index, 0x00, FALSE, &size, &sdo_value, EC_TIMEOUTSAFE) > 0) {
|
||||
printf(" Index 0x%04X: Value 0x%08X\n", sdo_index, sdo_value);
|
||||
}
|
||||
}
|
||||
printf("--------------------------------------------------\n");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void setPin1Out()
|
||||
{
|
||||
uint8_t *outputs = (uint8_t *)ec_slave[3].outputs;
|
||||
|
||||
// Print current output state before modification
|
||||
printf("Current output state: 0x%02X\n", outputs[0]);
|
||||
|
||||
// Set bit 0 (Channel 1 ON)
|
||||
outputs[0] |= 1;
|
||||
|
||||
// Send process data to the slave
|
||||
ec_send_processdata();
|
||||
|
||||
wkc = ec_receive_processdata(EC_TIMEOUTRET);
|
||||
|
||||
if (wkc >= expectedWKC) {
|
||||
printf("Process data exchanged successfully.\n");
|
||||
} else {
|
||||
printf("Process data exchange failed. WKC: %d, expectedWKC: %d\n", wkc, expectedWKC);
|
||||
}
|
||||
|
||||
// Print final output state
|
||||
printf("Final output state: 0x%02X\n", outputs[0]);
|
||||
|
||||
// Print slave state and AL status code
|
||||
printState(ec_slave[3].state);
|
||||
}
|
||||
|
||||
|
||||
/*!
|
||||
* @brief Initialising Distributed Clocks. you should initialize Distributed Clocks (DC)
|
||||
* after all slaves are configured and mapped,
|
||||
* but before transitioning them to OPERATIONAL (EC_STATE_OPERATIONAL).
|
||||
* @return 1 if No Error | 0 if Error
|
||||
* */
|
||||
uint8_t initDisributedClocks()
|
||||
{
|
||||
printf("Init Distributed Clocks\n");
|
||||
if (ec_configdc()) {
|
||||
printf(" |-> Succeeded \n");
|
||||
return 1;
|
||||
}else
|
||||
{
|
||||
printf(" |-> Failed \n");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*!
|
||||
* @brief map process data objects (PDOs) of all detected EtherCAT slaves into a single memory buffer (IOmap).
|
||||
* and groupe them into group[0] This will be important for the Slaves state intitalisation phase.
|
||||
* @return 1 if No Error | 0 if Error
|
||||
* */
|
||||
uint8_t mapSlavesGrouped()
|
||||
{
|
||||
printf("Mapping Slaves\n");
|
||||
if(ec_config_map(&IOmap)){
|
||||
printf(" |-> Succeeded \n");
|
||||
for (uint8_t i = 1; i <= ec_slavecount; i++) {
|
||||
printf(" |-> (%s) - ",ec_slave[i].name);
|
||||
printState(ec_slave[i].state);
|
||||
}
|
||||
return 1;
|
||||
}else
|
||||
{
|
||||
printf(" |-> Failed \n");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
* @brief Enumerate and init all slaves.>
|
||||
* @return 1 if No Error | 0 if Error
|
||||
* */
|
||||
uint8_t enumerateSlaves()
|
||||
{
|
||||
printf("Detection and enumeration \n");
|
||||
if (ec_config_init(FALSE) > 0) {
|
||||
printf(" |-> Succeeded \n");
|
||||
printf(" |-> Slave Count: %d \n",ec_slavecount);
|
||||
return 1;
|
||||
}else
|
||||
{
|
||||
printf(" |-> Failed \n");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
* @brief Initialising network atapter for communication with slaves
|
||||
* @param char *Ifname is the interface name
|
||||
* @return 1 if No Error | 0 if Error
|
||||
* */
|
||||
uint8_t initNetworkAdapterSingle(char *ifname)
|
||||
{
|
||||
printf("Init Network Interface < %s >\n", ifname);
|
||||
if (ec_init(ifname)) {
|
||||
printf(" |-> Succeeded \n");
|
||||
return 1;
|
||||
}else
|
||||
{
|
||||
printf(" |-> Failed \n");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
void dataLoop()
|
||||
{
|
||||
ec_send_processdata();
|
||||
wkc = ec_receive_processdata(EC_TIMEOUTRET);
|
||||
if(wkc >= expectedWKC)
|
||||
{
|
||||
|
||||
}
|
||||
osal_usleep(5000);
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
if (argc > 1) {
|
||||
// Init Network adapter
|
||||
if(!initNetworkAdapterSingle(argv[1])){
|
||||
printf("Unable to Initiate Network Adapter -> Quitting");
|
||||
ec_close();
|
||||
return 0;
|
||||
}
|
||||
|
||||
if(!enumerateSlaves()){
|
||||
printf("Unable to Enumerate Slaves -> Quitting");
|
||||
ec_close();
|
||||
return 0;
|
||||
}
|
||||
|
||||
if(!mapSlavesGrouped()){
|
||||
printf("Unable to Map Slaves -> Quitting");
|
||||
ec_close();
|
||||
return 0;
|
||||
}
|
||||
|
||||
expectedWKC = (ec_group[0].outputsWKC * 2) + ec_group[0].inputsWKC;
|
||||
printf("Calculated workcounter %d\n", expectedWKC);
|
||||
|
||||
if(!initDisributedClocks()){
|
||||
printf("Unable to Initialise Distributed Clocks -> Quitting");
|
||||
ec_close();
|
||||
return 0;
|
||||
}
|
||||
|
||||
for (uint8_t i = 1; i <= ec_slavecount; i++) {
|
||||
printf("-----------------------------------------------------------------------\n");
|
||||
print_device_info();
|
||||
printf("-----------------------------------------------------------------------\n");
|
||||
if(!setSlaveState(1,EC_STATE_INIT)){
|
||||
printf("Unable chnage Slave mode -> Quitting");
|
||||
ec_close();
|
||||
return 0;
|
||||
}
|
||||
if(!setSlaveState(i,EC_STATE_PRE_OP)){
|
||||
printf("Unable chnage Slave mode -> Quitting");
|
||||
ec_close();
|
||||
return 0;
|
||||
}
|
||||
if(!setSlaveState(i,EC_STATE_SAFE_OP)){
|
||||
printf("Unable chnage Slave mode -> Quitting");
|
||||
ec_close();
|
||||
return 0;
|
||||
}
|
||||
if(!setSlaveState(i,EC_STATE_OPERATIONAL)){
|
||||
printf("Unable chnage Slave mode -> Quitting");
|
||||
ec_close();
|
||||
}
|
||||
printf("-----------------------------------------------------------------------\n");
|
||||
}
|
||||
|
||||
setPin1Out();
|
||||
|
||||
for(uint16_t j = 0; j < 10000; j++)
|
||||
{
|
||||
ec_send_processdata();
|
||||
wkc = ec_receive_processdata(EC_TIMEOUTRET);
|
||||
|
||||
if (wkc >= expectedWKC) {
|
||||
} else {
|
||||
printf("Process data exchange failed. WKC: %d, expectedWKC: %d\n", wkc, expectedWKC);
|
||||
}
|
||||
usleep(100);
|
||||
}
|
||||
|
||||
ec_close();
|
||||
} else {
|
||||
printf("Usage : sudo %s <network interface name> need to be passed\n", argv[0]);
|
||||
printf("Example : sudo %s eth0 \n", argv[0]);
|
||||
}
|
||||
return 0;
|
||||
}
|
@ -0,0 +1,40 @@
|
||||
#include "slaveconfig.h"
|
||||
#include <stdio.h>
|
||||
|
||||
|
||||
/*!
|
||||
* @brief Prints the state in which the Slave is and also give basic infomations about that state.
|
||||
* @param uint16_t state is the state flag of the slave which will be masked to ist 8 LSB's
|
||||
* @link https://infosys.beckhoff.com/english.php?content=../content/1033/ethercatsystem/1036980875.html&id=
|
||||
* @return void
|
||||
* */
|
||||
void printState(uint16_t state)
|
||||
{
|
||||
uint8_t state_masked = state & 0x0F; // Mask first byte
|
||||
|
||||
switch (state_masked) {
|
||||
case EC_STATE_INIT:
|
||||
printf("State: INIT (0x%02X) - No communication yet.\n", state_masked);
|
||||
break;
|
||||
|
||||
case EC_STATE_PRE_OP:
|
||||
printf("State: PRE-OP (0x%02X) - Configuration possible.\n", state_masked);
|
||||
break;
|
||||
|
||||
case EC_STATE_SAFE_OP:
|
||||
printf("State: SAFE-OP (0x%02X) - Inputs work, outputs disabled.\n", state_masked);
|
||||
break;
|
||||
|
||||
case EC_STATE_OPERATIONAL:
|
||||
printf("State: OPERATIONAL (0x%02X) - Fully active.\n", state_masked);
|
||||
break;
|
||||
|
||||
case EC_STATE_BOOT:
|
||||
printf("State: BOOTSTRAP (0x%02X) - Firmware update mode.\n", state_masked);
|
||||
break;
|
||||
|
||||
default:
|
||||
printf("State: UNKNOWN STATE (0x%02X)\n", state_masked);
|
||||
break;
|
||||
}
|
||||
}
|
@ -0,0 +1,30 @@
|
||||
/*
|
||||
* Licensed under the GNU General Public License version 2 with exceptions. See
|
||||
* LICENSE file in the project root for full license information
|
||||
*/
|
||||
|
||||
/** \file
|
||||
* \brief
|
||||
* Headerfile for ethercatbase.c
|
||||
*/
|
||||
|
||||
#ifndef _slave_config_
|
||||
#define _slave_config_
|
||||
|
||||
#include "ethercat.h"
|
||||
|
||||
/*!
|
||||
* @brief Prints the state in which the Slave is and also give basic infomations about that state.
|
||||
* @param uint16_t state is the state flag of the slave which will be masked to ist 8 LSB's
|
||||
* @link https://infosys.beckhoff.com/english.php?content=../content/1033/ethercatsystem/1036980875.html&id=
|
||||
* @return void
|
||||
* */
|
||||
void printState(uint16_t state);
|
||||
|
||||
/*!
|
||||
* @brief Set the given Slave to given State
|
||||
* @return 1 if No Error | 0 if Error
|
||||
* */
|
||||
//uint8_t setSlaveState(uint8_t slave_index, uint16_t ethercat_state);
|
||||
|
||||
#endif
|
Loading…
Reference in new issue