/******************************************************************************* | |
* Copyright (c) 2012 - 2014 AIT, ACIN, fortiss | |
* This program and the accompanying materials are made available under the | |
* terms of the Eclipse Public License 2.0 which is available at | |
* http://www.eclipse.org/legal/epl-2.0. | |
* | |
* SPDX-License-Identifier: EPL-2.0 | |
* | |
* Contributors: | |
* Filip Andren, Alois Zoitl, Ewald Weinhandl - initial API and implementation and/or initial documentation | |
*******************************************************************************/ | |
#include "EplWrapper.h" | |
#include "ProcessImageMatrix.h" | |
#include "EplXmlReader.h" | |
#include <forte_thread.h> | |
#if (TARGET_SYSTEM == _WIN32_) | |
#define _WINSOCKAPI_ // prevent windows.h from including winsock.h | |
#endif // (TARGET_SYSTEM == _WIN32_) | |
/* includes */ | |
#include "Epl.h" | |
#undef EPL_STACK_VERSION | |
#define EPL_STACK_VERSION(ver,rev,rel) (((((ver)) & 0xFF)<<24)|((((rev))&0xFF)<<16)|(((rel))&0xFFFF)) | |
#if (TARGET_SYSTEM == _LINUX_) | |
#include <stdio.h> | |
#include <unistd.h> | |
#include <sys/types.h> | |
#include <sys/socket.h> | |
#include <sys/select.h> | |
#include <sys/ioctl.h> | |
#include <netinet/in.h> | |
#include <net/if.h> | |
#include <string.h> | |
#include <termios.h> | |
#include <pthread.h> | |
#include <sys/syscall.h> | |
#include <sys/resource.h> | |
#include <errno.h> | |
#include <sys/stat.h> | |
#include <fcntl.h> | |
#include <signal.h> | |
#include <time.h> | |
#include <stdarg.h> | |
#ifndef CONFIG_POWERLINK_USERSTACK | |
#include <pthread.h> | |
#else | |
#include <pcap.h> | |
#endif | |
#elif (TARGET_SYSTEM == _WIN32_) | |
#include <Iphlpapi.h> | |
#include <pcap.h> | |
#endif // (TARGET_SYSTEM == _WIN32_) | |
#include <EplTgtConio.h> | |
//#include <conio.h> | |
/***************************************************************************/ | |
/* */ | |
/* */ | |
/* G L O B A L D E F I N I T I O N S */ | |
/* */ | |
/* */ | |
/***************************************************************************/ | |
//--------------------------------------------------------------------------- | |
// const defines | |
//--------------------------------------------------------------------------- | |
#if (TARGET_SYSTEM == _LINUX_) | |
#define SET_CPU_AFFINITY | |
#define MAIN_THREAD_PRIORITY 20 | |
#elif (TARGET_SYSTEM == _WIN32_) | |
// TracePoint support for realtime-debugging | |
#ifdef _DBG_TRACE_POINTS_ | |
void PUBLIC TgtDbgSignalTracePoint (BYTE bTracePointNumber_p); | |
#define TGT_DBG_SIGNAL_TRACE_POINT(p) TgtDbgSignalTracePoint(p) | |
#else | |
#define TGT_DBG_SIGNAL_TRACE_POINT(p) | |
#endif | |
#endif // (TARGET_SYSTEM == _WIN32_) | |
const DWORD NODEID = 0xF0; //=> MN | |
const DWORD IP_ADDR = 0xc0a86401; // 192.168.100.1 | |
const DWORD SUBNET_MASK = 0xFFFFFF00; // 255.255.255.0 | |
const char* HOSTNAME = "EPL Stack"; | |
//--------------------------------------------------------------------------- | |
// module global vars | |
//--------------------------------------------------------------------------- | |
CONST BYTE abMacAddr[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; | |
static unsigned int uiNodeId_g = EPL_C_ADR_INVALID; | |
static tEplApiProcessImageCopyJob AppProcessImageCopyJob_g; | |
static bool waitingUntilOperational; | |
#ifdef CONFIG_POWERLINK_USERSTACK | |
//static char* pszCdcFilename_g = "mnobd.cdc"; | |
#else | |
static pthread_t eventThreadId; | |
static pthread_t syncThreadId; | |
void *powerlinkEventThread(void * arg); | |
void *powerlinkSyncThread(void * arg); | |
#endif | |
//--------------------------------------------------------------------------- | |
// local function prototypes | |
//--------------------------------------------------------------------------- | |
// This function is the entry point for your object dictionary. It is defined | |
// in OBJDICT.C by define EPL_OBD_INIT_RAM_NAME. Use this function name to define | |
// this function prototype here. If you want to use more than one Epl | |
// instances then the function name of each object dictionary has to differ. | |
extern "C" tEplKernel PUBLIC EplObdInitRam (tEplObdInitParam MEM* pInitParam_p); | |
tEplKernel PUBLIC AppCbEvent( | |
tEplApiEventType EventType_p,// IN: event type (enum) | |
tEplApiEventArg* pEventArg_p,// IN: event argument (union) | |
void GENERIC* pUserArg_p); | |
tEplKernel PUBLIC AppCbSync(void); | |
char* CEplStackWrapper::allocProcImage(unsigned int n_bytes){ | |
char* procImage = (char*) malloc(n_bytes); | |
for(unsigned int i = 0; i < n_bytes; i++){ | |
procImage[i] = 0x00; | |
} | |
return procImage; | |
} | |
//=========================================================================// | |
// // | |
// S T A T I C F U N C T I O N S // | |
// // | |
//=========================================================================// | |
DEFINE_SINGLETON(CEplStackWrapper); | |
void CEplStackWrapper::eplMainInit(){ | |
#if (TARGET_SYSTEM == _LINUX_) | |
sigset_t mask; | |
/* | |
* We have to block the real time signals used by the timer modules so | |
* that they are able to wait on them using sigwaitinfo! | |
*/ | |
sigemptyset(&mask); | |
sigaddset(&mask, SIGRTMIN); | |
sigaddset(&mask, SIGRTMIN + 1); | |
pthread_sigmask(SIG_BLOCK, &mask, NULL); | |
#endif | |
} | |
//=========================================================================// | |
// // | |
// C L A S S F U N C T I O N S // | |
// // | |
//=========================================================================// | |
CEplStackWrapper::CEplStackWrapper(){ | |
} | |
CEplStackWrapper::~CEplStackWrapper(){ | |
} | |
int CEplStackWrapper::eplStackInit(char* pa_chXmlFile, char* pa_chCdcFile, char* pa_chEthDeviceName){ | |
tEplKernel EplRet; | |
static tEplApiInitParam EplApiInitParam; | |
const char* sHostname = HOSTNAME; | |
// Read and process XML file | |
CEplXmlReader xmlReader(&m_oProcMatrixIn, &m_oProcMatrixOut); | |
xmlReader.readXmlFile(pa_chXmlFile); | |
m_nProcInSize = m_oProcMatrixIn.getProcessImageSize(); | |
m_nProcOutSize = m_oProcMatrixOut.getProcessImageSize(); | |
m_pchAppProcessImageIn_g = allocProcImage(m_nProcInSize); | |
m_pchAppProcessImageOut_g = allocProcImage(m_nProcOutSize); | |
#ifdef CONFIG_POWERLINK_USERSTACK | |
#if (TARGET_SYSTEM == _LINUX_) | |
struct sched_param schedParam; | |
#endif | |
// variables for Pcap | |
char sErr_Msg[PCAP_ERRBUF_SIZE]; | |
pcap_if_t *alldevs; | |
pcap_if_t *seldev; | |
int i = 0; | |
#endif | |
#ifdef CONFIG_POWERLINK_USERSTACK | |
#if (TARGET_SYSTEM == _LINUX_) | |
/* adjust process priority */ | |
if(nice(-20) == -1) // push nice level in case we have no RTPreempt | |
{ | |
#if EPL_DEFINED_STACK_VERSION >= EPL_STACK_VERSION(1, 8, 2) | |
EPL_DBGLVL_ERROR_TRACE("%s() couldn't set nice value! (%s)\n", __func__, strerror(errno)); | |
#else | |
EPL_DBGLVL_ERROR_TRACE2("%s() couldn't set nice value! (%s)\n", __func__, strerror(errno)); | |
#endif | |
} | |
schedParam.__sched_priority = MAIN_THREAD_PRIORITY; | |
if(pthread_setschedparam(pthread_self(), SCHED_RR, &schedParam) != 0){ | |
#if EPL_DEFINED_STACK_VERSION >= EPL_STACK_VERSION(1, 8, 2) | |
EPL_DBGLVL_ERROR_TRACE("%s() couldn't set thread scheduling parameters! %d\n", __func__, schedParam.__sched_priority); | |
#else | |
EPL_DBGLVL_ERROR_TRACE2("%s() couldn't set thread scheduling parameters! %d\n", __func__, schedParam.__sched_priority); | |
#endif | |
} | |
/* Initialize target specific stuff */ | |
// EplTgtInit(); | |
#elif (TARGET_SYSTEM == _WIN32_) | |
// activate realtime priority class | |
SetPriorityClass(GetCurrentProcess(), REALTIME_PRIORITY_CLASS); | |
// lower the priority of this thread | |
SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_IDLE); | |
#endif // (TARGET_SYSTEM == _WIN32_) | |
#endif // CONFIG_POWERLINK_USERSTACK | |
/* Enabling ftrace for debugging */ | |
FTRACE_OPEN(); | |
FTRACE_ENABLE (TRUE); | |
EPL_MEMSET(&EplApiInitParam, 0, sizeof(EplApiInitParam)); | |
EplApiInitParam.m_uiSizeOfStruct = sizeof(EplApiInitParam); | |
#ifdef CONFIG_POWERLINK_USERSTACK | |
//////////////////////////////////////////////////////////////////////////////// | |
// Find ETH card specified by user // | |
//////////////////////////////////////////////////////////////////////////////// | |
bool macFound; | |
char correctDevName[1024]; | |
macFound = findMAC(pa_chEthDeviceName, &correctDevName[0]); | |
/* Retrieve the device list on the local machine */ | |
if(pcap_findalldevs(&alldevs, sErr_Msg) == -1){ | |
fprintf(stderr, "Error in pcap_findalldevs: %s\n", sErr_Msg); | |
EplRet = kEplNoResource; | |
return EplRet; | |
} | |
printf("\n"); | |
for(seldev = alldevs, i = 0; seldev != NULL; seldev = seldev->next, i++){ | |
if(seldev->description){ | |
printf("%d: %s\n %s\n", i, seldev->description, seldev->name); | |
} | |
else{ | |
printf("%d: %s\n", i, seldev->name); | |
} | |
if(macFound){ | |
const char* userDescLoc = strstr(seldev->name, correctDevName); | |
if(userDescLoc != NULL){ | |
if(seldev->description){ | |
printf("\nChosen Ethernet Card: %s\n %s\n", seldev->description, seldev->name); | |
} | |
else{ | |
printf("\nChosen Ethernet Card: %s\n", seldev->name); | |
} | |
break; | |
} | |
} | |
if(seldev->description){ | |
const char* userDescLoc = strstr(seldev->description, pa_chEthDeviceName); | |
if(userDescLoc != NULL){ | |
printf("\nChosen Ethernet Card: %s\n", seldev->description); | |
break; | |
} | |
} | |
else{ | |
const char* userDescLoc = strstr(seldev->name, pa_chEthDeviceName); | |
if(userDescLoc != NULL){ | |
printf("Chosen Ethernet Card: %s\n", seldev->name); | |
break; | |
} | |
} | |
} | |
// Check if a device was found, otherwise shutdown stack | |
if(!seldev){ | |
fprintf(stderr, "%s(Err/Warn): Invalid MAC address or device name specified. Shutting down Powerlink stack\n", __func__); | |
EplRet = kEplNoResource; | |
return EplRet; | |
} | |
//////////////////////////////////////////////////////////////////////////////// | |
// Setup EplApiInitParam (some of them can be removed as we have obd?) // | |
//////////////////////////////////////////////////////////////////////////////// | |
// pass selected device name to Edrv | |
char devName[128]; | |
strncpy(devName, seldev->name, 127); | |
EplApiInitParam.m_HwParam.m_pszDevName = devName; | |
#endif | |
EplApiInitParam.m_uiNodeId = uiNodeId_g = NODEID; | |
EplApiInitParam.m_dwIpAddress = (0xFFFFFF00 & IP_ADDR) | EplApiInitParam.m_uiNodeId; | |
/* write 00:00:00:00:00:00 to MAC address, so that the driver uses the real hardware address */ | |
EPL_MEMCPY(EplApiInitParam.m_abMacAddress, abMacAddr, sizeof(EplApiInitParam.m_abMacAddress)); | |
EplApiInitParam.m_fAsyncOnly = FALSE; | |
EplApiInitParam.m_dwFeatureFlags = -1; | |
EplApiInitParam.m_dwCycleLen = 10000; // required for error detection | |
EplApiInitParam.m_uiIsochrTxMaxPayload = 256; // const | |
EplApiInitParam.m_uiIsochrRxMaxPayload = 256; // const | |
EplApiInitParam.m_dwPresMaxLatency = 50000; // const; only required for IdentRes | |
EplApiInitParam.m_uiPreqActPayloadLimit = 36; // required for initialisation (+28 bytes) | |
EplApiInitParam.m_uiPresActPayloadLimit = 36; // required for initialisation of Pres frame (+28 bytes) | |
EplApiInitParam.m_dwAsndMaxLatency = 150000; // const; only required for IdentRes | |
EplApiInitParam.m_uiMultiplCycleCnt = 0; // required for error detection | |
EplApiInitParam.m_uiAsyncMtu = 1500; // required to set up max frame size | |
EplApiInitParam.m_uiPrescaler = 2; // required for sync | |
EplApiInitParam.m_dwLossOfFrameTolerance = 500000; | |
EplApiInitParam.m_dwAsyncSlotTimeout = 3000000; | |
EplApiInitParam.m_dwWaitSocPreq = 150000; | |
EplApiInitParam.m_dwDeviceType = -1; // NMT_DeviceType_U32 | |
EplApiInitParam.m_dwVendorId = -1; // NMT_IdentityObject_REC.VendorId_U32 | |
EplApiInitParam.m_dwProductCode = -1; // NMT_IdentityObject_REC.ProductCode_U32 | |
EplApiInitParam.m_dwRevisionNumber = -1; // NMT_IdentityObject_REC.RevisionNo_U32 | |
EplApiInitParam.m_dwSerialNumber = -1; // NMT_IdentityObject_REC.SerialNo_U32 | |
EplApiInitParam.m_dwSubnetMask = SUBNET_MASK; | |
EplApiInitParam.m_dwDefaultGateway = 0; | |
EPL_MEMCPY(EplApiInitParam.m_sHostname, sHostname, sizeof(EplApiInitParam.m_sHostname)); | |
EplApiInitParam.m_uiSyncNodeId = EPL_C_ADR_SYNC_ON_SOA; | |
EplApiInitParam.m_fSyncOnPrcNode = FALSE; | |
// set callback functions | |
EplApiInitParam.m_pfnCbEvent = AppCbEvent; | |
#ifdef CONFIG_POWERLINK_USERSTACK | |
EplApiInitParam.m_pfnObdInitRam = EplObdInitRam; | |
EplApiInitParam.m_pfnCbSync = AppCbSync; | |
#else | |
EplApiInitParam.m_pfnCbSync = NULL; | |
#endif | |
//////////////////////////////////////////////////////////////////////////////// | |
//////////////////////////////////////////////////////////////////////////////// | |
// Initialize Powerlink Stack // | |
//////////////////////////////////////////////////////////////////////////////// | |
printf("\n\n Powerlink %s running.\n (build: %s / %s)\n\n", (NODEID == EPL_C_ADR_MN_DEF_NODE_ID ? "Managing Node" : "Controlled Node"), __DATE__, __TIME__); | |
// initialize POWERLINK stack | |
EplRet = EplApiInitialize(&EplApiInitParam); | |
if(EplRet != kEplSuccessful){ | |
return EplRet; | |
} | |
#ifdef CONFIG_POWERLINK_USERSTACK | |
/* At this point, we don't need any more the device list. Free it */ | |
pcap_freealldevs(alldevs); | |
EplRet = EplApiSetCdcFilename(pa_chCdcFile); | |
if(EplRet != kEplSuccessful){ | |
return EplRet; | |
} | |
#else | |
// create event thread | |
if(pthread_create(&eventThreadId, NULL, &powerlinkEventThread, NULL) != 0){ | |
return EplRet; | |
} | |
// create sync thread | |
if(pthread_create(&syncThreadId, NULL, &powerlinkSyncThread, NULL) != 0){ | |
return EplRet; | |
} | |
#endif | |
AppProcessImageCopyJob_g.m_fNonBlocking = FALSE; | |
AppProcessImageCopyJob_g.m_uiPriority = 0; | |
AppProcessImageCopyJob_g.m_In.m_pPart = m_pchAppProcessImageIn_g; | |
AppProcessImageCopyJob_g.m_In.m_uiOffset = 0; | |
AppProcessImageCopyJob_g.m_In.m_uiSize = m_nProcInSize; | |
AppProcessImageCopyJob_g.m_Out.m_pPart = m_pchAppProcessImageOut_g; | |
AppProcessImageCopyJob_g.m_Out.m_uiOffset = 0; | |
AppProcessImageCopyJob_g.m_Out.m_uiSize = m_nProcOutSize; | |
EplRet = EplApiProcessImageAlloc(m_nProcInSize, m_nProcOutSize, 2, 2); | |
if(EplRet != kEplSuccessful){ | |
eplStackShutdown(); | |
} | |
EplRet = EplApiProcessImageSetup(); | |
if(EplRet != kEplSuccessful){ | |
eplStackShutdown(); | |
} | |
// start processing | |
EplRet = EplApiExecNmtCommand(kEplNmtEventSwReset); | |
if(EplRet != kEplSuccessful){ | |
eplStackShutdown(); | |
} | |
waitingUntilOperational = false; | |
if(m_bWait == true){ | |
while(!waitingUntilOperational){ | |
// Waiting | |
CThread::sleepThread(1); | |
} | |
} | |
return EplRet; | |
} | |
//////////////////////////////////////////////////////////////////////////////// | |
// Stop the stack // | |
//////////////////////////////////////////////////////////////////////////////// | |
int CEplStackWrapper::eplStackShutdown(void){ | |
tEplKernel EplRet; | |
// halt the NMT state machine | |
// so the processing of POWERLINK frames stops | |
EplApiExecNmtCommand(kEplNmtEventSwitchOff); | |
// delete process image | |
EplApiProcessImageFree(); | |
// delete instance for all modules | |
EplRet = EplApiShutdown(); | |
printf("EplApiShutdown(): 0x%X\n", EplRet); | |
m_oProcMatrixIn.clearAll(); | |
m_oProcMatrixOut.clearAll(); | |
m_lCallbackList.clearAll(); | |
free(m_pchAppProcessImageIn_g); | |
free(m_pchAppProcessImageOut_g); | |
return EplRet; | |
} | |
CProcessImageMatrix* CEplStackWrapper::getProcessImageMatrixIn(){ | |
return &m_oProcMatrixIn; | |
} | |
CProcessImageMatrix* CEplStackWrapper::getProcessImageMatrixOut(){ | |
return &m_oProcMatrixOut; | |
} | |
char* CEplStackWrapper::getProcImageIn(){ | |
return m_pchAppProcessImageIn_g; | |
} | |
char* CEplStackWrapper::getProcImageOut(){ | |
return m_pchAppProcessImageOut_g; | |
} | |
void CEplStackWrapper::waitUntilOperational(bool pa_bWait){ | |
m_bWait = pa_bWait; | |
} | |
void CEplStackWrapper::registerCallback(IEplCNCallback* pa_pCallback){ | |
m_oSync.lock(); | |
m_lCallbackList.pushBack(pa_pCallback); | |
m_oSync.unlock(); | |
} | |
bool CEplStackWrapper::findMAC(const char* pa_pchUserMAC, char* pa_pchDeviceName){ | |
//char* correctDevName; | |
#if (TARGET_SYSTEM == _LINUX_) | |
int nSD; // Socket descriptor | |
struct ifreq sIfReq; // Interface request | |
struct if_nameindex *pIfList; // Ptr to interface name index | |
struct if_nameindex *pListSave; // Ptr to interface name index | |
// | |
// Initialize this function | |
// | |
pIfList = (struct if_nameindex *) NULL; | |
pListSave = (struct if_nameindex *) NULL; | |
#ifndef SIOCGIFADDR | |
// The kernel does not support the required ioctls | |
return (false); | |
#endif | |
// | |
// Create a socket that we can use for all of our ioctls | |
// | |
nSD = socket(PF_INET, SOCK_STREAM, 0); | |
if(nSD < 0){ | |
// Socket creation failed, this is a fatal error | |
printf("File %s: line %d: Socket failed\n", __FILE__, __LINE__); | |
return (0); | |
} | |
// | |
// Obtain a list of dynamically allocated structures | |
// | |
pIfList = pListSave = if_nameindex(); | |
// | |
// Walk thru the array returned and query for each interface's | |
// address | |
// | |
for(pIfList; *(char *) pIfList != 0; pIfList++){ | |
strncpy(sIfReq.ifr_name, pIfList->if_name, IF_NAMESIZE); | |
// | |
// Get the MAC address for this interface | |
// | |
if(ioctl(nSD, SIOCGIFHWADDR, &sIfReq) != 0){ | |
// We failed to get the MAC address for the interface | |
printf("File %s: line %d: Ioctl failed\n", __FILE__, __LINE__); | |
return false; | |
} | |
// | |
// Determine if we are processing the interface that we | |
// are interested in | |
// | |
char chMAC[6 * 2 + 5 + 2]; | |
sprintf(chMAC, "%02X-%02X-%02X-%02X-%02X-%02X", (unsigned char) sIfReq.ifr_hwaddr.sa_data[0], (unsigned char) sIfReq.ifr_hwaddr.sa_data[1], (unsigned char) sIfReq.ifr_hwaddr.sa_data[2], (unsigned char) sIfReq.ifr_hwaddr.sa_data[3], (unsigned char) sIfReq.ifr_hwaddr.sa_data[4], (unsigned char) sIfReq.ifr_hwaddr.sa_data[5]); | |
if(compareMACs(chMAC, pa_pchUserMAC)){ | |
strncpy(pa_pchDeviceName, pIfList->if_name, IF_NAMESIZE); | |
// | |
// Clean up things and return | |
// | |
if_freenameindex(pListSave); | |
close(nSD); | |
return true; | |
} | |
} | |
// | |
// Clean up things and return | |
// | |
if_freenameindex(pListSave); | |
close(nSD); | |
#elif (TARGET_SYSTEM == _WIN32_) | |
// Find MAC address | |
IP_ADAPTER_INFO AdapterInfo[16];// Allocate information for up to 16 NICs | |
DWORD dwBufLen = sizeof(AdapterInfo);// Save memory size of buffer | |
DWORD dwStatus = GetAdaptersInfo(AdapterInfo, &dwBufLen); | |
assert(dwStatus == ERROR_SUCCESS);// Verify return value is valid, no buffer overflow | |
PIP_ADAPTER_INFO pAdapterInfo = AdapterInfo;// Contains pointer to current adapter info | |
do{ | |
char* chMAC = new char[6*2+5+1]; | |
BYTE *macAddr = pAdapterInfo->Address; | |
for (int i = 0; i < 6*2+5; i = i+2) | |
{ | |
if (i>0){ | |
chMAC[i] = '-'; | |
i++; | |
} | |
sprintf(&chMAC[i],"%02x",*macAddr++); | |
} | |
if (compareMACs(chMAC, pa_pchUserMAC)){ | |
//correctDevName = new char[strlen(pAdapterInfo->AdapterName)+1]; | |
strcpy(pa_pchDeviceName,pAdapterInfo->AdapterName); | |
delete chMAC; | |
//pa_pchDeviceName = correctDevName; | |
return true; | |
} | |
pAdapterInfo = pAdapterInfo->Next; // Progress through linked list | |
delete chMAC; | |
} | |
while(pAdapterInfo); // Terminate if last adapter | |
#endif | |
//pa_pchDeviceName = NULL; //No effect | |
return false; | |
} | |
bool CEplStackWrapper::compareMACs(const char* pa_chMACa, const char* pa_chMACb){ | |
if(strcmp(pa_chMACa, pa_chMACb) == 0){ | |
return true; | |
} | |
char* macCopyA = new char[strlen(pa_chMACa) + 1]; | |
strcpy(macCopyA, pa_chMACa); | |
char* macCopyB = new char[strlen(pa_chMACb) + 1]; | |
strcpy(macCopyB, pa_chMACb); | |
// Change to upper case | |
for(int i = 0; i < strlen(pa_chMACa); i++){ | |
switch (macCopyA[i]){ | |
case 'a': | |
macCopyA[i] = 'A'; | |
break; | |
case 'b': | |
macCopyA[i] = 'B'; | |
break; | |
case 'c': | |
macCopyA[i] = 'C'; | |
break; | |
case 'd': | |
macCopyA[i] = 'D'; | |
break; | |
case 'e': | |
macCopyA[i] = 'E'; | |
break; | |
case 'f': | |
macCopyA[i] = 'F'; | |
break; | |
} | |
} | |
for(int i = 0; i < strlen(pa_chMACb); i++){ | |
switch (macCopyB[i]){ | |
case 'a': | |
macCopyB[i] = 'A'; | |
break; | |
case 'b': | |
macCopyB[i] = 'B'; | |
break; | |
case 'c': | |
macCopyB[i] = 'C'; | |
break; | |
case 'd': | |
macCopyB[i] = 'D'; | |
break; | |
case 'e': | |
macCopyB[i] = 'E'; | |
break; | |
case 'f': | |
macCopyB[i] = 'F'; | |
break; | |
} | |
} | |
if(strcmp(macCopyA, macCopyB) == 0){ | |
delete[] macCopyA; | |
delete[] macCopyB; | |
return true; | |
} | |
delete[] macCopyA; | |
delete[] macCopyB; | |
return false; | |
} | |
//=========================================================================// | |
// // | |
// P R I V A T E F U N C T I O N S // | |
// // | |
//=========================================================================// | |
//--------------------------------------------------------------------------- | |
// | |
// Function: AppCbEvent | |
// | |
// Description: event callback function called by EPL API layer within | |
// user part (low priority). | |
// | |
// Parameters: EventType_p = event type | |
// pEventArg_p = pointer to union, which describes | |
// the event in detail | |
// pUserArg_p = user specific argument | |
// | |
// Returns: tEplKernel = error code, | |
// kEplSuccessful = no error | |
// kEplReject = reject further processing | |
// otherwise = post error event to API layer | |
// | |
// State: | |
// | |
//--------------------------------------------------------------------------- | |
tEplKernel PUBLIC AppCbEvent( | |
tEplApiEventType EventType_p,// IN: event type (enum) | |
tEplApiEventArg* pEventArg_p,// IN: event argument (union) | |
void GENERIC* pUserArg_p) | |
{ | |
tEplKernel EplRet = kEplSuccessful; | |
UNUSED_PARAMETER(pUserArg_p); | |
// check if NMT_GS_OFF is reached | |
switch (EventType_p) | |
{ | |
case kEplApiEventNmtStateChange: | |
{ | |
switch (pEventArg_p->m_NmtStateChange.m_NewNmtState) | |
{ | |
case kEplNmtGsOff: | |
{ // NMT state machine was shut down, | |
// because of user signal (CTRL-C) or critical EPL stack error | |
// -> also shut down EplApiProcess() and main() | |
EplRet = kEplShutdown; | |
#if EPL_DEFINED_STACK_VERSION >= EPL_STACK_VERSION(1, 8, 2) | |
PRINTF("%s(kEplNmtGsOff) originating event = 0x%X\n", __func__, pEventArg_p->m_NmtStateChange.m_NmtEvent); | |
#else | |
PRINTF2("%s(kEplNmtGsOff) originating event = 0x%X\n", __func__, pEventArg_p->m_NmtStateChange.m_NmtEvent); | |
#endif | |
break; | |
} | |
case kEplNmtGsResetCommunication: | |
{ | |
// continue | |
} | |
case kEplNmtGsResetConfiguration: | |
{ | |
// continue | |
} | |
case kEplNmtMsPreOperational1: | |
{ | |
#if EPL_DEFINED_STACK_VERSION >= EPL_STACK_VERSION(1, 8, 2) | |
PRINTF("%s(0x%X) originating event = 0x%X\n", | |
__func__, | |
pEventArg_p->m_NmtStateChange.m_NewNmtState, | |
pEventArg_p->m_NmtStateChange.m_NmtEvent); | |
#else | |
PRINTF3("%s(0x%X) originating event = 0x%X\n", | |
__func__, | |
pEventArg_p->m_NmtStateChange.m_NewNmtState, | |
pEventArg_p->m_NmtStateChange.m_NmtEvent); | |
#endif | |
// continue | |
} | |
case kEplNmtGsInitialising: | |
case kEplNmtGsResetApplication: | |
case kEplNmtMsNotActive: | |
case kEplNmtCsNotActive: | |
case kEplNmtCsPreOperational1: | |
{ | |
break; | |
} | |
case kEplNmtCsOperational: | |
case kEplNmtMsOperational: | |
{ | |
break; | |
} | |
default: | |
{ | |
break; | |
} | |
} | |
break; | |
} | |
case kEplApiEventCriticalError: | |
case kEplApiEventWarning: | |
{ // error or warning occured within the stack or the application | |
// on error the API layer stops the NMT state machine | |
#if EPL_DEFINED_STACK_VERSION >= EPL_STACK_VERSION(1, 8, 2) | |
PRINTF("%s(Err/Warn): Source=%02X EplError=0x%03X", | |
__func__, | |
pEventArg_p->m_InternalError.m_EventSource, | |
pEventArg_p->m_InternalError.m_EplError); | |
#else | |
PRINTF3("%s(Err/Warn): Source=%02X EplError=0x%03X", | |
__func__, | |
pEventArg_p->m_InternalError.m_EventSource, | |
pEventArg_p->m_InternalError.m_EplError); | |
#endif | |
// check additional argument | |
switch (pEventArg_p->m_InternalError.m_EventSource) | |
{ | |
case kEplEventSourceEventk: | |
case kEplEventSourceEventu: | |
{ // error occured within event processing | |
// either in kernel or in user part | |
#if EPL_DEFINED_STACK_VERSION >= EPL_STACK_VERSION(1, 8, 2) | |
PRINTF(" OrgSource=%02X\n", pEventArg_p->m_InternalError.m_Arg.m_EventSource); | |
#else | |
PRINTF1(" OrgSource=%02X\n", pEventArg_p->m_InternalError.m_Arg.m_EventSource); | |
#endif | |
break; | |
} | |
case kEplEventSourceDllk: | |
{ // error occured within the data link layer (e.g. interrupt processing) | |
// the DWORD argument contains the DLL state and the NMT event | |
#if EPL_DEFINED_STACK_VERSION >= EPL_STACK_VERSION(1, 8, 2) | |
PRINTF(" val=%lX\n", pEventArg_p->m_InternalError.m_Arg.m_dwArg); | |
#else | |
PRINTF1(" val=%lX\n", pEventArg_p->m_InternalError.m_Arg.m_dwArg); | |
#endif | |
break; | |
} | |
case kEplEventSourceObdk: | |
case kEplEventSourceObdu: | |
{ // error occured within OBD module | |
// either in kernel or in user part | |
#if EPL_DEFINED_STACK_VERSION >= EPL_STACK_VERSION(1, 8, 2) | |
PRINTF(" Object=0x%04X/%u\n", pEventArg_p->m_InternalError.m_Arg.m_ObdError.m_uiIndex, pEventArg_p->m_InternalError.m_Arg.m_ObdError.m_uiSubIndex); | |
#else | |
PRINTF2(" Object=0x%04X/%u\n", pEventArg_p->m_InternalError.m_Arg.m_ObdError.m_uiIndex, pEventArg_p->m_InternalError.m_Arg.m_ObdError.m_uiSubIndex); | |
#endif | |
break; | |
} | |
default: | |
{ | |
#if EPL_DEFINED_STACK_VERSION >= EPL_STACK_VERSION(1, 8, 2) | |
PRINTF("\n"); | |
#else | |
PRINTF0("\n"); | |
#endif | |
break; | |
} | |
} | |
break; | |
} | |
case kEplApiEventHistoryEntry: | |
{ // new history entry | |
PRINTF("%s(HistoryEntry): Type=0x%04X Code=0x%04X (0x%02X %02X %02X %02X %02X %02X %02X %02X)\n", | |
__func__, | |
pEventArg_p->m_ErrHistoryEntry.m_wEntryType, | |
pEventArg_p->m_ErrHistoryEntry.m_wErrorCode, | |
(WORD) pEventArg_p->m_ErrHistoryEntry.m_abAddInfo[0], | |
(WORD) pEventArg_p->m_ErrHistoryEntry.m_abAddInfo[1], | |
(WORD) pEventArg_p->m_ErrHistoryEntry.m_abAddInfo[2], | |
(WORD) pEventArg_p->m_ErrHistoryEntry.m_abAddInfo[3], | |
(WORD) pEventArg_p->m_ErrHistoryEntry.m_abAddInfo[4], | |
(WORD) pEventArg_p->m_ErrHistoryEntry.m_abAddInfo[5], | |
(WORD) pEventArg_p->m_ErrHistoryEntry.m_abAddInfo[6], | |
(WORD) pEventArg_p->m_ErrHistoryEntry.m_abAddInfo[7]); | |
break; | |
} | |
case kEplApiEventNode: | |
{ | |
// check additional argument | |
switch (pEventArg_p->m_Node.m_NodeEvent) | |
{ | |
case kEplNmtNodeEventCheckConf: | |
{ | |
#if EPL_DEFINED_STACK_VERSION >= EPL_STACK_VERSION(1, 8, 2) | |
PRINTF("%s(Node=0x%X, CheckConf)\n", __func__, pEventArg_p->m_Node.m_uiNodeId); | |
#else | |
PRINTF2("%s(Node=0x%X, CheckConf)\n", __func__, pEventArg_p->m_Node.m_uiNodeId); | |
#endif | |
break; | |
} | |
case kEplNmtNodeEventUpdateConf: | |
{ | |
#if EPL_DEFINED_STACK_VERSION >= EPL_STACK_VERSION(1, 8, 2) | |
PRINTF("%s(Node=0x%X, UpdateConf)\n", __func__, pEventArg_p->m_Node.m_uiNodeId); | |
#else | |
PRINTF2("%s(Node=0x%X, UpdateConf)\n", __func__, pEventArg_p->m_Node.m_uiNodeId); | |
#endif | |
break; | |
} | |
case kEplNmtNodeEventNmtState: | |
{ | |
#if EPL_DEFINED_STACK_VERSION >= EPL_STACK_VERSION(1, 8, 2) | |
PRINTF("%s(Node=0x%X, NmtState=0x%X)\n", __func__, pEventArg_p->m_Node.m_uiNodeId, pEventArg_p->m_Node.m_NmtState); | |
#else | |
PRINTF3("%s(Node=0x%X, NmtState=0x%X)\n", __func__, pEventArg_p->m_Node.m_uiNodeId, pEventArg_p->m_Node.m_NmtState); | |
#endif | |
if (pEventArg_p->m_Node.m_NmtState == kEplNmtCsOperational){ | |
printf("init finished\n"); | |
waitingUntilOperational = true; | |
} | |
break; | |
} | |
case kEplNmtNodeEventError: | |
{ | |
#if EPL_DEFINED_STACK_VERSION >= EPL_STACK_VERSION(1, 8, 2) | |
PRINTF("%s(Node=0x%X, Error=0x%X)\n", __func__, pEventArg_p->m_Node.m_uiNodeId, pEventArg_p->m_Node.m_wErrorCode); | |
#else | |
PRINTF3("%s(Node=0x%X, Error=0x%X)\n", __func__, pEventArg_p->m_Node.m_uiNodeId, pEventArg_p->m_Node.m_wErrorCode); | |
#endif | |
break; | |
} | |
case kEplNmtNodeEventFound: | |
{ | |
#if EPL_DEFINED_STACK_VERSION >= EPL_STACK_VERSION(1, 8, 2) | |
PRINTF("%s(Node=0x%X, Found)\n", __func__, pEventArg_p->m_Node.m_uiNodeId); | |
#else | |
PRINTF2("%s(Node=0x%X, Found)\n", __func__, pEventArg_p->m_Node.m_uiNodeId); | |
#endif | |
break; | |
} | |
default: | |
{ | |
break; | |
} | |
} | |
break; | |
} | |
#if (((EPL_MODULE_INTEGRATION) & (EPL_MODULE_CFM)) != 0) | |
case kEplApiEventCfmProgress: | |
{ | |
#if EPL_DEFINED_STACK_VERSION >= EPL_STACK_VERSION(1, 8, 2) | |
PRINTF("%s(Node=0x%X, CFM-Progress: Object 0x%X/%u, ", __func__, pEventArg_p->m_CfmProgress.m_uiNodeId, pEventArg_p->m_CfmProgress.m_uiObjectIndex, pEventArg_p->m_CfmProgress.m_uiObjectSubIndex); | |
PRINTF("%u/%u Bytes", pEventArg_p->m_CfmProgress.m_dwBytesDownloaded, pEventArg_p->m_CfmProgress.m_dwTotalNumberOfBytes); | |
#else | |
PRINTF4("%s(Node=0x%X, CFM-Progress: Object 0x%X/%u, ", __func__, pEventArg_p->m_CfmProgress.m_uiNodeId, pEventArg_p->m_CfmProgress.m_uiObjectIndex, pEventArg_p->m_CfmProgress.m_uiObjectSubIndex); | |
PRINTF2("%u/%u Bytes", pEventArg_p->m_CfmProgress.m_dwBytesDownloaded, pEventArg_p->m_CfmProgress.m_dwTotalNumberOfBytes); | |
#endif | |
if ((pEventArg_p->m_CfmProgress.m_dwSdoAbortCode != 0) | |
|| (pEventArg_p->m_CfmProgress.m_EplError != kEplSuccessful)) | |
{ | |
#if EPL_DEFINED_STACK_VERSION >= EPL_STACK_VERSION(1, 8, 2) | |
PRINTF(" -> SDO Abort=0x%lX, Error=0x%X)\n", pEventArg_p->m_CfmProgress.m_dwSdoAbortCode, pEventArg_p->m_CfmProgress.m_EplError); | |
#else | |
PRINTF2(" -> SDO Abort=0x%lX, Error=0x%X)\n", pEventArg_p->m_CfmProgress.m_dwSdoAbortCode, pEventArg_p->m_CfmProgress.m_EplError); | |
#endif | |
} | |
else | |
{ | |
#if EPL_DEFINED_STACK_VERSION >= EPL_STACK_VERSION(1, 8, 2) | |
PRINTF(")\n"); | |
#else | |
PRINTF0(")\n"); | |
#endif | |
} | |
break; | |
} | |
case kEplApiEventCfmResult: | |
{ | |
switch (pEventArg_p->m_CfmResult.m_NodeCommand) | |
{ | |
case kEplNmtNodeCommandConfOk: | |
{ | |
#if EPL_DEFINED_STACK_VERSION >= EPL_STACK_VERSION(1, 8, 2) | |
PRINTF("%s(Node=0x%X, ConfOk)\n", __func__, pEventArg_p->m_CfmResult.m_uiNodeId); | |
#else | |
PRINTF2("%s(Node=0x%X, ConfOk)\n", __func__, pEventArg_p->m_CfmResult.m_uiNodeId); | |
#endif | |
break; | |
} | |
case kEplNmtNodeCommandConfErr: | |
{ | |
#if EPL_DEFINED_STACK_VERSION >= EPL_STACK_VERSION(1, 8, 2) | |
PRINTF("%s(Node=0x%X, ConfErr)\n", __func__, pEventArg_p->m_CfmResult.m_uiNodeId); | |
#else | |
PRINTF2("%s(Node=0x%X, ConfErr)\n", __func__, pEventArg_p->m_CfmResult.m_uiNodeId); | |
#endif | |
break; | |
} | |
case kEplNmtNodeCommandConfReset: | |
{ | |
#if EPL_DEFINED_STACK_VERSION >= EPL_STACK_VERSION(1, 8, 2) | |
PRINTF("%s(Node=0x%X, ConfReset)\n", __func__, pEventArg_p->m_CfmResult.m_uiNodeId); | |
#else | |
PRINTF2("%s(Node=0x%X, ConfReset)\n", __func__, pEventArg_p->m_CfmResult.m_uiNodeId); | |
#endif | |
break; | |
} | |
case kEplNmtNodeCommandConfRestored: | |
{ | |
#if EPL_DEFINED_STACK_VERSION >= EPL_STACK_VERSION(1, 8, 2) | |
PRINTF("%s(Node=0x%X, ConfRestored)\n", __func__, pEventArg_p->m_CfmResult.m_uiNodeId); | |
#else | |
PRINTF2("%s(Node=0x%X, ConfRestored)\n", __func__, pEventArg_p->m_CfmResult.m_uiNodeId); | |
#endif | |
break; | |
} | |
default: | |
{ | |
#if EPL_DEFINED_STACK_VERSION >= EPL_STACK_VERSION(1, 8, 2) | |
PRINTF("%s(Node=0x%X, CfmResult=0x%X)\n", __func__, pEventArg_p->m_CfmResult.m_uiNodeId, pEventArg_p->m_CfmResult.m_NodeCommand); | |
#else | |
PRINTF3("%s(Node=0x%X, CfmResult=0x%X)\n", __func__, pEventArg_p->m_CfmResult.m_uiNodeId, pEventArg_p->m_CfmResult.m_NodeCommand); | |
#endif | |
break; | |
} | |
} | |
break; | |
} | |
#endif | |
default: | |
break; | |
} | |
return EplRet; | |
} | |
//--------------------------------------------------------------------------- | |
// | |
// Function: AppCbSync | |
// | |
// Description: sync event callback function called by event module within | |
// kernel part (high priority). | |
// This function sets the outputs, reads the inputs and runs | |
// the control loop. | |
// | |
// Parameters: void | |
// | |
// Returns: tEplKernel = error code, | |
// kEplSuccessful = no error | |
// otherwise = post error event to API layer | |
// | |
// State: | |
// | |
//--------------------------------------------------------------------------- | |
tEplKernel PUBLIC AppCbSync(void){ | |
tEplKernel EplRet = kEplSuccessful; | |
EplRet = EplApiProcessImageExchange(&AppProcessImageCopyJob_g); | |
// Loop through callback list and call each FB in the list | |
CEplStackWrapper::getInstance().executeAllCallbacks(); | |
return EplRet; | |
} | |
void CEplStackWrapper::executeAllCallbacks(){ | |
m_oSync.lock(); | |
CSinglyLinkedList<IEplCNCallback*>::Iterator itEnd = m_lCallbackList.end(); | |
for(CSinglyLinkedList<IEplCNCallback*>::Iterator it = m_lCallbackList.begin(); it != itEnd; ++it){ | |
it->cnSynchCallback(); | |
} | |
m_oSync.unlock(); | |
} | |
#ifndef CONFIG_POWERLINK_USERSTACK | |
void *powerlinkEventThread(void * arg __attribute__((unused))){ | |
EplApiProcess(); | |
return NULL; | |
} | |
void *powerlinkSyncThread(void * arg __attribute__((unused))){ | |
while(1){ | |
AppCbSync(); | |
} | |
return NULL; | |
} | |
#endif | |
// EOF |