mirror of
https://github.com/sergeyyarkov/modbus-logger.git
synced 2026-10-11 10:28:51 +03:00
289 lines
6.9 KiB
C
289 lines
6.9 KiB
C
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <stdbool.h>
|
|
#include <time.h>
|
|
#include <windows.h>
|
|
#include <signal.h>
|
|
#include <dir.h>
|
|
#include <modbus.h>
|
|
|
|
#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;
|
|
}
|