From 5a70a1e516f2c7481e2e37d99bf71c907abd0984 Mon Sep 17 00:00:00 2001 From: Steven Smethurst Date: Fri, 19 Jul 2019 13:52:43 -0700 Subject: [PATCH] First version --- .gitignore | 20 ++ .gitlab-ci.yml | 20 ++ .gitmodules | 6 + .../ModbusTCPMasterExampleCpp.cpp | 207 ++++++++++++++++++ .../ModbusTCPMasterExampleCpp.sln | 31 +++ .../ModbusTCPMasterExampleCpp.vcxproj | 177 +++++++++++++++ .../ModbusTCPMasterExampleCpp.vcxproj.filters | 48 ++++ .../ModbusTCPMasterExampleCpp.vcxproj.user | 11 + README.md | 35 ++- ...odbusTCPMasterExampleCpp_Win32_Release.exe | Bin 0 -> 24064 bytes submodules/cas-modbus-stack | 1 + 11 files changed, 554 insertions(+), 2 deletions(-) create mode 100644 .gitignore create mode 100644 .gitlab-ci.yml create mode 100644 .gitmodules create mode 100644 ModbusTCPMasterExampleCpp/ModbusTCPMasterExampleCpp.cpp create mode 100644 ModbusTCPMasterExampleCpp/ModbusTCPMasterExampleCpp.sln create mode 100644 ModbusTCPMasterExampleCpp/ModbusTCPMasterExampleCpp.vcxproj create mode 100644 ModbusTCPMasterExampleCpp/ModbusTCPMasterExampleCpp.vcxproj.filters create mode 100644 ModbusTCPMasterExampleCpp/ModbusTCPMasterExampleCpp.vcxproj.user create mode 100644 bin/ModbusTCPMasterExampleCpp_Win32_Release.exe create mode 160000 submodules/cas-modbus-stack diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..0ba2da6 --- /dev/null +++ b/.gitignore @@ -0,0 +1,20 @@ + +ModbusTCPMasterExampleCpp/\.vs/ + +ModbusTCPMasterExampleCpp/Debug/ + +ModbusTCPMasterExampleCpp/Release/ + +*.lib + +*.ilk + +*.pdb + +*.exp + +*.iobj + +*.ipdb + +bin/ModbusTCPMasterExampleCpp_Win32_Debug\.exe diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml new file mode 100644 index 0000000..8598870 --- /dev/null +++ b/.gitlab-ci.yml @@ -0,0 +1,20 @@ +stages: + - build + +Build: + stage: build + tags: + - windows + - msvs + before_script: + - 'call "%PROGRAMFILES(X86)%\Microsoft Visual Studio\2019\Community\Common7\Tools\VsMSBuildCmd.bat"' + - msbuild /version + - "echo #define CI_PIPELINE_IID %CI_PIPELINE_IID% >source/CIBuildSettings.h" + script: + # Create the bin directory if it does not exist + - cd ModbusTCPMasterExampleCpp + - msbuild ModbusTCPMasterExampleCpp.sln /p:Configuration="Release" /p:Platform="x86" + artifacts: + paths: + - bin\ModbusTCPMasterExampleCpp_Win32_Release.exe + \ No newline at end of file diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 0000000..a63be82 --- /dev/null +++ b/.gitmodules @@ -0,0 +1,6 @@ +[submodule "submodules/cas-common"] + path = submodules/cas-common + url = https://gitlab.com/chipkin/cas-common.git +[submodule "submodules/cas-modbus-stack"] + path = submodules/cas-modbus-stack + url = https://gitlab.com/chipkin/cas-modbus-stack.git \ No newline at end of file diff --git a/ModbusTCPMasterExampleCpp/ModbusTCPMasterExampleCpp.cpp b/ModbusTCPMasterExampleCpp/ModbusTCPMasterExampleCpp.cpp new file mode 100644 index 0000000..17b33ca --- /dev/null +++ b/ModbusTCPMasterExampleCpp/ModbusTCPMasterExampleCpp.cpp @@ -0,0 +1,207 @@ +// ModbusTCPMasterExampleCpp.cpp : This file contains the 'main' function. Program execution begins and ends there. +// + +#include +// CASModbusMasterTCPExample +// +// Last updated: 2017 Dec 12 +// + +#include +#include // Current time in seconds. + +#include "CTCP.h" // TCP used by Modbus TCP +#include "CASModbusAdapter.h" // Loads all the Modbus functions. +#include "ChipkinEndianness.h" // Helps with OS depenent Endianness + +using namespace ChipkinCommon; + +// Settings +// =========================== +const char SETTING_TCP_IP_ADDRESS[] = "127.0.0.1"; +// const char SETTING_TCP_IP_ADDRESS[] = "192.168.1.201"; +const unsigned short SETTING_TCP_PORT = 502; +const unsigned char SETTING_MODBUS_SERVER_SLAVE_ADDRESS = 0x00; +unsigned int SETTING_MODBUS_TYPE = 2; // MODBUS_TYPE_RTU = 1 || MODBUS_TYPE_TCP = 2 + +// Globals +// =========================== +// TCP connection +CTCP gTcp; + + +// API return codes. +// =========================== +static const unsigned int MODBUS_STATUS_ERROR_UNKNOWN = 0; +static const unsigned int MODBUS_STATUS_SUCCESS = 1; + +// Modbus function codes +// =========================== +static const unsigned char MODBUS_FUNCTION_01_READ_COIL_STATUS = 1; +static const unsigned char MODBUS_FUNCTION_02_READ_INPUT_STATUS = 2; +static const unsigned char MODBUS_FUNCTION_03_READ_HOLDING_REGISTERS = 3; +static const unsigned char MODBUS_FUNCTION_04_READ_INPUT_REGISTERS = 4; +static const unsigned char MODBUS_FUNCTION_05_FORCE_SINGLE_COIL = 5; +static const unsigned char MODBUS_FUNCTION_06_PRESET_SINGLE_REGISTER = 6; +static const unsigned char MODBUS_FUNCTION_0F_FORCE_MULTIPLE_COILS = 15; +static const unsigned char MODBUS_FUNCTION_10_FORCE_MULTIPLE_REGISTERS = 16; +static const unsigned short MODBUS_FORCE_SINGLE_COIL_ON = 0xFF00; +static const unsigned short MODBUS_FORCE_SINGLE_COIL_OFF = 0x0000; + +// Modbus exception codes +// =========================== +static const unsigned int MODBUS_STATUS_EXCEPTION_01_ILLEGAL_FUNCTION = 0x01; +static const unsigned int MODBUS_STATUS_EXCEPTION_02_ILLEGAL_DATA_ADDRESS = 0x02; +static const unsigned int MODBUS_STATUS_EXCEPTION_04_SLAVE_DEVICE_FAILURE = 0x04; + +// Test functions +// =========================== +void TestWriteRequest(unsigned short connectionID); +void TestReadRequest(unsigned short connectionID); + + + +// Helper functions +// =========================== + +unsigned char SetBit(unsigned char data, unsigned char bit, bool value) +{ + // http://stackoverflow.com/a/47990 + data ^= (-(value ? 1 : 0) ^ data) & (1 << bit); + return data; +} +bool GetBit(unsigned char data, unsigned char bit) +{ + return ((data >> bit) & 1); +} + +// Callback functions +// =========================== +bool sendModbusMessage(const unsigned short connectionId, const unsigned char* payload, const unsigned short payloadSize) +{ + // Debug print sent message. + printf("FYI: TX: "); + for (unsigned int offset = 0; offset < payloadSize; offset++) + { + printf("%02X ", payload[offset]); + } + printf("\n"); + + if (!gTcp.SendMessage(connectionId, payload, payloadSize)) + { + printf("Error: SendMessage failed.\n"); + return false; // Unknonw error + } + // Everything looks good. + return true; +} +unsigned int recvModbusMessage(unsigned short& connectionId, unsigned char* payload, unsigned short maxPayloadSize) +{ + if (maxPayloadSize <= 0 || payload == NULL) + { + return 0; // No space to store message. + } + int length = gTcp.GetMessage(connectionId, payload, maxPayloadSize); + if (length <= 0) + { + return 0; + } + + // Debug print recived message. + printf("FYI: RX: "); + for (unsigned int offset = 0; offset < length; offset++) + { + printf("%02X ", payload[offset]); + } + printf("\n"); + + // Everything looks good. + return length; +} +unsigned long currentTime() +{ + return (unsigned long)time(0); +} + +int main() +{ + // Load the DLL functions + // -------------------------------- + if (!LoadModbusFunctions()) + { + printf("\nError could not load DLL functions\n\n"); + return 1; + } + printf("FYI: Modbus Stack version: %d.%d.%d.%d\n", fpModbusStack_GetAPIMajorVersion(), fpModbusStack_GetAPIMinorVersion(), fpModbusStack_GetAPIPatchVersion(), fpModbusStack_GetAPIBuildVersion()); + + // Set up the API and callbacks. + // -------------------------------- + unsigned int returnCode = fpModbusStack_Init(SETTING_MODBUS_TYPE, sendModbusMessage, recvModbusMessage, currentTime); + if (returnCode != MODBUS_STATUS_SUCCESS) + { + printf("\nError: Could not init the Modbus Stack, returnCode=%d\n\n", returnCode); + return 1; + } + printf("FYI: Modbus stack init, successfuly\n"); + + // Connect to the Modbus Slave + printf("FYI: Attempting to connect to TCP IPAddress=[%s], port=[%d]... \n", SETTING_TCP_IP_ADDRESS, SETTING_TCP_PORT); + int connectionID = gTcp.Connect(SETTING_TCP_IP_ADDRESS, SETTING_TCP_PORT); + if (connectionID < 0) { + printf("\n"); + printf("Error: Can not connect to TCP server. IP Address=[%s], port=[%d], lastError=[%d]\n\n", SETTING_TCP_IP_ADDRESS, SETTING_TCP_PORT, gTcp.GetLastError()); + return 1; + } + printf("Connected.\n"); + + // Build and send the Modbus messages + TestReadRequest(connectionID); + TestWriteRequest(connectionID); + + return 0; +} + + +void TestReadRequest(unsigned short connectionID) { + // Create a read request. + const unsigned char modbusFunction = MODBUS_FUNCTION_03_READ_HOLDING_REGISTERS; + const unsigned short modbusStartingAddress = 0; + const unsigned short modbusQuantity = 5; + unsigned short data[10]; + unsigned char exceptionCode; + + printf("FYI: Modbus read Request. SlaveAddress=[%d], function=[%d], StartingAddress=[%d], modbusQuantity=[%d]\n", SETTING_MODBUS_SERVER_SLAVE_ADDRESS, modbusFunction, modbusStartingAddress, modbusQuantity); + unsigned int returnCode = fpModbusStack_ReadRegisters(connectionID, SETTING_MODBUS_SERVER_SLAVE_ADDRESS, modbusFunction, modbusStartingAddress, modbusQuantity, (unsigned char*)data, sizeof(short) * 10, exceptionCode); + if (returnCode != MODBUS_STATUS_SUCCESS) { + printf("Error: Could not send Read Register message. returnCode=%d\n", returnCode); + return; + } + + // Print the results from the read result. + printf("Read result: \n"); + for (int offset = 0; offset < modbusQuantity; offset++) { + unsigned short value = data[offset]; + CEndianness::FromSmallEndian(&value, sizeof(short)); + printf("\tOffset[%d] Value=[%d]\n", offset, value); + } + printf("\n"); +} + +void TestWriteRequest(unsigned short connectionID) { + // Create a read request. + const unsigned char modbusFunction = MODBUS_FUNCTION_06_PRESET_SINGLE_REGISTER; + const unsigned short modbusStartingAddress = 0; + const unsigned short modbusQuantity = 1; + unsigned short data[1]; + data[0] = 1234; + CEndianness::ToSmallEndian(&data[0], sizeof(short)); + unsigned char exceptionCode; + + printf("FYI: Modbus write Request. SlaveAddress=[%d], function=[%d], StartingAddress=[%d], modbusQuantity=[%d], value=[%d]\n", SETTING_MODBUS_SERVER_SLAVE_ADDRESS, modbusFunction, modbusStartingAddress, modbusQuantity, data[0]); + unsigned int returnCode = fpModbusStack_WriteRegisters(connectionID, SETTING_MODBUS_SERVER_SLAVE_ADDRESS, modbusFunction, modbusStartingAddress, (unsigned char*)data, (unsigned short)modbusQuantity, exceptionCode); + if (returnCode != MODBUS_STATUS_SUCCESS) { + printf("Error: Could not send Read Register message. returnCode=%d\n", returnCode); + return; + } + printf("FYI: Write successful\n"); +} \ No newline at end of file diff --git a/ModbusTCPMasterExampleCpp/ModbusTCPMasterExampleCpp.sln b/ModbusTCPMasterExampleCpp/ModbusTCPMasterExampleCpp.sln new file mode 100644 index 0000000..eaa9c46 --- /dev/null +++ b/ModbusTCPMasterExampleCpp/ModbusTCPMasterExampleCpp.sln @@ -0,0 +1,31 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 16 +VisualStudioVersion = 16.0.29009.5 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ModbusTCPMasterExampleCpp", "ModbusTCPMasterExampleCpp.vcxproj", "{B46965D5-1AD2-46B0-BEA6-B6A5D62A9771}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|x64 = Debug|x64 + Debug|x86 = Debug|x86 + Release|x64 = Release|x64 + Release|x86 = Release|x86 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {B46965D5-1AD2-46B0-BEA6-B6A5D62A9771}.Debug|x64.ActiveCfg = Debug|x64 + {B46965D5-1AD2-46B0-BEA6-B6A5D62A9771}.Debug|x64.Build.0 = Debug|x64 + {B46965D5-1AD2-46B0-BEA6-B6A5D62A9771}.Debug|x86.ActiveCfg = Debug|Win32 + {B46965D5-1AD2-46B0-BEA6-B6A5D62A9771}.Debug|x86.Build.0 = Debug|Win32 + {B46965D5-1AD2-46B0-BEA6-B6A5D62A9771}.Release|x64.ActiveCfg = Release|x64 + {B46965D5-1AD2-46B0-BEA6-B6A5D62A9771}.Release|x64.Build.0 = Release|x64 + {B46965D5-1AD2-46B0-BEA6-B6A5D62A9771}.Release|x86.ActiveCfg = Release|Win32 + {B46965D5-1AD2-46B0-BEA6-B6A5D62A9771}.Release|x86.Build.0 = Release|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {D0436510-9A87-46B5-AFCC-25E53DC11382} + EndGlobalSection +EndGlobal diff --git a/ModbusTCPMasterExampleCpp/ModbusTCPMasterExampleCpp.vcxproj b/ModbusTCPMasterExampleCpp/ModbusTCPMasterExampleCpp.vcxproj new file mode 100644 index 0000000..d6e627d --- /dev/null +++ b/ModbusTCPMasterExampleCpp/ModbusTCPMasterExampleCpp.vcxproj @@ -0,0 +1,177 @@ + + + + + Debug + Win32 + + + Release + Win32 + + + Debug + x64 + + + Release + x64 + + + + 16.0 + {B46965D5-1AD2-46B0-BEA6-B6A5D62A9771} + Win32Proj + ModbusTCPMasterExampleCpp + 10.0 + + + + Application + true + v142 + NotSet + + + Application + false + v142 + true + NotSet + + + Application + true + v142 + Unicode + + + Application + false + v142 + true + Unicode + + + + + + + + + + + + + + + + + + + + + true + $(ProjectDir)..\bin + $(ProjectName)_$(Platform)_$(Configuration) + + + true + + + false + $(ProjectDir)..\bin + $(ProjectName)_$(Platform)_$(Configuration) + + + false + + + + + + Level3 + Disabled + true + WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions);_CRT_SECURE_NO_WARNINGS; _WINSOCK_DEPRECATED_NO_WARNINGS;CAS_MODBUS_STACK_LIB_TYPE_LIB + true + $(SolutionDir)..\submodules\cas-modbus-stack\source;$(SolutionDir)..\submodules\cas-modbus-stack\adapters\cpp;$(SolutionDir)..\submodules\cas-common\source;$(SolutionDir)..\submodules\cas-common\resources;%(AdditionalIncludeDirectories) + + + Console + true + $(SolutionDir)..\bin;%(AdditionalLibraryDirectories) + + + + + + + Level3 + Disabled + true + _DEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + + + Console + true + + + + + + + Level3 + MaxSpeed + true + true + true + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions);_CRT_SECURE_NO_WARNINGS; _WINSOCK_DEPRECATED_NO_WARNINGS;CAS_MODBUS_STACK_LIB_TYPE_LIB + true + $(SolutionDir)..\bin;$(SolutionDir)..\submodules\cas-modbus-stack\source;$(SolutionDir)..\submodules\cas-modbus-stack\adapters\cpp;$(SolutionDir)..\submodules\cas-common\source;$(SolutionDir)..\submodules\cas-common\resources;%(AdditionalIncludeDirectories) + + + Console + true + true + true + $(SolutionDir)..\bin;%(AdditionalLibraryDirectories) + + + + + + + Level3 + MaxSpeed + true + true + true + NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + + + Console + true + true + true + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/ModbusTCPMasterExampleCpp/ModbusTCPMasterExampleCpp.vcxproj.filters b/ModbusTCPMasterExampleCpp/ModbusTCPMasterExampleCpp.vcxproj.filters new file mode 100644 index 0000000..3536890 --- /dev/null +++ b/ModbusTCPMasterExampleCpp/ModbusTCPMasterExampleCpp.vcxproj.filters @@ -0,0 +1,48 @@ + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hh;hpp;hxx;hm;inl;inc;ipp;xsd + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms + + + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + \ No newline at end of file diff --git a/ModbusTCPMasterExampleCpp/ModbusTCPMasterExampleCpp.vcxproj.user b/ModbusTCPMasterExampleCpp/ModbusTCPMasterExampleCpp.vcxproj.user new file mode 100644 index 0000000..de8ca72 --- /dev/null +++ b/ModbusTCPMasterExampleCpp/ModbusTCPMasterExampleCpp.vcxproj.user @@ -0,0 +1,11 @@ + + + + $(ProjectDir)..\bin + WindowsLocalDebugger + + + $(ProjectDir)..\bin + WindowsLocalDebugger + + \ No newline at end of file diff --git a/README.md b/README.md index 4d00e19..c3b4522 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,33 @@ -# ModbusTCPMasterExampleCpp -A basic Modbus TCP Master example written in CPP using the CAS Modbus Stack +# Modbus TCP Master Example Cpp + +A basic Modbus TCP Master example written in CPP using the [CAS Modbus Stack](https://store.chipkin.com/services/stacks/modbus-stack) + +## Example output + +```txt +FYI: Modbus Stack version: 2.3.11.0 +FYI: Modbus stack init, successfuly +FYI: Attempting to connect to TCP IPAddress=[127.0.0.1], port=[502]... +Connected. +FYI: Modbus read Request. SlaveAddress=[0], function=[3], StartingAddress=[0], modbusQuantity=[5] +FYI: TX: 00 00 00 00 00 06 00 03 00 00 00 05 +FYI: RX: 00 00 00 00 00 0D 00 03 0A 04 D2 00 01 00 02 00 03 00 04 +Read result: + Offset[0] Value=[1234] + Offset[1] Value=[1] + Offset[2] Value=[2] + Offset[3] Value=[3] + Offset[4] Value=[4] + +FYI: Modbus write Request. SlaveAddress=[0], function=[6], StartingAddress=[0], modbusQuantity=[1], value=[1234] +FYI: TX: 00 00 00 00 00 06 00 06 00 00 04 D2 +FYI: RX: 00 00 00 00 00 06 00 06 00 00 04 D2 +FYI: Write successful +``` + +## Building + +1. Copy *CASModbusStack_Win32_Debug.dll*, *CASModbusStack_Win32_Release.dll*, *CASModbusStack_x64_Debug.dll*, and *CASModbusStack_x64_Release.dll* from the [CAS Modbus Stack](https://store.chipkin.com/services/stacks/modbus-stack) project into the /bin/ folder. +2. Use [Visual Studios 2019](https://visualstudio.microsoft.com/vs/) to build the project. The solution can be found in the */ModbusTCPSlaveExampleCpp/* folder. + +Note: The project is automaticly build on every checkin using GitlabCI. diff --git a/bin/ModbusTCPMasterExampleCpp_Win32_Release.exe b/bin/ModbusTCPMasterExampleCpp_Win32_Release.exe new file mode 100644 index 0000000000000000000000000000000000000000..977ae136b8defaa372c19733adeca998b0894281 GIT binary patch literal 24064 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 literal 0 HcmV?d00001 diff --git a/submodules/cas-modbus-stack b/submodules/cas-modbus-stack new file mode 160000 index 0000000..e663f4e --- /dev/null +++ b/submodules/cas-modbus-stack @@ -0,0 +1 @@ +Subproject commit e663f4e727e24dcdb96ba3d22e78a47dcca8847d