Merge "[567611] Code generator produces invalid code for FBs with 0 event ins or outs" into develop
diff --git a/src/arch/posix/CMakeLists.txt b/src/arch/posix/CMakeLists.txt
index 02f720a..720b06e 100644
--- a/src/arch/posix/CMakeLists.txt
+++ b/src/arch/posix/CMakeLists.txt
@@ -56,7 +56,7 @@
mark_as_advanced(FORTE_RTTI_AND_EXCEPTIONS)
if(FORTE_TESTS AND FORTE_USE_TEST_CONFIG_IN_FORTE)
- forte_add_definition("-DBOOST_TEST_DYN_LINK -g -O0 --coverage -fno-inline -fno-elide-constructors -fno-exceptions -fsanitize=address -DBOOST_NO_EXCEPTIONS")
+ forte_add_definition("-DBOOST_TEST_DYN_LINK -g -O0 --coverage -fno-inline -fno-elide-constructors -fsanitize=address")
forte_add_link_library("-fsanitize=address")
forte_add_link_library("--coverage")
else()
diff --git a/src/core/datatypes/forte_time.cpp b/src/core/datatypes/forte_time.cpp
index 8cac9c4..17ffb22 100644
--- a/src/core/datatypes/forte_time.cpp
+++ b/src/core/datatypes/forte_time.cpp
@@ -62,11 +62,9 @@
case 'd':
nTimeFactor = 24 * 60 * 60 * cgForteTimeBaseUnitsPerSecond;
break;
-
case 'h':
nTimeFactor = 60 * 60 * cgForteTimeBaseUnitsPerSecond;
break;
-
case 'm':
if('s' == tolower(*(pcEnd + 1))) {
nTimeFactor = cgForteTimeBaseUnitsPerSecond / forte::core::constants::cMillisecondsPerSecond;
@@ -78,8 +76,9 @@
case 'n':
if('s' == tolower(*(pcEnd + 1))) {
nTimeFactor = cgForteTimeBaseUnitsPerSecond / forte::core::constants::cNanosecondsPerSecond;
+ ++pcEnd;
} else {
- bEnd = true;
+ return -1;
}
break;
case 's':
@@ -88,28 +87,32 @@
case 'u':
if('s' == tolower(*(pcEnd + 1))) {
nTimeFactor = cgForteTimeBaseUnitsPerSecond / forte::core::constants::cMicrosecondsPerSecond;
+ ++pcEnd;
} else {
- bEnd = true;
+ return -1;
}
break;
case '_':
//ignore leading underscores
break;
default:
- if(paValue == pcEnd) {
- //we couldn't parse anything
+ if((pcEnd != paValue) || (0 == nIntVal)){ //we could not parse anything yet so wrong literal
+ //we have a number without unit or it is the first entry which we could not pars then this is an error
return -1;
}
+ // we are in an array and at the end of the literal
bEnd = true;
break;
}
nRetVal += static_cast<int>(pcEnd - paValue);
+ paValue = pcEnd;
if(!bEnd) {
++nRetVal;
+ ++paValue;
}
- paValue = pcEnd + 1;
nIntVal += (nBuf * nTimeFactor * nTimeSignFactor);
- } while(('\0' != *paValue) && (!bEnd));
+ } while((!bEnd) && ('\0' != *paValue));
+
} else {
return -1;
}
diff --git a/src/modules/PLC01A1/CMakeLists.txt b/src/modules/PLC01A1/CMakeLists.txt
new file mode 100644
index 0000000..9638b52
--- /dev/null
+++ b/src/modules/PLC01A1/CMakeLists.txt
@@ -0,0 +1,19 @@
+#*******************************************************************************
+# Copyright (c) 2019 fortiss GmbH
+# 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:
+# Jose Cabral
+# - initial API and implementation and/or initial documentation
+# *******************************************************************************/
+
+forte_add_io(PLC01A1 "Support for X-NUCLEO-PLC01A")
+
+if(FORTE_IO_PLC01A1)
+ forte_add_include_directories(${CMAKE_CURRENT_SOURCE_DIR})
+ forte_add_sourcefile_hcpp(plc01a1_controller plc01a1_config_fb)
+endif(FORTE_IO_PLC01A1)
diff --git a/src/modules/PLC01A1/plc01a1_config_fb.cpp b/src/modules/PLC01A1/plc01a1_config_fb.cpp
new file mode 100644
index 0000000..5ede19c
--- /dev/null
+++ b/src/modules/PLC01A1/plc01a1_config_fb.cpp
@@ -0,0 +1,88 @@
+/*******************************************************************************
+ * Copyright (c) 2019 fortiss GmbH
+ * 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:
+ * Jose Cabral - initial API and implementation and/or initial documentation
+ *******************************************************************************/
+
+#include "plc01a1_config_fb.h"
+#ifdef FORTE_ENABLE_GENERATED_SOURCE_CPP
+#include "plc01a1_config_fb_gen.cpp"
+#endif
+
+#include "plc01a1_controller.h"
+
+DEFINE_FIRMWARE_FB(PLC01A1ConfigFB, g_nStringIdPLC01A1)
+
+
+
+const CStringDictionary::TStringId PLC01A1ConfigFB::scm_anDataInputNames[] = { g_nStringIdQI, g_nStringIdIN1, g_nStringIdIN2, g_nStringIdIN3, g_nStringIdIN4,
+ g_nStringIdIN5, g_nStringIdIN6, g_nStringIdIN7, g_nStringIdIN8, g_nStringIdOUT1, g_nStringIdOUT2, g_nStringIdOUT3, g_nStringIdOUT4, g_nStringIdOUT5,
+ g_nStringIdOUT6, g_nStringIdOUT7, g_nStringIdOUT8, g_nStringIdUpdateInterval };
+
+const CStringDictionary::TStringId PLC01A1ConfigFB::scm_anDataInputTypeIds[] = { g_nStringIdBOOL, g_nStringIdWSTRING, g_nStringIdWSTRING, g_nStringIdWSTRING,
+ g_nStringIdWSTRING, g_nStringIdWSTRING, g_nStringIdWSTRING, g_nStringIdWSTRING, g_nStringIdWSTRING, g_nStringIdWSTRING, g_nStringIdWSTRING,
+ g_nStringIdWSTRING, g_nStringIdWSTRING, g_nStringIdWSTRING, g_nStringIdWSTRING, g_nStringIdWSTRING, g_nStringIdWSTRING, g_nStringIdUINT };
+
+const CStringDictionary::TStringId PLC01A1ConfigFB::scm_anDataOutputNames[] = { g_nStringIdQO, g_nStringIdSTATUS };
+
+const CStringDictionary::TStringId PLC01A1ConfigFB::scm_anDataOutputTypeIds[] = { g_nStringIdBOOL, g_nStringIdWSTRING };
+
+const TForteInt16 PLC01A1ConfigFB::scm_anEIWithIndexes[] = { 0 };
+const TDataIOID PLC01A1ConfigFB::scm_anEIWith[] = { 0, 17, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 255 };
+const CStringDictionary::TStringId PLC01A1ConfigFB::scm_anEventInputNames[] = { g_nStringIdINIT };
+const TDataIOID PLC01A1ConfigFB::scm_anEOWith[] = { 0, 1, 255, 0, 1, 255 };
+const TForteInt16 PLC01A1ConfigFB::scm_anEOWithIndexes[] = { 0, 3, -1 };
+const CStringDictionary::TStringId PLC01A1ConfigFB::scm_anEventOutputNames[] = { g_nStringIdINITO, g_nStringIdIND };
+const SFBInterfaceSpec PLC01A1ConfigFB::scm_stFBInterfaceSpec = {
+ 1, scm_anEventInputNames, scm_anEIWith, scm_anEIWithIndexes,
+ 2, scm_anEventOutputNames, scm_anEOWith, scm_anEOWithIndexes, 18, scm_anDataInputNames, scm_anDataInputTypeIds,
+ 2, scm_anDataOutputNames, scm_anDataOutputTypeIds,
+ 0, 0
+};
+
+void PLC01A1ConfigFB::setInitialValues() {
+ UpdateInterval() = 25;
+}
+
+forte::core::io::IODeviceController* PLC01A1ConfigFB::createDeviceController(CDeviceExecution &paDeviceExecution) {
+ return new PLC01A1Controller(paDeviceExecution);
+}
+
+void PLC01A1ConfigFB::setConfig() {
+ PLC01A1Controller::Config config;
+ config.mUpdateInterval = UpdateInterval();
+ getDeviceController()->setConfig(&config);
+}
+
+void PLC01A1ConfigFB::onStartup() {
+ // Initialize handles
+ size_t initialDIOffset = 1;
+ size_t numberOfInputs = 8;
+ size_t numberOfOutputs = 8;
+
+ for(size_t i = 0; i < numberOfInputs; i++) {
+ PLC01A1Controller::HandleDescriptor desc = PLC01A1Controller::HandleDescriptor(*static_cast<CIEC_WSTRING*>(getDI(initialDIOffset + i)),
+ forte::core::io::IOMapper::In,
+ 0 /*offset is always 0 */,
+ static_cast<uint8_t>(i));
+ initHandle(&desc);
+ }
+
+ for(size_t i = 0; i < numberOfOutputs; i++) {
+ PLC01A1Controller::HandleDescriptor
+ desc = PLC01A1Controller::HandleDescriptor(*static_cast<CIEC_WSTRING*>(getDI(initialDIOffset + numberOfInputs + i)),
+ forte::core::io::IOMapper::Out, 0 /*offset is always 0 */, static_cast<uint8_t>(numberOfOutputs - i - 1));
+ initHandle(&desc);
+ }
+
+ started();
+}
+
+
+
diff --git a/src/modules/PLC01A1/plc01a1_config_fb.h b/src/modules/PLC01A1/plc01a1_config_fb.h
new file mode 100644
index 0000000..ce6ebd2
--- /dev/null
+++ b/src/modules/PLC01A1/plc01a1_config_fb.h
@@ -0,0 +1,140 @@
+/*******************************************************************************
+ * Copyright (c) 2019 fortiss GmbH
+ * 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:
+ * Jose Cabral - initial API and implementation and/or initial documentation
+ *******************************************************************************/
+
+#ifndef _PLC01A1_H_
+#define _PLC01A1_H_
+
+#include <funcbloc.h>
+#include <forte_bool.h>
+#include <forte_uint.h>
+#include <forte_wstring.h>
+#include <io/configFB/io_configFB_controller.h>
+
+class PLC01A1ConfigFB : public forte::core::io::IOConfigFBController {
+ DECLARE_FIRMWARE_FB(PLC01A1ConfigFB)
+
+private:
+ static const CStringDictionary::TStringId scm_anDataInputNames[];
+ static const CStringDictionary::TStringId scm_anDataInputTypeIds[];
+ CIEC_BOOL &QI() {
+ return *static_cast<CIEC_BOOL*>(getDI(0));
+ };
+
+ CIEC_WSTRING &IN1() {
+ return *static_cast<CIEC_WSTRING*>(getDI(1));
+ };
+
+ CIEC_WSTRING &IN2() {
+ return *static_cast<CIEC_WSTRING*>(getDI(2));
+ };
+
+ CIEC_WSTRING &IN3() {
+ return *static_cast<CIEC_WSTRING*>(getDI(3));
+ };
+
+ CIEC_WSTRING &IN4() {
+ return *static_cast<CIEC_WSTRING*>(getDI(4));
+ };
+
+ CIEC_WSTRING &IN5() {
+ return *static_cast<CIEC_WSTRING*>(getDI(5));
+ };
+
+ CIEC_WSTRING &IN6() {
+ return *static_cast<CIEC_WSTRING*>(getDI(6));
+ };
+
+ CIEC_WSTRING &IN7() {
+ return *static_cast<CIEC_WSTRING*>(getDI(7));
+ };
+
+ CIEC_WSTRING &IN8() {
+ return *static_cast<CIEC_WSTRING*>(getDI(8));
+ };
+
+ CIEC_WSTRING &OUT1() {
+ return *static_cast<CIEC_WSTRING*>(getDI(9));
+ };
+
+ CIEC_WSTRING &OUT2() {
+ return *static_cast<CIEC_WSTRING*>(getDI(10));
+ };
+
+ CIEC_WSTRING &OUT3() {
+ return *static_cast<CIEC_WSTRING*>(getDI(11));
+ };
+
+ CIEC_WSTRING &OUT4() {
+ return *static_cast<CIEC_WSTRING*>(getDI(12));
+ };
+
+ CIEC_WSTRING &OUT5() {
+ return *static_cast<CIEC_WSTRING*>(getDI(13));
+ };
+
+ CIEC_WSTRING &OUT6() {
+ return *static_cast<CIEC_WSTRING*>(getDI(14));
+ };
+
+ CIEC_WSTRING &OUT7() {
+ return *static_cast<CIEC_WSTRING*>(getDI(15));
+ };
+
+ CIEC_WSTRING &OUT8() {
+ return *static_cast<CIEC_WSTRING*>(getDI(16));
+ };
+
+ CIEC_UINT &UpdateInterval() {
+ return *static_cast<CIEC_UINT*>(getDI(17));
+ };
+
+ static const CStringDictionary::TStringId scm_anDataOutputNames[];
+ static const CStringDictionary::TStringId scm_anDataOutputTypeIds[];
+ CIEC_BOOL &QO() {
+ return *static_cast<CIEC_BOOL*>(getDO(0));
+ };
+
+ CIEC_WSTRING &STATUS() {
+ return *static_cast<CIEC_WSTRING*>(getDO(1));
+ };
+
+ static const TEventID scm_nEventINITID = 0;
+ static const TForteInt16 scm_anEIWithIndexes[];
+ static const TDataIOID scm_anEIWith[];
+ static const CStringDictionary::TStringId scm_anEventInputNames[];
+
+ static const TEventID scm_nEventINITOID = 0;
+ static const TEventID scm_nEventINDID = 1;
+ static const TForteInt16 scm_anEOWithIndexes[];
+ static const TDataIOID scm_anEOWith[];
+ static const CStringDictionary::TStringId scm_anEventOutputNames[];
+
+ static const SFBInterfaceSpec scm_stFBInterfaceSpec;
+
+ FORTE_FB_DATA_ARRAY(2, 18, 2, 0);
+
+virtual void setInitialValues();
+
+ protected:
+ forte::core::io::IODeviceController* createDeviceController(CDeviceExecution &paDeviceExecution);
+
+ void setConfig();
+
+ virtual void onStartup();
+
+ public:
+ FUNCTION_BLOCK_CTOR_WITH_BASE_CLASS(PLC01A1ConfigFB, forte::core::io::IOConfigFBController){}
+
+};
+
+#endif //close the ifdef sequence from the beginning of the file
+
diff --git a/src/modules/PLC01A1/plc01a1_controller.cpp b/src/modules/PLC01A1/plc01a1_controller.cpp
new file mode 100644
index 0000000..da61dbf
--- /dev/null
+++ b/src/modules/PLC01A1/plc01a1_controller.cpp
@@ -0,0 +1,197 @@
+/*******************************************************************************
+ * Copyright (c) 2019 fortiss GmbH
+ * 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:
+ * Jose Cabral - initial API and implementation and/or initial documentation
+ *******************************************************************************/
+
+#include <io/mapper/io_handle_bit.h>
+#include "plc01a1_controller.h"
+#include <devlog.h>
+#include <sys/ioctl.h>
+#include <linux/ioctl.h>
+#include <fcntl.h>
+#include <unistd.h>
+
+const char *const PLC01A1Controller::scmSPIInputDevice = "/dev/spidev0.0";
+const char *const PLC01A1Controller::scmSPIOutputDevice = "/dev/spidev0.1";
+
+const char *const PLC01A1Controller::scmFailedToOpenInputControlFile = "Failed to open input control file";
+const char *const PLC01A1Controller::scmFailedToOpenOutputControlFile = "Failed to open output control file";
+
+const char *const PLC01A1Controller::scmFailedToSetInputMode = "Failed to set input mode";
+const char *const PLC01A1Controller::scmFailedToSetOutputMode = "Failed to set output mode";
+
+const char *const PLC01A1Controller::scmFailedToSetInputBits = "Failed to set input bits";
+const char *const PLC01A1Controller::scmFailedToSetOutputBits = "Failed to set output bits";
+
+const char *const PLC01A1Controller::scmFailedToSetInputSpeed = "Failed to set input speed";
+const char *const PLC01A1Controller::scmFailedToSetOutputSpeed = "Failed to set output speed";
+
+const uint32_t PLC01A1Controller::scmSPIMode = 0;
+
+const uint8_t PLC01A1Controller::scmSPIBits = 8;
+const uint32_t PLC01A1Controller::scmSPIInputMaxSpeed = 6250000; //6.25 MHz
+const uint32_t PLC01A1Controller::scmSPIOutputMaxSpeed = 5000000; //5 MHz
+
+
+
+PLC01A1Controller::PLC01A1Controller(CDeviceExecution &paDeviceExecution) :
+ forte::core::io::IODevicePollController(paDeviceExecution, 25), mSPIInputFd(0), mSPIOutputFd(0) {
+ memset(mInputArrayOld, 0, scmInputArrayLenght);
+ memset(mInputArray, 0, scmInputArrayLenght);
+ memset(mOutputArray, 0, scmOutputArrayLenght);
+ memset(mInputTX, 0, scmOutputArrayLenght);
+ memset(mOutputRX, 0, scmOutputArrayLenght);
+
+ memset(&mInputTR, 0, sizeof(struct spi_ioc_transfer));
+ memset(&mOutputTR, 0, sizeof(struct spi_ioc_transfer));
+
+ mInputTR.tx_buf = (unsigned long) mInputTX;
+ mInputTR.rx_buf = (unsigned long) mInputArray;
+ mInputTR.len = 2;
+ mInputTR.speed_hz = scmSPIInputMaxSpeed;
+ mInputTR.delay_usecs = 0;
+ mInputTR.bits_per_word = scmSPIBits;
+
+ mOutputTR.tx_buf = (unsigned long) mOutputArray;
+ mOutputTR.rx_buf = (unsigned long) mOutputRX;
+ mOutputTR.len = 2;
+ mOutputTR.speed_hz = scmSPIOutputMaxSpeed;
+ mOutputTR.delay_usecs = 0;
+ mOutputTR.bits_per_word = scmSPIBits;
+
+}
+
+void PLC01A1Controller::setConfig(struct forte::core::io::IODeviceController::Config *paConfig) {
+ Config newConfig = *static_cast<Config*>(paConfig);
+ setPollInterval(static_cast<float>(newConfig.mUpdateInterval));
+}
+
+const char* PLC01A1Controller::init() {
+
+ mSPIInputFd = open(scmSPIInputDevice, O_RDWR);
+ if(mSPIInputFd < 0) {
+ return scmFailedToOpenInputControlFile;
+ }
+
+ mSPIOutputFd = open(scmSPIOutputDevice, O_RDWR);
+ if(mSPIOutputFd < 0) {
+ return scmFailedToOpenOutputControlFile;
+ }
+
+ //SPI Mode
+ int ret = ioctl(mSPIInputFd, SPI_IOC_WR_MODE32, &scmSPIMode);
+ if(-1 == ret) {
+ return scmFailedToSetInputMode;
+ }
+
+ ret = ioctl(mSPIOutputFd, SPI_IOC_WR_MODE32, &scmSPIMode);
+ if(-1 == ret) {
+ return scmFailedToSetOutputMode;
+ }
+
+ //bits per word
+ ret = ioctl(mSPIInputFd, SPI_IOC_WR_BITS_PER_WORD, &scmSPIBits);
+ if(-1 == ret) {
+ return scmFailedToSetInputBits;
+ }
+
+ ret = ioctl(mSPIOutputFd, SPI_IOC_WR_BITS_PER_WORD, &scmSPIBits);
+ if(-1 == ret) {
+ return scmFailedToSetOutputBits;
+ }
+
+ // max speed hz
+ ret = ioctl(mSPIInputFd, SPI_IOC_WR_MAX_SPEED_HZ, &scmSPIInputMaxSpeed);
+ if(-1 == ret) {
+ return scmFailedToSetInputSpeed;
+ }
+
+ ret = ioctl(mSPIOutputFd, SPI_IOC_WR_MAX_SPEED_HZ, &scmSPIOutputMaxSpeed);
+ if(-1 == ret) {
+ return scmFailedToSetOutputSpeed;
+ }
+
+ DEVLOG_INFO("[PLC01A1Controller]: Initialization Correct!\n");
+
+ return 0;
+}
+
+void PLC01A1Controller::deInit() {
+ if(mSPIInputFd != 0) {
+ close(mSPIInputFd);
+ mSPIInputFd = 0;
+ }
+ if(mSPIOutputFd != 0) {
+ close(mSPIOutputFd);
+ mSPIOutputFd = 0;
+ }
+}
+
+void PLC01A1Controller::poll() {
+
+ int ret = ioctl(mSPIInputFd, SPI_IOC_MESSAGE(1), &mInputTR);
+ if(ret < 1) {
+ DEVLOG_ERROR("[PLC01A1Controller]: Failed sending SPI message to input controller");
+ }
+
+ // Check for updates and fire events
+ checkForInputChanges();
+
+ // Copy image to old image
+ memcpy(mInputArrayOld, mInputArray, scmInputArrayLenght);
+
+ output_parity_bits();
+
+ ret = ioctl(mSPIOutputFd, SPI_IOC_MESSAGE(1), &mOutputTR);
+ if(ret < 1) {
+ DEVLOG_ERROR("[PLC01A1Controller]: Failed sending SPI message to output controller");
+ }
+
+}
+
+bool PLC01A1Controller::isHandleValueEqual(forte::core::io::IOHandle *paHandle) {
+ return ((forte::core::io::IOHandleBit*) paHandle)->equal(mInputArrayOld);
+}
+
+forte::core::io::IOHandle* PLC01A1Controller::initHandle(forte::core::io::IODeviceController::HandleDescriptor *paHandleDescriptor) {
+ HandleDescriptor desc = *static_cast<HandleDescriptor*>(paHandleDescriptor);
+
+ return new forte::core::io::IOHandleBit(this, desc.mDirection, desc.mOffset, desc.mPosition,
+ desc.mDirection == forte::core::io::IOMapper::In ? mInputArray : mOutputArray);
+}
+
+void PLC01A1Controller::output_parity_bits() {
+
+ uint8_t outputBits[8] = { };
+ uint8_t parityBits[4] = { };
+
+ for(size_t i = 0; i < 8; i++) {
+ outputBits[i] = mOutputArray[0] & (0x80 >> i);
+ outputBits[i] = static_cast<uint8_t>(outputBits[i] >> (7 - i));
+ }
+
+ parityBits[3] = ((outputBits[7] ^ outputBits[5]) ^ outputBits[3]) ^ outputBits[1];
+ parityBits[3] = (parityBits[3] == 0x01) ? 0x08 : 0x00;
+
+
+ parityBits[2] = ((outputBits[6] ^ outputBits[4]) ^ outputBits[2]) ^ outputBits[0];
+ parityBits[2] = (parityBits[2] == 0x01) ? 0x04 : 0x00;
+
+ parityBits[1] = ((((((outputBits[7] ^ outputBits[6]) ^ outputBits[5]) ^ outputBits[4]) ^ outputBits[3])
+ ^ outputBits[2])
+ ^ outputBits[1]) ^ outputBits[0];
+ parityBits[1] = (parityBits[1] == 0x01) ? 0x02 : 0x00;
+
+
+ parityBits[0] = (parityBits[1] == 0x02) ? 0x00 : 0x01;
+
+ mOutputArray[1] = parityBits[3] | parityBits[2] | parityBits[1] | parityBits[0];
+}
+
diff --git a/src/modules/PLC01A1/plc01a1_controller.h b/src/modules/PLC01A1/plc01a1_controller.h
new file mode 100644
index 0000000..a76caca
--- /dev/null
+++ b/src/modules/PLC01A1/plc01a1_controller.h
@@ -0,0 +1,93 @@
+/*******************************************************************************
+ * Copyright (c) 2019 fortiss GmbH
+ * 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:
+ * Jose Cabral - initial API and implementation and/or initial documentation
+ *******************************************************************************/
+
+#ifndef SRC_MODULES_FESTO_CECC_FESTO_CONTROLLER_H_
+#define SRC_MODULES_FESTO_CECC_FESTO_CONTROLLER_H_
+
+#include <io/device/io_controller_poll.h>
+#include <linux/spi/spidev.h>
+
+class PLC01A1Controller : public forte::core::io::IODevicePollController {
+ public:
+ explicit PLC01A1Controller(CDeviceExecution &paDeviceExecution);
+
+ struct Config : forte::core::io::IODeviceController::Config {
+ unsigned int mUpdateInterval; //!< Sets the frequency for the data update cycle. The default value is 25 Hz.
+ };
+
+ class HandleDescriptor : public forte::core::io::IODeviceController::HandleDescriptor {
+ public:
+ uint8_t mOffset;
+ uint8_t mPosition;
+
+ HandleDescriptor(CIEC_WSTRING const &paId, forte::core::io::IOMapper::Direction paDirection, uint8_t paOffset, uint8_t paPosition) :
+ forte::core::io::IODeviceController::HandleDescriptor(paId, paDirection), mOffset(paOffset), mPosition(paPosition) {
+
+ }
+ };
+
+ void setConfig(struct forte::core::io::IODeviceController::Config* paConfig);
+
+ virtual bool isHandleValueEqual(forte::core::io::IOHandle* paHandle);
+
+ forte::core::io::IOHandle* initHandle(forte::core::io::IODeviceController::HandleDescriptor *paHandleDescriptor);
+
+ protected:
+ const char* init();
+ void deInit();
+
+ void poll();
+
+ private:
+
+ static const char *const scmSPIInputDevice;
+ static const char *const scmSPIOutputDevice;
+
+ int mSPIInputFd;
+ int mSPIOutputFd;
+
+ static const char * const scmFailedToOpenInputControlFile;
+ static const char *const scmFailedToOpenOutputControlFile;
+
+ static const uint32_t scmSPIMode;
+
+ static const char *const scmFailedToSetInputMode;
+ static const char *const scmFailedToSetOutputMode;
+
+ static const uint8_t scmSPIBits;
+
+ static const char *const scmFailedToSetInputBits;
+ static const char *const scmFailedToSetOutputBits;
+
+ static const uint32_t scmSPIInputMaxSpeed;
+ static const uint32_t scmSPIOutputMaxSpeed;
+
+ static const char *const scmFailedToSetInputSpeed;
+ static const char *const scmFailedToSetOutputSpeed;
+
+ static const size_t scmInputArrayLenght = 2;
+ static const size_t scmOutputArrayLenght = 2;
+
+ uint8_t mInputArrayOld[scmInputArrayLenght];
+ uint8_t mInputArray[scmInputArrayLenght];
+ uint8_t mOutputArray[scmOutputArrayLenght];
+
+ uint8_t mInputTX[scmInputArrayLenght];
+ uint8_t mOutputRX[scmInputArrayLenght];
+
+ struct spi_ioc_transfer mInputTR;
+ struct spi_ioc_transfer mOutputTR;
+
+ void output_parity_bits();
+};
+
+#endif /* SRC_MODULES_FESTO_CECC_FESTO_CONTROLLER_H_ */
diff --git a/tests/core/datatypes/CIEC_TIME_test.cpp b/tests/core/datatypes/CIEC_TIME_test.cpp
index ff5f1f8..905de44 100644
--- a/tests/core/datatypes/CIEC_TIME_test.cpp
+++ b/tests/core/datatypes/CIEC_TIME_test.cpp
@@ -341,6 +341,17 @@
BOOST_CHECK_EQUAL(time.getInMicroSeconds(), -10325643);
}
+BOOST_AUTO_TEST_CASE(parse_missing_s_in_microseconds_literal)
+{
+ CIEC_TIME time;
+
+ BOOST_CHECK_EQUAL(time.fromString("T#-1u"), -1);
+ BOOST_CHECK_EQUAL(time.getInMicroSeconds(), 0);
+
+ BOOST_CHECK_EQUAL(time.fromString("T#-1ut"), -1);
+ BOOST_CHECK_EQUAL(time.getInMicroSeconds(), 0);
+}
+
BOOST_AUTO_TEST_CASE(parse_time_literal_in_nanoseconds)
{
CIEC_TIME time;
@@ -358,6 +369,14 @@
BOOST_CHECK_EQUAL(time.getInNanoSeconds(), 10325643);
}
+BOOST_AUTO_TEST_CASE(parse_missing_s_in_nanoseconds_literal)
+{
+ CIEC_TIME time;
+
+ BOOST_CHECK_EQUAL(time.fromString("T#1234nx"), -1);
+ BOOST_CHECK_EQUAL(time.getInMicroSeconds(), 0);
+}
+
BOOST_AUTO_TEST_CASE(parse_negative_signed_time_literal_in_nanoseconds)
{
CIEC_TIME time;
@@ -375,4 +394,56 @@
BOOST_CHECK_EQUAL(time.getInNanoSeconds(), -10325643);
}
+BOOST_AUTO_TEST_CASE(parse_time_literals_with_missing_end_unit)
+{
+ CIEC_TIME time;
+
+ BOOST_CHECK_EQUAL(-1, time.fromString("T#68231"));
+ BOOST_CHECK_EQUAL(time.getInNanoSeconds(), 0);
+ BOOST_CHECK_EQUAL(-1, time.fromString("T#1234r"));
+ BOOST_CHECK_EQUAL(time.getInNanoSeconds(), 0);
+ BOOST_CHECK_EQUAL(-1, time.fromString("T#1h23"));
+ BOOST_CHECK_EQUAL(time.getInNanoSeconds(), 0);
+ BOOST_CHECK_EQUAL(-1, time.fromString("T#23m89"));
+ BOOST_CHECK_EQUAL(time.getInNanoSeconds(), 0);
+ BOOST_CHECK_EQUAL(-1, time.fromString("T#55s514"));
+ BOOST_CHECK_EQUAL(time.getInNanoSeconds(), 0);
+ BOOST_CHECK_EQUAL(-1, time.fromString("T#344ms1"));
+ BOOST_CHECK_EQUAL(time.getInNanoSeconds(), 0);
+ BOOST_CHECK_EQUAL(-1, time.fromString("T#344ms12399"));
+ BOOST_CHECK_EQUAL(time.getInNanoSeconds(), 0);
+ BOOST_CHECK_EQUAL(-1, time.fromString("T#344ms12399"));
+ BOOST_CHECK_EQUAL(time.getInNanoSeconds(), 0);
+}
+
+BOOST_AUTO_TEST_CASE(parse_wrong_time_prefix)
+{
+ CIEC_TIME time;
+
+ BOOST_CHECK_EQUAL(-1, time.fromString("T23m"));
+ BOOST_CHECK_EQUAL(time.getInNanoSeconds(), 0);
+ BOOST_CHECK_EQUAL(-1, time.fromString("TIME23m"));
+ BOOST_CHECK_EQUAL(time.getInNanoSeconds(), 0);
+ BOOST_CHECK_EQUAL(-1, time.fromString("Tome#23m"));
+ BOOST_CHECK_EQUAL(time.getInNanoSeconds(), 0);
+ BOOST_CHECK_EQUAL(-1, time.fromString("Tine#23m"));
+ BOOST_CHECK_EQUAL(time.getInNanoSeconds(), 0);
+ BOOST_CHECK_EQUAL(-1, time.fromString("Tima#23m"));
+ BOOST_CHECK_EQUAL(time.getInNanoSeconds(), 0);
+}
+
+BOOST_AUTO_TEST_CASE(parse_time_in_struct_or_array_literal)
+{
+ CIEC_TIME time;
+
+ BOOST_CHECK_EQUAL(7, time.fromString("T#999ms, "));
+ BOOST_CHECK_EQUAL(time.getInMilliSeconds(), 999);
+
+ BOOST_CHECK_EQUAL(6, time.fromString("T#23ms , "));
+ BOOST_CHECK_EQUAL(time.getInMilliSeconds(), 23);
+
+ BOOST_CHECK_EQUAL(12, time.fromString("T#10325643us,"));
+ BOOST_CHECK_EQUAL(time.getInMicroSeconds(), 10325643);
+}
+
BOOST_AUTO_TEST_SUITE_END()