blob: f29c246bfa36fd79c4bab695be74da703a3e97b2 [file] [log] [blame]
/*******************************************************************************
* 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