| /******************************************************************************* | |
| * 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 |