mirror of
https://github.com/emqx/neuron.git
synced 2026-10-17 04:40:42 +08:00
313 lines
8.5 KiB
C
313 lines
8.5 KiB
C
/**
|
|
* NEURON IIoT System for Industry 4.0
|
|
* Copyright (C) 2020-2022 EMQ Technologies Co., Ltd All rights reserved.
|
|
*
|
|
* This program 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 3 of the License, or (at your option) any later version.
|
|
*
|
|
* This program 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 program; if not, write to the Free Software Foundation,
|
|
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
|
**/
|
|
#include <getopt.h>
|
|
#include <memory.h>
|
|
#include <signal.h>
|
|
#include <stdbool.h>
|
|
#include <stdint.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <termios.h>
|
|
#include <unistd.h>
|
|
|
|
#include <neuron.h>
|
|
|
|
#include "modbus_s.h"
|
|
|
|
#define UNUSED(X) ((void) (X))
|
|
#define BUFFER_SIZE (4096)
|
|
|
|
zlog_category_t *neuron = NULL;
|
|
neu_events_t * events = NULL;
|
|
neu_event_io_t * event = NULL;
|
|
neu_conn_t * conn = NULL;
|
|
|
|
struct cycle_buf {
|
|
int len;
|
|
uint8_t buf[BUFFER_SIZE];
|
|
};
|
|
|
|
static struct cycle_buf recv_buf, res_buf;
|
|
|
|
static void connected(void *data, int fd);
|
|
static void disconnected(void *data, int fd);
|
|
|
|
static void sig_handler(int sig)
|
|
{
|
|
(void) sig;
|
|
|
|
nlog_warn("recv sig: %d\n", sig);
|
|
neu_conn_destory(conn);
|
|
neu_event_close(events);
|
|
exit(0);
|
|
}
|
|
|
|
static int slave_io_cb(enum neu_event_io_type type, int fd, void *usr_data)
|
|
{
|
|
UNUSED(usr_data);
|
|
if (type != NEU_EVENT_IO_READ) {
|
|
nlog_warn("read close!");
|
|
return -1;
|
|
}
|
|
|
|
int ret = read(fd, recv_buf.buf + recv_buf.len, BUFFER_SIZE - recv_buf.len);
|
|
|
|
if (ret <= 0) {
|
|
nlog_warn("recv failed!");
|
|
return -1;
|
|
}
|
|
|
|
recv_buf.len += ret;
|
|
|
|
ret = modbus_s_rtu_req(recv_buf.buf, recv_buf.len, res_buf.buf, BUFFER_SIZE,
|
|
&res_buf.len);
|
|
|
|
if (ret == -2) {
|
|
printf("recv modbus adrress for retry_test, continue wait msg\n");
|
|
return 0;
|
|
}
|
|
|
|
neu_msleep(2);
|
|
|
|
ret = write(fd, res_buf.buf, res_buf.len);
|
|
if (ret <= 0) {
|
|
nlog_warn("send failed!");
|
|
return -1;
|
|
}
|
|
|
|
recv_buf.len = 0;
|
|
|
|
return 0;
|
|
}
|
|
|
|
static inline void usage(const char *prog)
|
|
{
|
|
// clang-format off
|
|
const char *text =
|
|
"USAGE:\n"
|
|
" %s [OPTIONS]\n\n"
|
|
"OPTIONS:\n"
|
|
" -l, --link TTY device\n"
|
|
" -b, --baud TTY baud rate (default 9600)\n"
|
|
" -p, --parity TTY parity (default none)\n"
|
|
" -s, --stop TTY stop bits (default 0)\n"
|
|
" -d, --data TTY data bits (default 8)\n"
|
|
" -f, --flow Enable TTYP flow\n"
|
|
" -e, --simulate_error Simulate error\n"
|
|
" -h, --help show this help message\n"
|
|
"\n";
|
|
// clang-format on
|
|
|
|
fprintf(stderr, text, prog);
|
|
}
|
|
|
|
int main(int argc, char *argv[])
|
|
{
|
|
char * device = NULL;
|
|
neu_conn_tty_baud_e baud = NEU_CONN_TTY_BAUD_9600;
|
|
neu_conn_tty_parity_e parity = NEU_CONN_TTY_PARITY_NONE;
|
|
neu_conn_tty_stop_e stop = NEU_CONN_TTY_STOP_1;
|
|
neu_conn_tty_data_e data = NEU_CONN_TTY_DATA_8;
|
|
neu_conn_tty_flow_e flow = NEU_CONN_TTYP_FLOW_DISABLE;
|
|
bool sim = false;
|
|
|
|
struct option long_options[] = {
|
|
{ "help", no_argument, NULL, 'h' },
|
|
{ "link", required_argument, NULL, 'l' },
|
|
{ "baud", required_argument, NULL, 'b' },
|
|
{ "parity", required_argument, NULL, 'p' },
|
|
{ "stop", required_argument, NULL, 's' },
|
|
{ "data", required_argument, NULL, 'd' },
|
|
{ "flow", no_argument, NULL, 'f' },
|
|
{ "simulate_error", no_argument, NULL, 'e' },
|
|
{ NULL, 0, NULL, 0 },
|
|
};
|
|
|
|
int c = 0;
|
|
int option_index = 0;
|
|
|
|
while ((c = getopt_long(argc, argv, "hl:b:p:s:d:fe", long_options,
|
|
&option_index)) != -1) {
|
|
switch (c) {
|
|
case 'h':
|
|
usage(argv[0]);
|
|
return 0;
|
|
case 'l':
|
|
device = optarg;
|
|
break;
|
|
case 'b': {
|
|
int t_baud = atoi(optarg);
|
|
switch (t_baud) {
|
|
case 2400:
|
|
baud = NEU_CONN_TTY_BAUD_2400;
|
|
break;
|
|
case 4800:
|
|
baud = NEU_CONN_TTY_BAUD_4800;
|
|
break;
|
|
case 9600:
|
|
baud = NEU_CONN_TTY_BAUD_9600;
|
|
break;
|
|
case 19200:
|
|
baud = NEU_CONN_TTY_BAUD_19200;
|
|
break;
|
|
case 38400:
|
|
baud = NEU_CONN_TTY_BAUD_38400;
|
|
break;
|
|
case 57600:
|
|
baud = NEU_CONN_TTY_BAUD_57600;
|
|
break;
|
|
case 115200:
|
|
baud = NEU_CONN_TTY_BAUD_115200;
|
|
break;
|
|
default:
|
|
printf("baud no match!input:2400 4800 9600 19200 38400 57600 "
|
|
"115200\n");
|
|
return -1;
|
|
}
|
|
break;
|
|
}
|
|
case 'p': {
|
|
if (strcmp(optarg, "none") == 0) {
|
|
parity = NEU_CONN_TTY_PARITY_NONE;
|
|
} else if (strcmp(optarg, "odd") == 0) {
|
|
parity = NEU_CONN_TTY_PARITY_ODD;
|
|
} else if (strcmp(optarg, "even") == 0) {
|
|
parity = NEU_CONN_TTY_PARITY_EVEN;
|
|
} else if (strcmp(optarg, "mark") == 0) {
|
|
parity = NEU_CONN_TTY_PARITY_MARK;
|
|
} else if (strcmp(optarg, "space") == 0) {
|
|
parity = NEU_CONN_TTY_PARITY_SPACE;
|
|
} else {
|
|
printf("parity no match!input:none odd even mark space\n");
|
|
return -1;
|
|
}
|
|
break;
|
|
}
|
|
case 's': {
|
|
int t_stop = atoi(optarg);
|
|
switch (t_stop) {
|
|
case 1:
|
|
stop = NEU_CONN_TTY_STOP_1;
|
|
break;
|
|
case 2:
|
|
stop = NEU_CONN_TTY_STOP_2;
|
|
break;
|
|
default:
|
|
printf("stop no match!input:1 2\n");
|
|
return -1;
|
|
}
|
|
break;
|
|
}
|
|
case 'd': {
|
|
int t_data = atoi(optarg);
|
|
switch (t_data) {
|
|
case 5:
|
|
data = NEU_CONN_TTY_DATA_5;
|
|
break;
|
|
case 6:
|
|
data = NEU_CONN_TTY_DATA_6;
|
|
break;
|
|
case 7:
|
|
data = NEU_CONN_TTY_DATA_7;
|
|
break;
|
|
case 8:
|
|
data = NEU_CONN_TTY_DATA_8;
|
|
break;
|
|
default:
|
|
printf("data no match!input:5 6 7 8");
|
|
return -1;
|
|
}
|
|
break;
|
|
}
|
|
case 'f': {
|
|
flow = NEU_CONN_TTYP_FLOW_ENABLE;
|
|
break;
|
|
}
|
|
case 'e': {
|
|
sim = true;
|
|
break;
|
|
}
|
|
case '?':
|
|
default:
|
|
usage(argv[0]);
|
|
return -1;
|
|
}
|
|
}
|
|
|
|
zlog_init("./config/dev.conf");
|
|
neuron = zlog_get_category("neuron");
|
|
modbus_s_init();
|
|
modbus_s_simulate_error(sim);
|
|
neu_conn_param_t param = {
|
|
.log = neuron,
|
|
.type = NEU_CONN_TTY_CLIENT,
|
|
.params.tty_client.device = device,
|
|
.params.tty_client.baud = baud,
|
|
.params.tty_client.data = data,
|
|
.params.tty_client.parity = parity,
|
|
.params.tty_client.stop = stop,
|
|
.params.tty_client.flow = flow,
|
|
.params.tty_client.timeout = 3000,
|
|
};
|
|
|
|
events = neu_event_new("modbus_tty_simulator");
|
|
conn = neu_conn_new(¶m, NULL, connected, disconnected);
|
|
|
|
neu_conn_start(conn);
|
|
|
|
neu_conn_connect(conn);
|
|
|
|
int fd = neu_conn_fd(conn);
|
|
|
|
if (fd <= 0) {
|
|
return -1;
|
|
}
|
|
|
|
neu_event_io_param_t ioparam = { 0 };
|
|
ioparam.fd = fd;
|
|
ioparam.cb = slave_io_cb;
|
|
ioparam.usr_data = conn;
|
|
|
|
event = neu_event_add_io(events, ioparam);
|
|
|
|
signal(SIGINT, sig_handler);
|
|
signal(SIGTERM, sig_handler);
|
|
signal(SIGABRT, sig_handler);
|
|
|
|
while (1) {
|
|
sleep(10);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static void connected(void *data, int fd)
|
|
{
|
|
(void) data;
|
|
nlog_debug("connected %d", fd);
|
|
return;
|
|
}
|
|
|
|
static void disconnected(void *data, int fd)
|
|
{
|
|
(void) data;
|
|
nlog_debug("disconnected %d", fd);
|
|
return;
|
|
} |