commit 1d0a21cd92f233cf1c2cb617de67e844493458f6 Author: sergeyyarkov Date: Wed Oct 18 22:52:41 2023 +0300 first diff --git a/bin/Debug/modbus-logger.exe b/bin/Debug/modbus-logger.exe new file mode 100644 index 0000000..3387da3 Binary files /dev/null and b/bin/Debug/modbus-logger.exe differ diff --git a/bin/Debug/modbus.dll b/bin/Debug/modbus.dll new file mode 100644 index 0000000..89fd83b Binary files /dev/null and b/bin/Debug/modbus.dll differ diff --git a/bin/Release/modbus-logger.exe b/bin/Release/modbus-logger.exe new file mode 100644 index 0000000..c56181c Binary files /dev/null and b/bin/Release/modbus-logger.exe differ diff --git a/bin/Release/modbus.dll b/bin/Release/modbus.dll new file mode 100644 index 0000000..89fd83b Binary files /dev/null and b/bin/Release/modbus.dll differ diff --git a/bin/Release/settings.conf b/bin/Release/settings.conf new file mode 100644 index 0000000..dfa2511 --- /dev/null +++ b/bin/Release/settings.conf @@ -0,0 +1,12 @@ +CONNECTION_TYPE=TCP +IP=127.0.0.1 +PORT=502 +RTU_PATH=COM1 +RTU_BAUD=9600 +RTU_PARITY=N +RTU_DATA_BITS=8 +RTU_STOP_BITS=1 +POLL_INTERVAL_MS=1000 +LOGGER_DIR=C:\Users\VBox\Documents\Log\Modbus\Network1 +ENABLE_STDOUT_LOG=1 +SLAVE_IDS=1,2,3,4 diff --git a/lib/libmodbus_win32/modbus-rtu.h b/lib/libmodbus_win32/modbus-rtu.h new file mode 100644 index 0000000..8e89e73 --- /dev/null +++ b/lib/libmodbus_win32/modbus-rtu.h @@ -0,0 +1,43 @@ +/* + * Copyright © Stéphane Raimbault + * + * SPDX-License-Identifier: LGPL-2.1-or-later + */ + +#ifndef MODBUS_RTU_H +#define MODBUS_RTU_H + +#include "modbus.h" + +MODBUS_BEGIN_DECLS + +/* Modbus_Application_Protocol_V1_1b.pdf Chapter 4 Section 1 Page 5 + * RS232 / RS485 ADU = 253 bytes + slave (1 byte) + CRC (2 bytes) = 256 bytes + */ +#define MODBUS_RTU_MAX_ADU_LENGTH 256 + +MODBUS_API modbus_t * +modbus_new_rtu(const char *device, int baud, char parity, int data_bit, int stop_bit); + +#define MODBUS_RTU_RS232 0 +#define MODBUS_RTU_RS485 1 + +MODBUS_API int modbus_rtu_set_serial_mode(modbus_t *ctx, int mode); +MODBUS_API int modbus_rtu_get_serial_mode(modbus_t *ctx); + +#define MODBUS_RTU_RTS_NONE 0 +#define MODBUS_RTU_RTS_UP 1 +#define MODBUS_RTU_RTS_DOWN 2 + +MODBUS_API int modbus_rtu_set_rts(modbus_t *ctx, int mode); +MODBUS_API int modbus_rtu_get_rts(modbus_t *ctx); + +MODBUS_API int modbus_rtu_set_custom_rts(modbus_t *ctx, + void (*set_rts)(modbus_t *ctx, int on)); + +MODBUS_API int modbus_rtu_set_rts_delay(modbus_t *ctx, int us); +MODBUS_API int modbus_rtu_get_rts_delay(modbus_t *ctx); + +MODBUS_END_DECLS + +#endif /* MODBUS_RTU_H */ diff --git a/lib/libmodbus_win32/modbus-tcp.h b/lib/libmodbus_win32/modbus-tcp.h new file mode 100644 index 0000000..768d38c --- /dev/null +++ b/lib/libmodbus_win32/modbus-tcp.h @@ -0,0 +1,52 @@ +/* + * Copyright © Stéphane Raimbault + * + * SPDX-License-Identifier: LGPL-2.1-or-later + */ + +#ifndef MODBUS_TCP_H +#define MODBUS_TCP_H + +#include "modbus.h" + +MODBUS_BEGIN_DECLS + +#if defined(_WIN32) && !defined(__CYGWIN__) +/* Win32 with MinGW, supplement to */ +#include +#if !defined(ECONNRESET) +#define ECONNRESET WSAECONNRESET +#endif +#if !defined(ECONNREFUSED) +#define ECONNREFUSED WSAECONNREFUSED +#endif +#if !defined(ETIMEDOUT) +#define ETIMEDOUT WSAETIMEDOUT +#endif +#if !defined(ENOPROTOOPT) +#define ENOPROTOOPT WSAENOPROTOOPT +#endif +#if !defined(EINPROGRESS) +#define EINPROGRESS WSAEINPROGRESS +#endif +#endif + +#define MODBUS_TCP_DEFAULT_PORT 502 +#define MODBUS_TCP_SLAVE 0xFF + +/* Modbus_Application_Protocol_V1_1b.pdf Chapter 4 Section 1 Page 5 + * TCP MODBUS ADU = 253 bytes + MBAP (7 bytes) = 260 bytes + */ +#define MODBUS_TCP_MAX_ADU_LENGTH 260 + +MODBUS_API modbus_t *modbus_new_tcp(const char *ip_address, int port); +MODBUS_API int modbus_tcp_listen(modbus_t *ctx, int nb_connection); +MODBUS_API int modbus_tcp_accept(modbus_t *ctx, int *s); + +MODBUS_API modbus_t *modbus_new_tcp_pi(const char *node, const char *service); +MODBUS_API int modbus_tcp_pi_listen(modbus_t *ctx, int nb_connection); +MODBUS_API int modbus_tcp_pi_accept(modbus_t *ctx, int *s); + +MODBUS_END_DECLS + +#endif /* MODBUS_TCP_H */ diff --git a/lib/libmodbus_win32/modbus-version.h b/lib/libmodbus_win32/modbus-version.h new file mode 100644 index 0000000..750c74a --- /dev/null +++ b/lib/libmodbus_win32/modbus-version.h @@ -0,0 +1,51 @@ +/* + * Copyright © Stéphane Raimbault + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef MODBUS_VERSION_H +#define MODBUS_VERSION_H + +/* The major version, (1, if %LIBMODBUS_VERSION is 1.2.3) */ +#define LIBMODBUS_VERSION_MAJOR (3) + +/* The minor version (2, if %LIBMODBUS_VERSION is 1.2.3) */ +#define LIBMODBUS_VERSION_MINOR (1) + +/* The micro version (3, if %LIBMODBUS_VERSION is 1.2.3) */ +#define LIBMODBUS_VERSION_MICRO (1) + +/* The full version, like 1.2.3 */ +#define LIBMODBUS_VERSION 3.1.1 + +/* The full version, in string form (suited for string concatenation) + */ +#define LIBMODBUS_VERSION_STRING "3.1.1" + +/* Numerically encoded version, eg. v1.2.3 is 0x010203 */ +#define LIBMODBUS_VERSION_HEX \ + ((LIBMODBUS_VERSION_MAJOR << 16) | (LIBMODBUS_VERSION_MINOR << 8) | \ + (LIBMODBUS_VERSION_MICRO << 0)) + +/* Evaluates to True if the version is greater than @major, @minor and @micro + */ +#define LIBMODBUS_VERSION_CHECK(major, minor, micro) \ + (LIBMODBUS_VERSION_MAJOR > (major) || \ + (LIBMODBUS_VERSION_MAJOR == (major) && LIBMODBUS_VERSION_MINOR > (minor)) || \ + (LIBMODBUS_VERSION_MAJOR == (major) && LIBMODBUS_VERSION_MINOR == (minor) && \ + LIBMODBUS_VERSION_MICRO >= (micro))) + +#endif /* MODBUS_VERSION_H */ diff --git a/lib/libmodbus_win32/modbus.dll b/lib/libmodbus_win32/modbus.dll new file mode 100644 index 0000000..89fd83b Binary files /dev/null and b/lib/libmodbus_win32/modbus.dll differ diff --git a/lib/libmodbus_win32/modbus.h b/lib/libmodbus_win32/modbus.h new file mode 100644 index 0000000..55ef08a --- /dev/null +++ b/lib/libmodbus_win32/modbus.h @@ -0,0 +1,329 @@ +/* + * Copyright © Stéphane Raimbault + * + * SPDX-License-Identifier: LGPL-2.1-or-later + */ + +#ifndef MODBUS_H +#define MODBUS_H + +// clang-format off +/* Add this for macros that defined unix flavor */ +#if (defined(__unix__) || defined(unix)) && !defined(USG) +# include +#endif + +#ifndef _MSC_VER +# include +#else +# include "stdint.h" +#endif + +#include "modbus-version.h" + +#if defined(_MSC_VER) +# if defined(DLLBUILD) +/* define DLLBUILD when building the DLL */ +# define MODBUS_API __declspec(dllexport) +# else +# define MODBUS_API __declspec(dllimport) +# endif +#else +# define MODBUS_API +#endif + +#ifdef __cplusplus +# define MODBUS_BEGIN_DECLS extern "C" { +# define MODBUS_END_DECLS } +#else +# define MODBUS_BEGIN_DECLS +# define MODBUS_END_DECLS +#endif +// clang-format on + +MODBUS_BEGIN_DECLS + +#ifndef FALSE +#define FALSE 0 +#endif + +#ifndef TRUE +#define TRUE 1 +#endif + +#ifndef OFF +#define OFF 0 +#endif + +#ifndef ON +#define ON 1 +#endif + +/* Modbus function codes */ +#define MODBUS_FC_READ_COILS 0x01 +#define MODBUS_FC_READ_DISCRETE_INPUTS 0x02 +#define MODBUS_FC_READ_HOLDING_REGISTERS 0x03 +#define MODBUS_FC_READ_INPUT_REGISTERS 0x04 +#define MODBUS_FC_WRITE_SINGLE_COIL 0x05 +#define MODBUS_FC_WRITE_SINGLE_REGISTER 0x06 +#define MODBUS_FC_READ_EXCEPTION_STATUS 0x07 +#define MODBUS_FC_WRITE_MULTIPLE_COILS 0x0F +#define MODBUS_FC_WRITE_MULTIPLE_REGISTERS 0x10 +#define MODBUS_FC_REPORT_SLAVE_ID 0x11 +#define MODBUS_FC_MASK_WRITE_REGISTER 0x16 +#define MODBUS_FC_WRITE_AND_READ_REGISTERS 0x17 + +#define MODBUS_BROADCAST_ADDRESS 0 + +/* Modbus_Application_Protocol_V1_1b.pdf (chapter 6 section 1 page 12) + * Quantity of Coils to read (2 bytes): 1 to 2000 (0x7D0) + * (chapter 6 section 11 page 29) + * Quantity of Coils to write (2 bytes): 1 to 1968 (0x7B0) + */ +#define MODBUS_MAX_READ_BITS 2000 +#define MODBUS_MAX_WRITE_BITS 1968 + +/* Modbus_Application_Protocol_V1_1b.pdf (chapter 6 section 3 page 15) + * Quantity of Registers to read (2 bytes): 1 to 125 (0x7D) + * (chapter 6 section 12 page 31) + * Quantity of Registers to write (2 bytes) 1 to 123 (0x7B) + * (chapter 6 section 17 page 38) + * Quantity of Registers to write in R/W registers (2 bytes) 1 to 121 (0x79) + */ +#define MODBUS_MAX_READ_REGISTERS 125 +#define MODBUS_MAX_WRITE_REGISTERS 123 +#define MODBUS_MAX_WR_WRITE_REGISTERS 121 +#define MODBUS_MAX_WR_READ_REGISTERS 125 + +/* The size of the MODBUS PDU is limited by the size constraint inherited from + * the first MODBUS implementation on Serial Line network (max. RS485 ADU = 256 + * bytes). Therefore, MODBUS PDU for serial line communication = 256 - Server + * address (1 byte) - CRC (2 bytes) = 253 bytes. + */ +#define MODBUS_MAX_PDU_LENGTH 253 + +/* Consequently: + * - RTU MODBUS ADU = 253 bytes + Server address (1 byte) + CRC (2 bytes) = 256 + * bytes. + * - TCP MODBUS ADU = 253 bytes + MBAP (7 bytes) = 260 bytes. + * so the maximum of both backend in 260 bytes. This size can used to allocate + * an array of bytes to store responses and it will be compatible with the two + * backends. + */ +#define MODBUS_MAX_ADU_LENGTH 260 + +/* Random number to avoid errno conflicts */ +#define MODBUS_ENOBASE 112345678 + +/* Protocol exceptions */ +enum { + MODBUS_EXCEPTION_ILLEGAL_FUNCTION = 0x01, + MODBUS_EXCEPTION_ILLEGAL_DATA_ADDRESS, + MODBUS_EXCEPTION_ILLEGAL_DATA_VALUE, + MODBUS_EXCEPTION_SLAVE_OR_SERVER_FAILURE, + MODBUS_EXCEPTION_ACKNOWLEDGE, + MODBUS_EXCEPTION_SLAVE_OR_SERVER_BUSY, + MODBUS_EXCEPTION_NEGATIVE_ACKNOWLEDGE, + MODBUS_EXCEPTION_MEMORY_PARITY, + MODBUS_EXCEPTION_NOT_DEFINED, + MODBUS_EXCEPTION_GATEWAY_PATH, + MODBUS_EXCEPTION_GATEWAY_TARGET, + MODBUS_EXCEPTION_MAX +}; + +#define EMBXILFUN (MODBUS_ENOBASE + MODBUS_EXCEPTION_ILLEGAL_FUNCTION) +#define EMBXILADD (MODBUS_ENOBASE + MODBUS_EXCEPTION_ILLEGAL_DATA_ADDRESS) +#define EMBXILVAL (MODBUS_ENOBASE + MODBUS_EXCEPTION_ILLEGAL_DATA_VALUE) +#define EMBXSFAIL (MODBUS_ENOBASE + MODBUS_EXCEPTION_SLAVE_OR_SERVER_FAILURE) +#define EMBXACK (MODBUS_ENOBASE + MODBUS_EXCEPTION_ACKNOWLEDGE) +#define EMBXSBUSY (MODBUS_ENOBASE + MODBUS_EXCEPTION_SLAVE_OR_SERVER_BUSY) +#define EMBXNACK (MODBUS_ENOBASE + MODBUS_EXCEPTION_NEGATIVE_ACKNOWLEDGE) +#define EMBXMEMPAR (MODBUS_ENOBASE + MODBUS_EXCEPTION_MEMORY_PARITY) +#define EMBXGPATH (MODBUS_ENOBASE + MODBUS_EXCEPTION_GATEWAY_PATH) +#define EMBXGTAR (MODBUS_ENOBASE + MODBUS_EXCEPTION_GATEWAY_TARGET) + +/* Native libmodbus error codes */ +#define EMBBADCRC (EMBXGTAR + 1) +#define EMBBADDATA (EMBXGTAR + 2) +#define EMBBADEXC (EMBXGTAR + 3) +#define EMBUNKEXC (EMBXGTAR + 4) +#define EMBMDATA (EMBXGTAR + 5) +#define EMBBADSLAVE (EMBXGTAR + 6) + +extern const unsigned int libmodbus_version_major; +extern const unsigned int libmodbus_version_minor; +extern const unsigned int libmodbus_version_micro; + +typedef struct _modbus modbus_t; + +typedef struct _modbus_mapping_t { + int nb_bits; + int start_bits; + int nb_input_bits; + int start_input_bits; + int nb_input_registers; + int start_input_registers; + int nb_registers; + int start_registers; + uint8_t *tab_bits; + uint8_t *tab_input_bits; + uint16_t *tab_input_registers; + uint16_t *tab_registers; +} modbus_mapping_t; + +typedef enum { + MODBUS_ERROR_RECOVERY_NONE = 0, + MODBUS_ERROR_RECOVERY_LINK = (1 << 1), + MODBUS_ERROR_RECOVERY_PROTOCOL = (1 << 2) +} modbus_error_recovery_mode; + +typedef enum { + MODBUS_QUIRK_NONE = 0, + MODBUS_QUIRK_MAX_SLAVE = (1 << 1), + MODBUS_QUIRK_REPLY_TO_BROADCAST = (1 << 2), + MODBUS_QUIRK_ALL = 0xFF +} modbus_quirks; + +MODBUS_API int modbus_set_slave(modbus_t *ctx, int slave); +MODBUS_API int modbus_get_slave(modbus_t *ctx); +MODBUS_API int modbus_set_error_recovery(modbus_t *ctx, + modbus_error_recovery_mode error_recovery); +MODBUS_API int modbus_set_socket(modbus_t *ctx, int s); +MODBUS_API int modbus_get_socket(modbus_t *ctx); + +MODBUS_API int +modbus_get_response_timeout(modbus_t *ctx, uint32_t *to_sec, uint32_t *to_usec); +MODBUS_API int +modbus_set_response_timeout(modbus_t *ctx, uint32_t to_sec, uint32_t to_usec); + +MODBUS_API int +modbus_get_byte_timeout(modbus_t *ctx, uint32_t *to_sec, uint32_t *to_usec); +MODBUS_API int modbus_set_byte_timeout(modbus_t *ctx, uint32_t to_sec, uint32_t to_usec); + +MODBUS_API int +modbus_get_indication_timeout(modbus_t *ctx, uint32_t *to_sec, uint32_t *to_usec); +MODBUS_API int +modbus_set_indication_timeout(modbus_t *ctx, uint32_t to_sec, uint32_t to_usec); + +MODBUS_API int modbus_get_header_length(modbus_t *ctx); + +MODBUS_API int modbus_connect(modbus_t *ctx); +MODBUS_API void modbus_close(modbus_t *ctx); + +MODBUS_API void modbus_free(modbus_t *ctx); + +MODBUS_API int modbus_flush(modbus_t *ctx); +MODBUS_API int modbus_set_debug(modbus_t *ctx, int flag); + +MODBUS_API const char *modbus_strerror(int errnum); + +MODBUS_API int modbus_read_bits(modbus_t *ctx, int addr, int nb, uint8_t *dest); +MODBUS_API int modbus_read_input_bits(modbus_t *ctx, int addr, int nb, uint8_t *dest); +MODBUS_API int modbus_read_registers(modbus_t *ctx, int addr, int nb, uint16_t *dest); +MODBUS_API int +modbus_read_input_registers(modbus_t *ctx, int addr, int nb, uint16_t *dest); +MODBUS_API int modbus_write_bit(modbus_t *ctx, int coil_addr, int status); +MODBUS_API int modbus_write_register(modbus_t *ctx, int reg_addr, const uint16_t value); +MODBUS_API int modbus_write_bits(modbus_t *ctx, int addr, int nb, const uint8_t *data); +MODBUS_API int +modbus_write_registers(modbus_t *ctx, int addr, int nb, const uint16_t *data); +MODBUS_API int +modbus_mask_write_register(modbus_t *ctx, int addr, uint16_t and_mask, uint16_t or_mask); +MODBUS_API int modbus_write_and_read_registers(modbus_t *ctx, + int write_addr, + int write_nb, + const uint16_t *src, + int read_addr, + int read_nb, + uint16_t *dest); +MODBUS_API int modbus_report_slave_id(modbus_t *ctx, int max_dest, uint8_t *dest); + +MODBUS_API modbus_mapping_t * +modbus_mapping_new_start_address(unsigned int start_bits, + unsigned int nb_bits, + unsigned int start_input_bits, + unsigned int nb_input_bits, + unsigned int start_registers, + unsigned int nb_registers, + unsigned int start_input_registers, + unsigned int nb_input_registers); + +MODBUS_API modbus_mapping_t *modbus_mapping_new(int nb_bits, + int nb_input_bits, + int nb_registers, + int nb_input_registers); +MODBUS_API void modbus_mapping_free(modbus_mapping_t *mb_mapping); + +MODBUS_API int +modbus_send_raw_request(modbus_t *ctx, const uint8_t *raw_req, int raw_req_length); + +MODBUS_API int modbus_receive(modbus_t *ctx, uint8_t *req); + +MODBUS_API int modbus_receive_confirmation(modbus_t *ctx, uint8_t *rsp); + +MODBUS_API int modbus_reply(modbus_t *ctx, + const uint8_t *req, + int req_length, + modbus_mapping_t *mb_mapping); +MODBUS_API int +modbus_reply_exception(modbus_t *ctx, const uint8_t *req, unsigned int exception_code); +MODBUS_API int modbus_enable_quirks(modbus_t *ctx, unsigned int quirks_mask); +MODBUS_API int modbus_disable_quirks(modbus_t *ctx, unsigned int quirks_mask); + +/** + * UTILS FUNCTIONS + **/ + +#define MODBUS_GET_HIGH_BYTE(data) (((data) >> 8) & 0xFF) +#define MODBUS_GET_LOW_BYTE(data) ((data) &0xFF) +#define MODBUS_GET_INT64_FROM_INT16(tab_int16, index) \ + (((int64_t) tab_int16[(index)] << 48) | ((int64_t) tab_int16[(index) + 1] << 32) | \ + ((int64_t) tab_int16[(index) + 2] << 16) | (int64_t) tab_int16[(index) + 3]) +#define MODBUS_GET_INT32_FROM_INT16(tab_int16, index) \ + (((int32_t) tab_int16[(index)] << 16) | (int32_t) tab_int16[(index) + 1]) +#define MODBUS_GET_INT16_FROM_INT8(tab_int8, index) \ + (((int16_t) tab_int8[(index)] << 8) | (int16_t) tab_int8[(index) + 1]) +#define MODBUS_SET_INT16_TO_INT8(tab_int8, index, value) \ + do { \ + ((int8_t *) (tab_int8))[(index)] = (int8_t) ((value) >> 8); \ + ((int8_t *) (tab_int8))[(index) + 1] = (int8_t) (value); \ + } while (0) +#define MODBUS_SET_INT32_TO_INT16(tab_int16, index, value) \ + do { \ + ((int16_t *) (tab_int16))[(index)] = (int16_t) ((value) >> 16); \ + ((int16_t *) (tab_int16))[(index) + 1] = (int16_t) (value); \ + } while (0) +#define MODBUS_SET_INT64_TO_INT16(tab_int16, index, value) \ + do { \ + ((int16_t *) (tab_int16))[(index)] = (int16_t) ((value) >> 48); \ + ((int16_t *) (tab_int16))[(index) + 1] = (int16_t) ((value) >> 32); \ + ((int16_t *) (tab_int16))[(index) + 2] = (int16_t) ((value) >> 16); \ + ((int16_t *) (tab_int16))[(index) + 3] = (int16_t) (value); \ + } while (0) + +MODBUS_API void modbus_set_bits_from_byte(uint8_t *dest, int idx, const uint8_t value); +MODBUS_API void modbus_set_bits_from_bytes(uint8_t *dest, + int idx, + unsigned int nb_bits, + const uint8_t *tab_byte); +MODBUS_API uint8_t modbus_get_byte_from_bits(const uint8_t *src, + int idx, + unsigned int nb_bits); +MODBUS_API float modbus_get_float(const uint16_t *src); +MODBUS_API float modbus_get_float_abcd(const uint16_t *src); +MODBUS_API float modbus_get_float_dcba(const uint16_t *src); +MODBUS_API float modbus_get_float_badc(const uint16_t *src); +MODBUS_API float modbus_get_float_cdab(const uint16_t *src); + +MODBUS_API void modbus_set_float(float f, uint16_t *dest); +MODBUS_API void modbus_set_float_abcd(float f, uint16_t *dest); +MODBUS_API void modbus_set_float_dcba(float f, uint16_t *dest); +MODBUS_API void modbus_set_float_badc(float f, uint16_t *dest); +MODBUS_API void modbus_set_float_cdab(float f, uint16_t *dest); + +#include "modbus-rtu.h" +#include "modbus-tcp.h" + +MODBUS_END_DECLS + +#endif /* MODBUS_H */ diff --git a/lib/libmodbus_win32/modbus.lib b/lib/libmodbus_win32/modbus.lib new file mode 100644 index 0000000..4d7500d Binary files /dev/null and b/lib/libmodbus_win32/modbus.lib differ diff --git a/lib/libmodbus_win32/v3.1.10.txt b/lib/libmodbus_win32/v3.1.10.txt new file mode 100644 index 0000000..b597f65 --- /dev/null +++ b/lib/libmodbus_win32/v3.1.10.txt @@ -0,0 +1,5 @@ +3.1.10 +Kompiliert am 12.05.2023 mit Visual Studio 2008 Express C++ in einer Virtuellen Win10 x64 Maschine + +3.1.6 +Kompiliert am 09.11.2021 mit Visual Studio 2008 Express C++ in einer Virtuellen Win10 x64 Maschine \ No newline at end of file diff --git a/main.c b/main.c new file mode 100644 index 0000000..2a2460f --- /dev/null +++ b/main.c @@ -0,0 +1,288 @@ +#include +#include +#include +#include +#include +#include +#include +#include + +#define DEFAULT_POLL_INTERVAL_MS 1000 + +#define NB 5 + +#define CON_TYPE_TCP 0x01 +#define CON_TYPE_RTU 0x02 + +static volatile sig_atomic_t keep_running = 1; + +static char *get_timef(char *format, size_t maxsize) { + char *str = malloc(sizeof(char) * maxsize); + time_t system_time = time(NULL); + struct tm* time = localtime(&system_time); + strftime(str, maxsize, format, time); + return str; +} + +int get_file_size(FILE *fp) { + fseek(fp, 0, SEEK_END); + int size = ftell(fp); + fseek(fp, 0, SEEK_SET); + return size; +} + +static char *app_get_setting_val(char *key) { + FILE *fp = NULL; + char content[1024]; + char *value = malloc(sizeof(char) * 128); + bool is_exist = false; + + if ((fp = fopen("settings.conf", "r")) == NULL) { + perror("Failed open configuration file"); + exit(EXIT_FAILURE); + } + + /* read file to content */ + int c = fread(content, sizeof(char), 1024, fp); + content[c] = '\0'; + fclose(fp); + + /* extract value by key */ + char *input = strtok(content, "=\n"); + while(input != NULL) { + if (is_exist) { + strcpy(value, input); + break; + } + if (strcmp(input, key) == 0) + is_exist = true; + + input = strtok(NULL, "=\n"); + } + + if (!is_exist) { + free(value); + return NULL; + } + + return value; +} + +uint8_t app_check_con_type(char *type) { + if (strcmp(type, "TCP") == 0) return CON_TYPE_TCP; + if (strcmp(type, "RTU") == 0) return CON_TYPE_RTU; + return 0; +} + +modbus_t *app_create_connection(char *type) { + modbus_t *ctx; + + switch(app_check_con_type(type)) { + case CON_TYPE_TCP: + { + char *IP = app_get_setting_val("IP"); + char *PORT = app_get_setting_val("PORT"); + puts("Creating TCP Modbus connection."); + ctx = modbus_new_tcp(IP, atoi(PORT)); + } + break; + case CON_TYPE_RTU: + { + char *PATH = app_get_setting_val("RTU_PATH"); + char *BAUD = app_get_setting_val("RTU_BAUD"); + char *PARITY = app_get_setting_val("RTU_PARITY"); + char *DATA_BITS = app_get_setting_val("RTU_DATA_BITS"); + char *STOP_BITS = app_get_setting_val("RTU_STOP_BITS"); + puts("Creating RTU Modbus connection."); + ctx = modbus_new_rtu(PATH, atoi(BAUD), *PARITY, atoi(DATA_BITS), atoi(STOP_BITS)); + } + break; + default: + fprintf(stderr, "Connection type can be \"TCP\" or \"RTU\"."); + exit(EXIT_FAILURE); + break; + } + + if (ctx == NULL) { + fprintf(stderr, "Unable to create the libmodbus context\n"); + exit(EXIT_FAILURE); + } + + if (modbus_connect(ctx) == -1) { + perror("Connection error"); + modbus_free(ctx); + getchar(); + exit(EXIT_FAILURE); + } + + return ctx; +} + +static void app_sig_handler(int sig) { + keep_running = 0; + exit(EXIT_SUCCESS); +} + +char **strsplit(char *input, const char *delimiter, size_t *count) { + if (!input || !delimiter) return NULL; + + char *tmp = input; + size_t size = 0; + + while (*tmp != '\0') { + if (*(tmp + 1) == '\0' && *tmp != *delimiter) { + size++; + break; + } + if (*tmp == *delimiter) + size++; + tmp++; + } + + *count = size; + + char **result = malloc(sizeof(char*) * size); + if (result) { + size_t idx = 0; + char *token = strtok(input, delimiter); + while (token) { + *(result + idx++) = strdup(token); + token = strtok(NULL, delimiter); + } + } + return result; +} + +void putchar_many(char c, unsigned int count) { + while(count--) putchar(c); +} + +int main(void) { + FILE *fp = NULL; + bool is_stdout_log_enabled = 0; + uint16_t tab_reg[NB] = {0}; + uint16_t tab_reg_len = (sizeof(tab_reg) / sizeof(uint16_t)); + + char *con_type = app_get_setting_val("CONNECTION_TYPE"); + char *poll_interval = app_get_setting_val("POLL_INTERVAL_MS"); + char *enable_stdout_log = app_get_setting_val("ENABLE_STDOUT_LOG"); + char *base_logger_dir = app_get_setting_val("LOGGER_DIR"); + + size_t slaves_count = 0; + char **slave_ids_str = strsplit(app_get_setting_val("SLAVE_IDS"), ",", &slaves_count); + unsigned int *slave_ids = malloc(sizeof(unsigned int) * slaves_count); + unsigned int selected_slave_idx = 0; + unsigned int i = slaves_count; + while (i--) + slave_ids[i] = atoi(slave_ids_str[i]); + + free(slave_ids_str); + + signal(SIGINT, app_sig_handler); + + if (con_type == NULL || base_logger_dir == NULL) { + fprintf(stderr, "The \"CONNECTION_TYPE\" or \"LOGGER_DIR\" is undefined."); + exit(EXIT_FAILURE); + } + + if (enable_stdout_log != NULL) { + is_stdout_log_enabled = atoi(enable_stdout_log); + } + + modbus_t *ctx = app_create_connection(con_type); + + puts("Successfully connected."); + + modbus_set_slave(ctx, slave_ids[selected_slave_idx]); + + init_dir: ; + char *writing_date = get_timef("%Y-%d-%m", 11); + char *current_writer_dir = malloc(sizeof(char) * 256); + + snprintf(current_writer_dir, 256, "%s\\%s", base_logger_dir, writing_date); + _mkdir(current_writer_dir); + + char *logger_path = strcat(current_writer_dir, "\\log.csv"); + + if ((fp = fopen(logger_path, "a+")) == NULL) { + perror("Cannot open file for logging"); + return EXIT_FAILURE; + } + + while (keep_running) { + char *time_str = get_timef("%Y-%d-%m %H:%M:%S", 20); + char *date_str = malloc(sizeof(char) * 11); + strncpy(date_str, time_str, 10); + + /* update writing folder */ + if (strcmp(date_str, writing_date) != 0) { + fclose(fp); + free(current_writer_dir); + free(logger_path); + free(writing_date); + modbus_flush(ctx); + goto init_dir; + } + + int response = modbus_read_registers(ctx, 0, NB, tab_reg); + + /*if (response == -1) { + fprintf(stderr, "%s\n", "Error while reading registers"); + Sleep(500); + continue; + }*/ + + // csv header + int f_size = get_file_size(fp); + if (f_size <= 0) { + fputs("DATE,SLAVE_ID,", fp); + for (uint16_t i = 0; i < tab_reg_len; i++) { + fprintf(fp, "REG%d", i+1); + if (i != tab_reg_len - 1) + putc(',', fp); + } + fputc('\n', fp); + } + + /* date and slave_id */ + fprintf(fp, "%s,%d,", time_str, slave_ids[selected_slave_idx]); + + if (is_stdout_log_enabled) { + system("cls"); + printf("Log directory: %s\n", logger_path); + printf("Time: %s\n", time_str); + printf("Filesize: %d\n", f_size); + puts("Registers type: Holding"); + printf("Slaves count: %d\n", slaves_count); + printf("Data"); + } + + uint16_t i = 0; + while (i < tab_reg_len) { + if (is_stdout_log_enabled) + printf("\tREG%d: %d\n", i + 1, tab_reg[i]); + + fprintf(fp, "%d", tab_reg[i]); + + if (i != tab_reg_len - 1) + putc(',', fp); + i++; + } + + if (is_stdout_log_enabled) putchar_many('=', 65); + + free(time_str); + free(date_str); + + putc('\n', fp); + if (is_stdout_log_enabled) putchar('\n'); + Sleep(poll_interval != NULL ? atoi(poll_interval) : DEFAULT_POLL_INTERVAL_MS); + } + + puts("Stopped by signal SIGINT"); + fclose(fp); + modbus_close(ctx); + modbus_free(ctx); + + return EXIT_SUCCESS; +} diff --git a/modbus-logger.cbp b/modbus-logger.cbp new file mode 100644 index 0000000..2b23c72 --- /dev/null +++ b/modbus-logger.cbp @@ -0,0 +1,52 @@ + + + + + + diff --git a/modbus-logger.depend b/modbus-logger.depend new file mode 100644 index 0000000..909357e --- /dev/null +++ b/modbus-logger.depend @@ -0,0 +1,28 @@ +# depslib dependency file v1.0 +1697658335 source:c:\users\vbox\desktop\modbus\modbus-logger\main.c + + + + + + + + + +1670403614 c:\users\vbox\desktop\modbus\modbus-logger\lib\libmodbus_win32\modbus.h + + + "stdint.h" + "modbus-version.h" + "modbus-rtu.h" + "modbus-tcp.h" + +1683884788 c:\users\vbox\desktop\modbus\modbus-logger\lib\libmodbus_win32\modbus-version.h + +1670403614 c:\users\vbox\desktop\modbus\modbus-logger\lib\libmodbus_win32\modbus-rtu.h + "modbus.h" + +1670403614 c:\users\vbox\desktop\modbus\modbus-logger\lib\libmodbus_win32\modbus-tcp.h + "modbus.h" + + diff --git a/modbus-logger.layout b/modbus-logger.layout new file mode 100644 index 0000000..641bb9c --- /dev/null +++ b/modbus-logger.layout @@ -0,0 +1,20 @@ + + + + + + + + + + + + + + + + + + + + diff --git a/obj/Debug/main.o b/obj/Debug/main.o new file mode 100644 index 0000000..e63ea2d Binary files /dev/null and b/obj/Debug/main.o differ diff --git a/obj/Release/main.o b/obj/Release/main.o new file mode 100644 index 0000000..8d68d02 Binary files /dev/null and b/obj/Release/main.o differ